Skip to content

Commit

Permalink
Version 2, ORM and tags
Browse files Browse the repository at this point in the history
  • Loading branch information
geoolekom committed Jun 12, 2019
1 parent a20beb2 commit cf2d8d8
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idea/
__pycache__/
*.pyc
conf/current.conf
11 changes: 11 additions & 0 deletions conf/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[main]
DEBUG: False
THRESHOLD: 3

[db]
ENGINE:
DATABASE:

[telegram]
POLL_INTERVAL: 1
TOKEN: fillme
Empty file added handlers/__init__.py
Empty file.
46 changes: 46 additions & 0 deletions handlers/echo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import logging

import peewee
from telegram.ext import MessageHandler, Filters, BaseFilter

from models import Message
from project import settings
from project.db import db
from utils import get_reply_markup, format_text

logger = logging.getLogger('request.{0}'.format(__file__))


class ExcludeTagFilter(BaseFilter):
def filter(self, message):
caption = message.caption or ''
return all(('#{0}'.format(tag) not in caption for tag in settings.EXCLUDE_TAGS))


def callback(bot, update):
reply_markup = get_reply_markup()
text = format_text(update.message.from_user, update.message.caption)
kwargs = dict(chat_id=update.message.chat_id, reply_markup=reply_markup, caption=text)

if update.message.photo:
bot_msg = bot.send_photo(**kwargs, photo=update.message.photo[-1].file_id)
elif update.message.video:
bot_msg = bot.send_video(**kwargs, video=update.message.video.file_id)
elif update.message.document:
bot_msg = bot.send_document(**kwargs, document=update.message.document.file_id)
else:
return

db.connect()
try:
Message.create(message_id=bot_msg.message_id, chat_id=update.message.chat_id, user_id=update.message.from_user.id)
except peewee.PeeweeException as e:
logger.error(e, exc_info=True)
finally:
db.close()

bot.delete_message(update.message.chat_id, update.message.message_id)


filters = (Filters.photo | Filters.video | Filters.document) & ExcludeTagFilter()
handler = MessageHandler(filters, callback)
7 changes: 7 additions & 0 deletions handlers/error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import logging

logger = logging.getLogger('request.{0}'.format(__file__))


def handler(bot, update, error):
logger.warning('Update "%s" caused error "%s"', update, error)
59 changes: 59 additions & 0 deletions handlers/like.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import logging

import peewee
from telegram.ext import CallbackQueryHandler

from models import Message, Like
from project import settings
from project.db import db
from utils import get_reply_markup

logger = logging.getLogger('request.{0}'.format(__file__))


def callback(bot, update):
query = update.callback_query
like_type = query.data

chat_id = query.message.chat_id
message_id = query.message.message_id
user_id = query.from_user.id

db.connect()
try:
msg = Message.filter(Message.chat_id == chat_id, Message.message_id == message_id).get()
like = msg.likes.filter(Like.user_id == user_id).first()
if like:
if like_type == str(like.type):
like.delete_instance()
else:
like.type = like_type
like.save()
else:
if user_id == msg.user_id:
if like_type == str(Like.DISLIKE):
bot.delete_message(chat_id, message_id)
query.answer()
return
else:
Like.create(message_id=msg.id, user_id=user_id, type=like_type)
except peewee.PeeweeException as e:
logger.error(e, exc_info=True)
else:
like_dict = msg.get_likes_by_type()

if like_dict[Like.LIKE] + settings.THRESHOLD <= like_dict[Like.DISLIKE] + like_dict[Like.OLD]:
bot.delete_message(chat_id, message_id)
else:
reply_markup = get_reply_markup(like_dict)
kwargs = dict(chat_id=chat_id, message_id=message_id, reply_markup=reply_markup)
if query.message.text:
bot.edit_message_text(text=query.message.text, **kwargs)
else:
bot.edit_message_caption(caption=query.message.caption, **kwargs)
finally:
db.close()
query.answer()


handler = CallbackQueryHandler(callback)
38 changes: 38 additions & 0 deletions handlers/text.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import logging

import peewee
from telegram.ext import MessageHandler, Filters, BaseFilter

from models import Message
from project import settings
from project.db import db
from utils import get_reply_markup, format_text

logger = logging.getLogger('request.{0}'.format(__file__))


class IncludeTagFilter(BaseFilter):
def filter(self, message):
caption = message.text or ''
return any(('#{0}'.format(tag) in caption for tag in settings.INCLUDE_TAGS))


def callback(bot, update):
reply_markup = get_reply_markup()
text = format_text(update.message.from_user, update.message.text)
kwargs = dict(chat_id=update.message.chat_id, reply_markup=reply_markup, text=text)
bot_msg = bot.send_message(**kwargs)

db.connect()
try:
Message.create(message_id=bot_msg.message_id, chat_id=update.message.chat_id, user_id=update.message.from_user.id)
except peewee.PeeweeException as e:
logger.error(e, exc_info=True)
finally:
db.close()

bot.delete_message(update.message.chat_id, update.message.message_id)


filters = IncludeTagFilter()
handler = MessageHandler(filters, callback)
4 changes: 4 additions & 0 deletions initdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from project.db import db
from models import User, Message, Like

db.create_tables([User, Message, Like])
55 changes: 55 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from collections import defaultdict

import peewee

from project.db import db


class BaseModel(peewee.Model):
class Meta:
database = db


class User(BaseModel):
user_id = peewee.IntegerField(verbose_name='id в Telegram')


