From f95efdb2987eee8dfd34df48e8e9b064f2133ba7 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 9 Jan 2021 17:57:23 +0600 Subject: [PATCH 1/5] karma --- .env.dist | 4 +- .gitignore | 2 +- app.py | 3 +- data/cache_karma.py | 10 ++++ data/main.db | Bin 8192 -> 12288 bytes docker-compose.yml | 2 +- filters/__init__.py | 3 +- filters/access_karma.py | 42 ++++++++++++++++ filters/admin_filter.py | 11 +++++ filters/chat_filters.py | 1 + filters/is_reply.py | 2 - handlers/essential/__init__.py | 1 + handlers/essential/karma.py | 72 +++++++++++++++++++++++++++ handlers/groups/basic.py | 1 - handlers/groups/service_messages.py | 1 + handlers/private/basic.py | 1 + middlewares/__init__.py | 3 +- middlewares/throttling.py | 14 ++++-- utils/db_api/sqlite.py | 73 +++++++++++++++++++++++++--- utils/misc/karma.py | 29 +++++++++++ utils/misc/throttling.py | 2 + utils/notify_admins.py | 2 + utils/set_bot_commands.py | 1 + 23 files changed, 259 insertions(+), 21 deletions(-) create mode 100644 data/cache_karma.py create mode 100644 filters/access_karma.py create mode 100644 filters/admin_filter.py create mode 100644 handlers/essential/karma.py create mode 100644 utils/misc/karma.py diff --git a/.env.dist b/.env.dist index 932fb58..eb85ec0 100644 --- a/.env.dist +++ b/.env.dist @@ -1,8 +1,8 @@ # Telegram API Token -BOT_TOKEN= +BOT_TOKEN=token # Не надо использовать пробел после "," -ADMINS_ID=123456789,987654321 +ADMINS_ID=ID # Указываем пропускать ли боту апдейты при запуске SKIP_UPDATES=False diff --git a/.gitignore b/.gitignore index 7ed07d0..786c6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -102,7 +102,7 @@ celerybeat.pid *.sage.py # Environments -.env +.env.dist .venv env/ venv/ diff --git a/app.py b/app.py index 6034929..4a26187 100644 --- a/app.py +++ b/app.py @@ -17,8 +17,9 @@ async def on_startup(dp): await set_default_commands(dp) await on_startup_notify(dp) + try: - db.create_table_stickers() + db.create_table_karma_users() except Exception as err: print(err) logger.info("Бот запущен") diff --git a/data/cache_karma.py b/data/cache_karma.py new file mode 100644 index 0000000..f679d72 --- /dev/null +++ b/data/cache_karma.py @@ -0,0 +1,10 @@ + + +# тут мы будем хранить данные для того, чтобы не наргуржать базу данных не нужной информацией. +""" +format +{message_id: user_id} + +""" +reply_message_id_user = {} + diff --git a/data/main.db b/data/main.db index 38dc6fd8ae79763a429de35bacb91c05bf96f886..b5d124a40e9f0795c99ea31719d282e5030ce763 100644 GIT binary patch delta 328 zcmZp0Xh@hKEm*<8z`zW|Fu*cV#~3K6XMd9yD8$5ff`Pw*@5IK!2)_D8QzmwCWo5=D z!;-|LoYc@@*P!5dZ^s~CM{ANLc_57~w3WhM_$N}21zT!jl06fP`MxG)a@md#Z# delta 53 zcmZojXmFSyEy&2gz`z8=Fu*ub$C#gyLC^jsFHne)zkz|jVY8rs5dY=|{ssX6&i)9R diff --git a/docker-compose.yml b/docker-compose.yml index 9937f91..face709 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,4 +9,4 @@ services: restart: always env_file: - - ".env" + - ".env.dist" diff --git a/filters/__init__.py b/filters/__init__.py index 0bd45cf..98382c0 100644 --- a/filters/__init__.py +++ b/filters/__init__.py @@ -1,7 +1,7 @@ from aiogram import Dispatcher from loguru import logger - +from .admin_filter import IsPrivateAdmin from .user_filters import IsContributor from .chat_filters import IsGroup from .chat_filters import IsPrivate @@ -23,3 +23,4 @@ def setup(dp: Dispatcher): dp.filters_factory.bind(IsContributor) dp.filters_factory.bind(IsGroup) dp.filters_factory.bind(IsPrivate) + dp.filters_factory.bind(IsPrivateAdmin) diff --git a/filters/access_karma.py b/filters/access_karma.py new file mode 100644 index 0000000..9cfa2cc --- /dev/null +++ b/filters/access_karma.py @@ -0,0 +1,42 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter +from loguru import logger + +from data.cache_karma import reply_message_id_user +from loader import db, bot + + +class Restriction_Karma(BoundFilter): + + async def check(self, message: types.Message) -> bool: + bot_id = (await bot.get_me()).id + my_user_id = message.from_user.id + user_id_not_karma = [bot_id, my_user_id] + + # чтобы нельзя было давать карму боту и самому себе + if message.reply_to_message.from_user.id in user_id_not_karma: + await message.delete() + return False + + if await self._get_cached_message_value(message) is None: + await self._set_cached_message_value(message) + db.add_user(user_id=message.reply_to_message.from_user.id, + full_name=message.reply_to_message.from_user.full_name) + await message.delete() + return True + + async def _set_cached_message_value(self, message: types.Message): + if not await self._get_cached_message_value(message) is None: + return + reply_message_id_user[message.reply_to_message.message_id] = message.from_user.id + + async def _get_cached_message_value(self, message: types.Message): + try: + return reply_message_id_user[message.reply_to_message.message_id] + except Exception as error: + logger.info(error) + + + + + diff --git a/filters/admin_filter.py b/filters/admin_filter.py new file mode 100644 index 0000000..a9697ac --- /dev/null +++ b/filters/admin_filter.py @@ -0,0 +1,11 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter + + +class IsPrivateAdmin(BoundFilter): + def __init__(self, users_id: list): + self.users_id = list(map(int, users_id)) + + async def check(self, message:types.Message): + + return message.from_user.id in self.users_id diff --git a/filters/chat_filters.py b/filters/chat_filters.py index 6f6facf..ef60c31 100644 --- a/filters/chat_filters.py +++ b/filters/chat_filters.py @@ -1,5 +1,6 @@ from aiogram import types from aiogram.dispatcher.filters import BoundFilter +from loguru import logger class IsGroup(BoundFilter): diff --git a/filters/is_reply.py b/filters/is_reply.py index a4cb022..97d6473 100644 --- a/filters/is_reply.py +++ b/filters/is_reply.py @@ -9,9 +9,7 @@ class IsReplyFilter(BoundFilter): """ Фильтр, проверяющий, явлляется ли сообщение ответом на сообщение """ - key = "is_reply" - is_reply: bool async def check(self, message: types.Message) -> bool: diff --git a/handlers/essential/__init__.py b/handlers/essential/__init__.py index c928e9f..842e4fe 100644 --- a/handlers/essential/__init__.py +++ b/handlers/essential/__init__.py @@ -1,5 +1,6 @@ from .errors import dp from .other import dp from .metabolism import dp +from .karma import dp __all__ = ["dp"] diff --git a/handlers/essential/karma.py b/handlers/essential/karma.py new file mode 100644 index 0000000..996f0fd --- /dev/null +++ b/handlers/essential/karma.py @@ -0,0 +1,72 @@ +import re + +from aiogram import types +from aiogram.dispatcher.filters import Command, AdminFilter +from aiogram.utils.markdown import hlink, hbold + +from data.cache_karma import reply_message_id_user +from data.config import ADMINS_ID +from filters import IsGroup, IsReplyFilter, IsPrivate, IsPrivateAdmin +from filters.access_karma import Restriction_Karma +from loader import dp, bot, db +from utils.misc import rate_limit +from utils.misc.karma import karma, url + + +@dp.message_handler(IsPrivate(), IsPrivateAdmin(ADMINS_ID), Command("clear")) +async def clear_cache_message_id_karma(message: types.Message): + size = None + + if type(reply_message_id_user) is dict: + size = 144 + if len(reply_message_id_user) > 8: + size += 12 * (len(reply_message_id_user) - 8) + await message.answer(f"Памяти в кэше {size}\n" + "Было очищено") + reply_message_id_user.clear() + +@rate_limit(limit=0) +@dp.message_handler(IsGroup(), Command("top_karma", prefixes="!/")) +async def result_top_users(message: types.Message): + name_bot = await bot.get_me() + command_parse = re.compile(r"(!top_karma|/top_karma) ?(\d+)?") + a = command_parse.match(message.text) + limit = a.group(2) + + if limit is None: + limit = 10 + + if int(limit) > 20: + limit = 20 + + list_top_users = db.select_karma_top(limit=limit) + text_messages = [f"Топ участников чата по карме: {hbold(name_bot.full_name)}"] + + for count, user_object in enumerate(list_top_users, 1): + user_id, karma_user, full_name = user_object + text = f"{count}. {hlink(full_name, url(user_id))} - {karma_user} 💋" + text_messages.append(text) + + await message.answer("\n".join(text_messages)) + +@rate_limit(limit=60) +@dp.message_handler(IsGroup(), IsReplyFilter(is_reply=True), Restriction_Karma(), text=["+", "-"]) +async def give_karma_user(message: types.Message): + + answer = message.text + text_with_karma = {"+": (1, "пополнил"), + "-": (-1, "понизил")} + karma(message, karma=text_with_karma[f"{answer}"][0]) + + user = hlink(message.from_user.first_name, message.from_user.url) + text = text_with_karma.get(answer)[1] + to_user = hlink(message.reply_to_message.from_user.first_name, message.reply_to_message.from_user.url) + get_karma = str(text_with_karma.get(answer)[0]) + total_karma = db.select_karma_user(user_id=message.reply_to_message.from_user.id)[0][1] # получаем общую карму пользователя + + await message.answer(R"""{user} {text} {to_user} карму на {get_karma} +Текущая карма: {total_karma}""".format(user=user, + text=text, + to_user=to_user, + get_karma=get_karma, + total_karma=total_karma)) diff --git a/handlers/groups/basic.py b/handlers/groups/basic.py index bd8f331..ad6f3b4 100644 --- a/handlers/groups/basic.py +++ b/handlers/groups/basic.py @@ -47,7 +47,6 @@ async def help(message: types.Message): "/gay [цель*] - Тест на гея" "\n" "/biba - Проверить бибу" "\n" "/roll - Случайное число" "\n" - "/metabolism - Узнать свою суточную норму калорий" "\n" "\n" "{warning}".format( header1=hbold("Основные комманды"), diff --git a/handlers/groups/service_messages.py b/handlers/groups/service_messages.py index 115a45b..5eb4121 100644 --- a/handlers/groups/service_messages.py +++ b/handlers/groups/service_messages.py @@ -25,6 +25,7 @@ async def left_chat_member(message: types.Message): return False # Проверяем вышел ли пользователь сам + if message.left_chat_member.id == message.from_user.id: await message.answer(f"{message.left_chat_member.get_mention(as_html=True)} вышел из чата.") until_date = datetime.datetime.now() + datetime.timedelta(days=1) diff --git a/handlers/private/basic.py b/handlers/private/basic.py index 0a4eef9..867e8a4 100644 --- a/handlers/private/basic.py +++ b/handlers/private/basic.py @@ -10,6 +10,7 @@ from filters import IsPrivate from keyboards.inline import start_markup from loader import dp +from utils.misc import rate_limit @dp.message_handler(IsPrivate(), Command("start", prefixes="/")) diff --git a/middlewares/__init__.py b/middlewares/__init__.py index b64e7a8..d299a37 100644 --- a/middlewares/__init__.py +++ b/middlewares/__init__.py @@ -1,9 +1,10 @@ from aiogram import Dispatcher from loguru import logger -from .throttling import ThrottlingMiddleware +from .throttling import ThrottlingMiddleware def setup(dp: Dispatcher): logger.info("Подключение middlewares...") dp.middleware.setup(ThrottlingMiddleware()) + diff --git a/middlewares/throttling.py b/middlewares/throttling.py index 855a042..00411bd 100644 --- a/middlewares/throttling.py +++ b/middlewares/throttling.py @@ -5,6 +5,7 @@ from aiogram.dispatcher.handler import CancelHandler, current_handler from aiogram.dispatcher.middlewares import BaseMiddleware from aiogram.utils.exceptions import Throttled +from loguru import logger class ThrottlingMiddleware(BaseMiddleware): @@ -12,15 +13,19 @@ class ThrottlingMiddleware(BaseMiddleware): Simple middleware """ - def __init__(self, limit=DEFAULT_RATE_LIMIT, key_prefix='antiflood_'): + def __init__(self, limit=DEFAULT_RATE_LIMIT, + limit_karma=1, + key_prefix='antiflood_'): self.rate_limit = limit self.prefix = key_prefix + super(ThrottlingMiddleware, self).__init__() # noinspection PyUnusedLocal async def on_process_message(self, message: types.Message, data: dict): handler = current_handler.get() dispatcher = Dispatcher.get_current() + if handler: limit = getattr(handler, 'throttling_rate_limit', self.rate_limit) key = getattr(handler, 'throttling_key', f"{self.prefix}_{handler.__name__}") @@ -28,8 +33,11 @@ async def on_process_message(self, message: types.Message, data: dict): limit = self.rate_limit key = f"{self.prefix}_message" try: + logger.info(limit) + await dispatcher.throttle(key, rate=limit) except Throttled as t: + await self.message_throttled(message, t) raise CancelHandler() @@ -42,9 +50,9 @@ async def message_throttled(self, message: types.Message, throttled: Throttled): key = f"{self.prefix}_message" delta = throttled.rate - throttled.delta if throttled.exceeded_count <= 2: - service_message = await message.reply('Too many requests! ') + service_message = await message.answer('Не надо так часто.') - await asyncio.sleep(5) + await asyncio.sleep(2) await service_message.delete() await message.delete() try: diff --git a/utils/db_api/sqlite.py b/utils/db_api/sqlite.py index fd71469..9686071 100644 --- a/utils/db_api/sqlite.py +++ b/utils/db_api/sqlite.py @@ -1,5 +1,7 @@ import sqlite3 +from loguru import logger + class Database: def __init__(self, path_to_db="main.db"): @@ -13,7 +15,7 @@ def execute(self, sql: str, parameters: tuple = None, fetchone=False, fetchall=F if not parameters: parameters = () connection = self.connection - connection.set_trace_callback(logger) + # connection.set_trace_callback(logger) cursor = connection.cursor() data = None cursor.execute(sql, parameters) @@ -55,11 +57,66 @@ def select_all_sets(self): """ return self.execute(sql, fetchall=True) + def create_table_karma_users(self): + + """ + Создаем таблицу с название USERS_KARMA + колонки: + user_id : integer + karma: integer + + """ + sql = """CREATE TABLE USERS_KARMA ( + + user_id INTEGER PRIMARY KEY, + karma INTEGER, + full_name varchar 255 + ) + """ + self.execute(sql, commit=True) + + def update_karma(self, user_id: int, karma: int = 0): + + # если статус update_karma = True, мы обновляем карму + now_karma = self.select_karma_user(user_id=user_id)[0][1] + + now_karma += karma + sql = "UPDATE USERS_KARMA SET karma = ? WHERE user_id = ?" + return self.execute(sql, parameters=(now_karma, user_id), commit=True) + + def add_user(self, user_id: int, full_name: str, karma: int = 0): + try: + sql = "INSERT INTO USERS_KARMA (user_id, full_name, karma) VALUES (?,?,?)" + self.execute(sql, parameters=(user_id, full_name, karma), commit=True) + except Exception as e: + logger.info(e) + + def select_karma_user(self, user_id: int): + """ + Выводим пользователя из базы данных по юзеру + """ + sql = "SELECT * FROM USERS_KARMA WHERE user_id = ?" + return self.execute(sql, parameters=(user_id,), fetchall=True) + + def select_karma_top(self, limit: int = 10): + """ + Функция в котором мы определяем количество топ пользователей + группы по набранным баллам + + parameters: + limit - int , default = 10 users + """ + + sql = "SELECT * FROM USERS_KARMA ORDER BY karma DESC" + setting_limit = " LIMIT " + str(limit) + sql += setting_limit + + return self.execute(sql, fetchall=True) -def logger(statement): - print(f""" -_____________________________________________________ -Executing: -{statement} -_____________________________________________________ -""") +# def logger(statement): +# print(f""" +# _____________________________________________________ +# Executing: +# {statement} +# _____________________________________________________ +# """) diff --git a/utils/misc/karma.py b/utils/misc/karma.py new file mode 100644 index 0000000..0bfd928 --- /dev/null +++ b/utils/misc/karma.py @@ -0,0 +1,29 @@ +from aiogram import types +from loguru import logger + +from loader import db + +def url(user_id: int) -> str: + return f"tg://user?id={user_id}" + +def karma(message: types.Message, karma: int = 1): + + user_id = db.select_karma_user(user_id=message.reply_to_message.from_user.id) + + # если нет юзера в базе + if len(user_id) == 0: + db.add_user(user_id=message.reply_to_message.from_user.id, + full_name=message.reply_to_message.from_user.full_name) # добавляем пользователя в базу и даем +1 к карме + + db.update_karma(user_id=message.reply_to_message.from_user.id, + karma=karma) + logger.info(f'Мы обновили карму юзеру {message.reply_to_message.from_user.id}') + return + + + + + + + + diff --git a/utils/misc/throttling.py b/utils/misc/throttling.py index c881c9e..43981ce 100644 --- a/utils/misc/throttling.py +++ b/utils/misc/throttling.py @@ -14,3 +14,5 @@ def decorator(func): return func return decorator + + diff --git a/utils/notify_admins.py b/utils/notify_admins.py index 7199f3c..2b51807 100644 --- a/utils/notify_admins.py +++ b/utils/notify_admins.py @@ -1,3 +1,5 @@ +import logging + from loguru import logger from aiogram import Dispatcher diff --git a/utils/set_bot_commands.py b/utils/set_bot_commands.py index f58cbc0..9be98f7 100644 --- a/utils/set_bot_commands.py +++ b/utils/set_bot_commands.py @@ -9,6 +9,7 @@ async def set_default_commands(dp): types.BotCommand("set_title", "(admins only) Установить название группы"), types.BotCommand("set_description", "(admins only) Установить описание группы"), types.BotCommand("gay", "Узнать, на сколько % пользователь гей"), + types.BotCommand("top", "Узнать топ хелперов"), types.BotCommand("metabolism", "Узнать свою суточную норму калорий"), # types.BotCommand("roll", "Получить случайное число"), types.BotCommand("biba", "Узнать сколько см у пользователя биба"), From d4202c38fecb1bee296760fb7897d291f5e9643e Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 9 Jan 2021 18:17:06 +0600 Subject: [PATCH 2/5] karma --- app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app.py b/app.py index 4a26187..5aa41e1 100644 --- a/app.py +++ b/app.py @@ -19,6 +19,7 @@ async def on_startup(dp): await on_startup_notify(dp) try: + db.create_table_stickers() db.create_table_karma_users() except Exception as err: print(err) From 6259a8c4791394f8934bcbab6602ebf4f735d237 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 9 Jan 2021 18:20:33 +0600 Subject: [PATCH 3/5] karma --- utils/set_bot_commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/set_bot_commands.py b/utils/set_bot_commands.py index 9be98f7..acddc90 100644 --- a/utils/set_bot_commands.py +++ b/utils/set_bot_commands.py @@ -9,13 +9,14 @@ async def set_default_commands(dp): types.BotCommand("set_title", "(admins only) Установить название группы"), types.BotCommand("set_description", "(admins only) Установить описание группы"), types.BotCommand("gay", "Узнать, на сколько % пользователь гей"), - types.BotCommand("top", "Узнать топ хелперов"), + types.BotCommand("top_karma", "Узнать топ хелперов"), types.BotCommand("metabolism", "Узнать свою суточную норму калорий"), # types.BotCommand("roll", "Получить случайное число"), types.BotCommand("biba", "Узнать сколько см у пользователя биба"), # types.BotCommand("ro", "(admins only) Замутить пользователя"), types.BotCommand("unro", "(admins only) Размутить пользователя"), # types.BotCommand("ban", "(admins only) Забанить пользователя"), + types.BotCommand("clear", "(admin only) private chat Очистка кэша"), types.BotCommand("unban", "(admins only) Разбанить пользователя"), types.BotCommand("media_false", "(admins only) Запрещает использование media"), types.BotCommand("media_true", "(admins only) Разрешает использование media"), From 1905a350d0b83f156464221f76f357ee0a9808ab Mon Sep 17 00:00:00 2001 From: Maiss-python Date: Tue, 10 Aug 2021 19:44:10 +0600 Subject: [PATCH 4/5] rename .env --- .env.dist => .env | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .env.dist => .env (100%) diff --git a/.env.dist b/.env similarity index 100% rename from .env.dist rename to .env From 277194611851eafd2bdbed80a495991af8bc1c48 Mon Sep 17 00:00:00 2001 From: Mikhail <67838942+Maiss-python@users.noreply.github.com> Date: Tue, 10 Aug 2021 19:46:26 +0600 Subject: [PATCH 5/5] update .env karma --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index face709..9937f91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,4 +9,4 @@ services: restart: always env_file: - - ".env.dist" + - ".env"