forked from shuternay/likes_bot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
367 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
idea/ | ||
__pycache__/ | ||
*.pyc | ||
conf/current.conf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
python-telegram-bot==11.1.0 | ||
peewee==3.9.6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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:]] | ||
]) |