class Message(BaseModel):
chat_id = peewee.IntegerField(verbose_name='id чата')
message_id = peewee.IntegerField(verbose_name='id сообщения')
user_id = peewee.IntegerField(verbose_name='id пользователя')
# user = peewee.ForeignKeyField(User, backref='messages')

def get_likes_by_type(self):
query = self.likes.select(Like.type, peewee.fn.COUNT(Like.id).alias('like_count')).group_by(Like.type)
data = defaultdict(int)
for e in query:
data[e.type] = e.like_count
return data


class Like(BaseModel):
message = peewee.ForeignKeyField(Message, backref='likes')
user_id = peewee.IntegerField(verbose_name='id пользователя')
# user = peewee.ForeignKeyField(User, backref='likes')

LIKE = 1
DISLIKE = 2
OLD = 3
CLASSIC = 4

TYPE_CHOICES = (
(LIKE, 'Лайк'),
(DISLIKE, 'Дислайк'),
(OLD, 'Баян'),
(CLASSIC, 'Классика'),
)

type = peewee.IntegerField(verbose_name='тип', choices=TYPE_CHOICES)

BUTTON_LABELS = (
(LIKE, '\U0001F44D'),
(DISLIKE, '\U0001F44E'),
(CLASSIC, '\U0001F44D [:||||:]'),
(OLD, '\U0001F44E [:||||:]'),
)
Empty file added project/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions project/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import importlib
from project import settings

MODULE, ENGINE = settings.DB_ENGINE.rsplit('.', 1)
engine = getattr(importlib.import_module(MODULE), ENGINE, None)
if engine:
params = {k: v for k, v in settings.DB_PARAMS.items() if v is not None}
db = engine(**params)
else:
raise ImportError()
75 changes: 75 additions & 0 deletions project/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import os
from configparser import ConfigParser

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

current_config_path = os.path.join(BASE_DIR, 'conf', 'current.conf')
default_config_path = os.path.join(BASE_DIR, 'conf', 'default.conf')

if os.path.exists(current_config_path):
config_path = current_config_path
else:
config_path = default_config_path

config = ConfigParser()
config.read(config_path)

# Main
DEBUG = config.getboolean('main', 'DEBUG')
THRESHOLD = config.getint('main', 'THRESHOLD')
INCLUDE_TAGS = config.get('main', 'INCLUDE_TAGS').split(', ')
EXCLUDE_TAGS = config.get('main', 'EXCLUDE_TAGS').split(', ')

# Telegram
POLL_INTERVAL = config.getfloat('telegram', 'POLL_INTERVAL')
TELEGRAM_TOKEN = config.get('telegram', 'TOKEN')

# Database
DB_ENGINE = config.get('db', 'ENGINE')
DB_PARAMS = {
'database': config.get('db', 'NAME'),
'user': config.get('db', 'USER', fallback=None),
'password': config.get('db', 'PASSWORD', fallback=None),
'host': config.get('db', 'HOST', fallback=None),
'port': config.getint('db', 'PORT', fallback=None),
}

# Logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[%(levelname)s] %(asctime)s %(module)s: %(message)s'
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
'syslog': {
'class': 'logging.handlers.SysLogHandler',
'formatter': 'verbose',
'facility': 'user',
},
},
'loggers': {
'request': {
'handlers': ['console', 'syslog', ],
'level': 'ERROR',
'propagate': True,
},
'peewee': {
'handlers': ['console', 'syslog', ],
'level': 'DEBUG',
'propagate': True,
},
'main': {
'handlers': ['console', 'syslog', ],
'level': 'INFO',
'propagate': True,
},
},
}
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
python-telegram-bot==11.1.0
peewee==3.9.6
28 changes: 28 additions & 0 deletions server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import logging.config

from telegram.ext import Updater

from handlers import echo, error, like, text
from project import settings

logger = logging.getLogger('main')


def main():
logging.config.dictConfig(settings.LOGGING)
updater = Updater(settings.TELEGRAM_TOKEN)

dp = updater.dispatcher
dp.add_handler(echo.handler)
dp.add_handler(text.handler)
dp.add_handler(like.handler)
dp.add_error_handler(error.handler)

updater.start_polling(poll_interval=settings.POLL_INTERVAL)
logger.info('Бот запущен.')
updater.idle()
logger.info('Бот остановлен.')


if __name__ == '__main__':
main()
28 changes: 28 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from telegram import InlineKeyboardMarkup, InlineKeyboardButton

from models import Like, Message


def format_text(user, text):
return '{0}\nSender: {1} {2}'.format(text or '', user.first_name or '', user.last_name or '')


def get_button(data, text, like_count):
if like_count:
button_text = '{0} {1}'.format(text, like_count)
else:
button_text = text
return InlineKeyboardButton(button_text, callback_data=data)


def get_reply_markup(like_dict=None):
if like_dict and isinstance(like_dict, dict):
return InlineKeyboardMarkup([
[get_button(data, text, like_dict.get(data)) for data, text in Like.BUTTON_LABELS[:2]],
[get_button(data, text, like_dict.get(data)) for data, text in Like.BUTTON_LABELS[2:]]
])
else:
return InlineKeyboardMarkup([
[get_button(data, text, None) for data, text in Like.BUTTON_LABELS[:2]],
[get_button(data, text, None) for data, text in Like.BUTTON_LABELS[2:]]
])

0 comments on commit cf2d8d8

Please sign in to comment.