From 494a2391a2cb23cd1a1f301fd380e07492676cc3 Mon Sep 17 00:00:00 2001 From: "m1st4k3@vk.com" Date: Sat, 2 Jul 2022 12:33:42 +0300 Subject: [PATCH 01/16] Add template --- .env.dist | 13 +++++++ .gitignore | 63 ++++++++++++++++++++++++++++++++++ Dockerfile | 8 +++++ bot.py | 64 +++++++++++++++++++++++++++++++++++ docker-compose.yml | 23 +++++++++++++ requirements.txt | 3 ++ systemd/tgbot.service | 14 ++++++++ tgbot/__init__.py | 0 tgbot/config.py | 50 +++++++++++++++++++++++++++ tgbot/filters/__init__.py | 0 tgbot/filters/admin.py | 19 +++++++++++ tgbot/handlers/__init__.py | 0 tgbot/handlers/admin.py | 10 ++++++ tgbot/handlers/echo.py | 28 +++++++++++++++ tgbot/handlers/user.py | 10 ++++++ tgbot/keyboards/__init__.py | 0 tgbot/keyboards/inline.py | 0 tgbot/keyboards/reply.py | 0 tgbot/middlewares/__init__.py | 0 tgbot/middlewares/db.py | 10 ++++++ tgbot/misc/__init__.py | 0 tgbot/misc/states.py | 0 tgbot/models/__init__.py | 0 tgbot/services/__init__.py | 0 24 files changed, 315 insertions(+) create mode 100644 .env.dist create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 bot.py create mode 100644 docker-compose.yml create mode 100644 requirements.txt create mode 100644 systemd/tgbot.service create mode 100644 tgbot/__init__.py create mode 100644 tgbot/config.py create mode 100644 tgbot/filters/__init__.py create mode 100644 tgbot/filters/admin.py create mode 100644 tgbot/handlers/__init__.py create mode 100644 tgbot/handlers/admin.py create mode 100644 tgbot/handlers/echo.py create mode 100644 tgbot/handlers/user.py create mode 100644 tgbot/keyboards/__init__.py create mode 100644 tgbot/keyboards/inline.py create mode 100644 tgbot/keyboards/reply.py create mode 100644 tgbot/middlewares/__init__.py create mode 100644 tgbot/middlewares/db.py create mode 100644 tgbot/misc/__init__.py create mode 100644 tgbot/misc/states.py create mode 100644 tgbot/models/__init__.py create mode 100644 tgbot/services/__init__.py diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..211d5db --- /dev/null +++ b/.env.dist @@ -0,0 +1,13 @@ +BOT_CONTAINER_NAME=bot_container_name +BOT_IMAGE_NAME=botimage_name +BOT_NAME=mybotname +BOT_TOKEN=123456:Your-TokEn_ExaMple +ADMINS=123456,654321 +USE_REDIS=False + +DB_USER=exampleDBUserName +PG_PASSWORD=examplePostgresPass +DB_PASS=exampleDBPassword +DB_NAME=exampleDBName +DB_HOST=127.0.0.1 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c33c9a --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Translations +*.mo +*.pot + + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Environments +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Pyre type checker +.pyre/ +.idea/* +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a92a6aa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.9-buster +ENV BOT_NAME=$BOT_NAME + +WORKDIR /usr/src/app/"${BOT_NAME:-tg_bot}" + +COPY requirements.txt /usr/src/app/"${BOT_NAME:-tg_bot}" +RUN pip install -r /usr/src/app/"${BOT_NAME:-tg_bot}"/requirements.txt +COPY . /usr/src/app/"${BOT_NAME:-tg_bot}" diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..c6ef904 --- /dev/null +++ b/bot.py @@ -0,0 +1,64 @@ +import asyncio +import logging + +from aiogram import Bot, Dispatcher +from aiogram.contrib.fsm_storage.memory import MemoryStorage +from aiogram.contrib.fsm_storage.redis import RedisStorage2 + +from tgbot.config import load_config +from tgbot.filters.admin import AdminFilter +from tgbot.handlers.admin import register_admin +from tgbot.handlers.echo import register_echo +from tgbot.handlers.user import register_user +from tgbot.middlewares.db import DbMiddleware + +logger = logging.getLogger(__name__) + + +def register_all_middlewares(dp): + dp.setup_middleware(DbMiddleware()) + + +def register_all_filters(dp): + dp.filters_factory.bind(AdminFilter) + + +def register_all_handlers(dp): + register_admin(dp) + register_user(dp) + + register_echo(dp) + + +async def main(): + logging.basicConfig( + level=logging.INFO, + format=u'%(filename)s:%(lineno)d #%(levelname)-8s [%(asctime)s] - %(name)s - %(message)s', + ) + logger.info("Starting bot") + config = load_config(".env") + + storage = RedisStorage2() if config.tg_bot.use_redis else MemoryStorage() + bot = Bot(token=config.tg_bot.token, parse_mode='HTML') + dp = Dispatcher(bot, storage=storage) + + bot['config'] = config + + register_all_middlewares(dp) + register_all_filters(dp) + register_all_handlers(dp) + + # start + try: + await dp.start_polling() + finally: + await dp.storage.close() + await dp.storage.wait_closed() + await bot.session.close() + + +if __name__ == '__main__': + try: + asyncio.run(main()) + except (KeyboardInterrupt, SystemExit): + logger.error("Bot stopped!") diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..040a4b9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3.3' + +services: + bot: + image: "${BOT_IMAGE_NAME:-tg_bot-image}" + container_name: "${BOT_CONTAINER_NAME:-tg_bot-container}" + stop_signal: SIGINT + build: + context: . + working_dir: "/usr/src/app/${BOT_NAME:-tg_bot}" + volumes: + - .:/usr/src/app/${BOT_NAME:-tg_bot} + command: python3 -m bot + restart: always + env_file: + - ".env" + networks: + - tg_bot + + +networks: + tg_bot: + driver: bridge diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e40b428 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +aiogram~=2.18 +aioredis~=2.0 +environs~=9.0 diff --git a/systemd/tgbot.service b/systemd/tgbot.service new file mode 100644 index 0000000..ccf3b2c --- /dev/null +++ b/systemd/tgbot.service @@ -0,0 +1,14 @@ +[Unit] +Description=Course Bot +After=network.target + +[Service] +User=tgbot +Group=tgbot +Type=simple +WorkingDirectory=/opt/tgbot +ExecStart=/opt/tgbot/venv/bin/python bot.py +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/tgbot/__init__.py b/tgbot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/config.py b/tgbot/config.py new file mode 100644 index 0000000..26e8e94 --- /dev/null +++ b/tgbot/config.py @@ -0,0 +1,50 @@ +from dataclasses import dataclass + +from environs import Env + + +@dataclass +class DbConfig: + host: str + password: str + user: str + database: str + + +@dataclass +class TgBot: + token: str + admin_ids: list[int] + use_redis: bool + + +@dataclass +class Miscellaneous: + other_params: str = None + + +@dataclass +class Config: + tg_bot: TgBot + db: DbConfig + misc: Miscellaneous + + +def load_config(path: str = None): + env = Env() + env.read_env(path) + + return Config( + tg_bot=TgBot( + token=env.str("BOT_TOKEN"), + admin_ids=list(map(int, env.list("ADMINS"))), + use_redis=env.bool("USE_REDIS"), + ), + db=DbConfig( + host=env.str('DB_HOST'), + password=env.str('DB_PASS'), + user=env.str('DB_USER'), + database=env.str('DB_NAME') + ), + misc=Miscellaneous() + ) diff --git a/tgbot/filters/__init__.py b/tgbot/filters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/filters/admin.py b/tgbot/filters/admin.py new file mode 100644 index 0000000..02422a5 --- /dev/null +++ b/tgbot/filters/admin.py @@ -0,0 +1,19 @@ +import typing + +from aiogram.dispatcher.filters import BoundFilter + +from tgbot.config import Config + + +class AdminFilter(BoundFilter): + key = 'is_admin' + + def __init__(self, is_admin: typing.Optional[bool] = None): + self.is_admin = is_admin + + async def check(self, obj): + if self.is_admin is None: + return False + config: Config = obj.bot.get('config') + return (obj.from_user.id in config.tg_bot.admin_ids) == self.is_admin + diff --git a/tgbot/handlers/__init__.py b/tgbot/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/handlers/admin.py b/tgbot/handlers/admin.py new file mode 100644 index 0000000..a40a47f --- /dev/null +++ b/tgbot/handlers/admin.py @@ -0,0 +1,10 @@ +from aiogram import Dispatcher +from aiogram.types import Message + + +async def admin_start(message: Message): + await message.reply("Hello, admin!") + + +def register_admin(dp: Dispatcher): + dp.register_message_handler(admin_start, commands=["start"], state="*", is_admin=True) diff --git a/tgbot/handlers/echo.py b/tgbot/handlers/echo.py new file mode 100644 index 0000000..e280f64 --- /dev/null +++ b/tgbot/handlers/echo.py @@ -0,0 +1,28 @@ +from aiogram import types, Dispatcher +from aiogram.dispatcher import FSMContext +from aiogram.utils.markdown import hcode + + +async def bot_echo(message: types.Message): + text = [ + "Эхо без состояния.", + "Сообщение:", + message.text + ] + + await message.answer('\n'.join(text)) + + +async def bot_echo_all(message: types.Message, state: FSMContext): + state_name = await state.get_state() + text = [ + f'Эхо в состоянии {hcode(state_name)}', + 'Содержание сообщения:', + hcode(message.text) + ] + await message.answer('\n'.join(text)) + + +def register_echo(dp: Dispatcher): + dp.register_message_handler(bot_echo) + dp.register_message_handler(bot_echo_all, state="*", content_types=types.ContentTypes.ANY) diff --git a/tgbot/handlers/user.py b/tgbot/handlers/user.py new file mode 100644 index 0000000..f5b820a --- /dev/null +++ b/tgbot/handlers/user.py @@ -0,0 +1,10 @@ +from aiogram import Dispatcher +from aiogram.types import Message + + +async def user_start(message: Message): + await message.reply("Hello, user!") + + +def register_user(dp: Dispatcher): + dp.register_message_handler(user_start, commands=["start"], state="*") diff --git a/tgbot/keyboards/__init__.py b/tgbot/keyboards/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/keyboards/inline.py b/tgbot/keyboards/inline.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/keyboards/reply.py b/tgbot/keyboards/reply.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/middlewares/__init__.py b/tgbot/middlewares/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/middlewares/db.py b/tgbot/middlewares/db.py new file mode 100644 index 0000000..c4e5569 --- /dev/null +++ b/tgbot/middlewares/db.py @@ -0,0 +1,10 @@ +from aiogram.dispatcher.middlewares import LifetimeControllerMiddleware + + +class DbMiddleware(LifetimeControllerMiddleware): + skip_patterns = ["error", "update"] + + async def pre_process(self, obj, data, *args): + db_session = obj.bot.get('db') + # Передаем данные из таблицы в хендлер + # data['some_model'] = await Model.get() diff --git a/tgbot/misc/__init__.py b/tgbot/misc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/misc/states.py b/tgbot/misc/states.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/models/__init__.py b/tgbot/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/services/__init__.py b/tgbot/services/__init__.py new file mode 100644 index 0000000..e69de29 From 80ecbe7497ee60cc64803839f2c876c4e89b4e9c Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Tue, 12 Jul 2022 19:03:32 +0300 Subject: [PATCH 02/16] First commit --- .env.dist | 7 +- bot.py | 38 +++++-- requirements.txt | 4 +- tgbot/Utils/DBWorker.py | 135 ++++++++++++++++++++++++ tgbot/Utils/__init__.py | 0 tgbot/Utils/get_user_link.py | 16 +++ tgbot/config.py | 11 +- tgbot/filters/count.py | 27 +++++ tgbot/filters/granted.py | 20 ++++ tgbot/filters/group_join.py | 12 +++ tgbot/filters/moder_group.py | 20 ++++ tgbot/filters/user_group.py | 20 ++++ tgbot/handlers/catch_update.py | 37 +++++++ tgbot/handlers/check.py | 26 +++++ tgbot/handlers/echo.py | 3 +- tgbot/handlers/get_granted.py | 25 +++++ tgbot/handlers/grant_callback.py | 70 ++++++++++++ tgbot/handlers/grant_cancel_callback.py | 19 ++++ tgbot/handlers/restore.py | 35 ++++++ tgbot/keyboards/inline.py | 7 ++ tgbot/middlewares/db.py | 10 -- 21 files changed, 512 insertions(+), 30 deletions(-) create mode 100644 tgbot/Utils/DBWorker.py create mode 100644 tgbot/Utils/__init__.py create mode 100644 tgbot/Utils/get_user_link.py create mode 100644 tgbot/filters/count.py create mode 100644 tgbot/filters/granted.py create mode 100644 tgbot/filters/group_join.py create mode 100644 tgbot/filters/moder_group.py create mode 100644 tgbot/filters/user_group.py create mode 100644 tgbot/handlers/catch_update.py create mode 100644 tgbot/handlers/check.py create mode 100644 tgbot/handlers/get_granted.py create mode 100644 tgbot/handlers/grant_callback.py create mode 100644 tgbot/handlers/grant_cancel_callback.py create mode 100644 tgbot/handlers/restore.py delete mode 100644 tgbot/middlewares/db.py diff --git a/.env.dist b/.env.dist index 211d5db..86d3d93 100644 --- a/.env.dist +++ b/.env.dist @@ -5,9 +5,6 @@ BOT_TOKEN=123456:Your-TokEn_ExaMple ADMINS=123456,654321 USE_REDIS=False -DB_USER=exampleDBUserName -PG_PASSWORD=examplePostgresPass -DB_PASS=exampleDBPassword -DB_NAME=exampleDBName -DB_HOST=127.0.0.1 +DB_NAME=Granted.db +GRANT_NUMBER=1 diff --git a/bot.py b/bot.py index c6ef904..fbbebe9 100644 --- a/bot.py +++ b/bot.py @@ -4,30 +4,54 @@ from aiogram import Bot, Dispatcher from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.contrib.fsm_storage.redis import RedisStorage2 - +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.types import AllowedUpdates + +from filters.moder_group import IsModerGroup +from handlers.check import register_check_queue +from handlers.get_granted import register_get_granted +from handlers.restore import register_restore +from tgbot.handlers.grant_cancel_callback import register_cancel_grant +from tgbot.handlers.grant_callback import register_grant +from tgbot.filters.granted import IsNotGranted +from tgbot.filters.count import IsGrantCount +from tgbot.filters.user_group import IsUserGroup +from tgbot.Utils.DBWorker import create_tables from tgbot.config import load_config from tgbot.filters.admin import AdminFilter +from tgbot.filters.group_join import IsGroupJoin from tgbot.handlers.admin import register_admin +from tgbot.handlers.catch_update import register_catch from tgbot.handlers.echo import register_echo from tgbot.handlers.user import register_user -from tgbot.middlewares.db import DbMiddleware logger = logging.getLogger(__name__) def register_all_middlewares(dp): - dp.setup_middleware(DbMiddleware()) + dp.setup_middleware(LoggingMiddleware()) def register_all_filters(dp): dp.filters_factory.bind(AdminFilter) + dp.filters_factory.bind(IsGroupJoin) + dp.filters_factory.bind(IsUserGroup) + dp.filters_factory.bind(IsModerGroup) + dp.filters_factory.bind(IsGrantCount) + dp.filters_factory.bind(IsNotGranted) def register_all_handlers(dp): + # register_echo(dp) register_admin(dp) register_user(dp) + register_catch(dp) + register_grant(dp) + register_cancel_grant(dp) + register_check_queue(dp) + register_restore(dp) + register_get_granted(dp) - register_echo(dp) async def main(): @@ -43,14 +67,16 @@ async def main(): dp = Dispatcher(bot, storage=storage) bot['config'] = config - register_all_middlewares(dp) register_all_filters(dp) register_all_handlers(dp) + await create_tables() # start try: - await dp.start_polling() + await bot.delete_webhook(drop_pending_updates=True) + await dp.start_polling( + allowed_updates=AllowedUpdates.MESSAGE + AllowedUpdates.CHAT_MEMBER + AllowedUpdates.CALLBACK_QUERY) finally: await dp.storage.close() await dp.storage.wait_closed() diff --git a/requirements.txt b/requirements.txt index e40b428..a02d288 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ -aiogram~=2.18 +aiogram~=2.21 aioredis~=2.0 environs~=9.0 +aiosqlite~=0.17 +python-dotenv~=0.20 \ No newline at end of file diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py new file mode 100644 index 0000000..99cb10e --- /dev/null +++ b/tgbot/Utils/DBWorker.py @@ -0,0 +1,135 @@ +import os +import aiosqlite + + +async def db_execute(string, values=None, multiple=False, get=False) -> bool: + """Функция для выполнения SQL запросов""" + db_name = os.getenv('DB_NAME') + async with aiosqlite.connect(db_name) as db: + if multiple: + await db.executemany(string, values) + await db.commit() + elif values: + await db.execute(string, values) + await db.commit() + else: + if get: + async with db.execute(string) as cursor: + return await cursor.fetchall() + else: + await db.execute(string) + await db.commit() + return True + + +async def create_tables() -> None: + """Функция для создания БД и создания таблиц""" + + string = """CREATE TABLE IF NOT EXISTS granted( + id INTEGER PRIMARY KEY autoincrement, + group_id_users INTEGER, + name_group TEXT, + user_id INTEGER, + user TEXT, + group_id_mod INTEGER, + moder_id INTEGER, + count, + datetime_update TEXT, + datetime_granted TEXT, + username TEXT); + """ + await db_execute(string) + + string = """CREATE TABLE IF NOT EXISTS groups( + id INTEGER PRIMARY KEY autoincrement, + mod_group_id INTEGER, + user_group_ids TEXT); + """ + await db_execute(string) + + string = """CREATE TABLE IF NOT EXISTS queue( + id INTEGER PRIMARY KEY autoincrement, + message_id INTEGER, + group_id_users INTEGER, + name_group TEXT, + group_id_mod INTEGER, + user_id INTEGER, + user TEXT, + count INTEGER, + datetime_update TEXT, + UUID TEXT, + username TEXT); + """ + await db_execute(string) + + +async def get_users_groups(group_id): + return await db_execute(string=f'SELECT user_group_ids FROM groups WHERE mod_group_id={group_id}', + get=True) + + +async def get_moder_groups(group_id): + return await db_execute(string=f'SELECT mod_group_id FROM groups WHERE user_group_ids LIKE "%{group_id}%"', + get=True) + + +async def set_data_queue(values): + return await db_execute(string= + f"INSERT INTO queue(message_id, group_id_users, name_group, group_id_mod, user_id, user, count, datetime_update, UUID, username) " + f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + values=values) + + +async def update_data_queue(message_id, old_message_id, group_id): + return await db_execute( + string=f'UPDATE queue SET message_id={message_id} WHERE message_id={old_message_id} AND ' + f'group_id_users LIKE "%{group_id}%"') + + +async def set_data_granted(values): + return await db_execute(string= + f"INSERT INTO granted(group_id_users, name_group, user_id, user, group_id_mod, moder_id, count, datetime_update, datetime_granted, username) " + f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + values=values, multiple=True) + +async def get_data_granted(group_id_moder): + return await db_execute(string=f'SELECT * FROM granted WHERE group_id_mod={group_id_moder} ORDER BY group_id_users', + get=True) + + +async def get_count_queue(group_id): + return await db_execute(string=f"SELECT COUNT(*) FROM queue WHERE group_id_users={group_id}", get=True) + + +async def check_granted(user_id, group_id): + return await db_execute( + string=f"SELECT COUNT(*) FROM granted WHERE user_id={user_id} AND group_id_users={group_id}", get=True) + + +async def check_queue(user_id, group_id): + return await db_execute( + string=f"SELECT COUNT(*) FROM queue WHERE user_id={user_id} AND group_id_users={group_id}", get=True) + + +async def get_message_in_queue(uid): + return await db_execute(string=f"SELECT * FROM queue WHERE UUID='{uid}'", get=True) + + +async def get_queue(group_id, message_id=0): + return await db_execute( + string=f"SELECT * FROM queue WHERE group_id_users={group_id} AND message_id!={message_id}", + get=True) + + +async def delete_from_queue(group_id): + return await db_execute(string=f"DELETE FROM queue WHERE group_id_users={group_id}") + + +async def count_from_queue(group_id): + return await db_execute( + string=f"SELECT count FROM queue WHERE group_id_users={group_id} ORDER BY datetime_update limit 1", + get=True) + + +async def vacuum(): + return await db_execute(string="VACUUM") diff --git a/tgbot/Utils/__init__.py b/tgbot/Utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/Utils/get_user_link.py b/tgbot/Utils/get_user_link.py new file mode 100644 index 0000000..da7bbe1 --- /dev/null +++ b/tgbot/Utils/get_user_link.py @@ -0,0 +1,16 @@ +from aiogram import md +from aiogram import types + + +async def get_link(user: types.User): + if not user.url: + return 'пользователь' + if user.first_name: + username = user.first_name + if user.last_name: + username += f' {user.last_name}' + elif user.username: + username = user.username + else: + username = 'пользователь' + return md.hlink(username, user.url) diff --git a/tgbot/config.py b/tgbot/config.py index 26e8e94..8bfe029 100644 --- a/tgbot/config.py +++ b/tgbot/config.py @@ -5,9 +5,6 @@ @dataclass class DbConfig: - host: str - password: str - user: str database: str @@ -20,6 +17,7 @@ class TgBot: @dataclass class Miscellaneous: + grant_count: int other_params: str = None @@ -41,10 +39,9 @@ def load_config(path: str = None): use_redis=env.bool("USE_REDIS"), ), db=DbConfig( - host=env.str('DB_HOST'), - password=env.str('DB_PASS'), - user=env.str('DB_USER'), database=env.str('DB_NAME') ), - misc=Miscellaneous() + misc=Miscellaneous( + grant_count=env.int('GRANT_NUMBER') + ) ) diff --git a/tgbot/filters/count.py b/tgbot/filters/count.py new file mode 100644 index 0000000..e5d1b12 --- /dev/null +++ b/tgbot/filters/count.py @@ -0,0 +1,27 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter +from aiogram.dispatcher.handler import CancelHandler + +from tgbot.Utils.DBWorker import get_count_queue + + +class IsGrantCount(BoundFilter): + #TODO доделать + key = "is_grant_count" + + def __init__(self, is_grant_count: bool): + self.is_grant_count = is_grant_count + + async def check(self, update: types.ChatMemberUpdated): + config_count = update.bot.data['config'].misc.grant_count + if not config_count: + raise CancelHandler() + count = await update.chat.get_member_count() + count_to_delete = await get_count_queue(update.chat.id) + if count_to_delete: + if count_to_delete[0][0] < 3: + return {"count": count} + elif not count % config_count: + return {"count": count} + return False + diff --git a/tgbot/filters/granted.py b/tgbot/filters/granted.py new file mode 100644 index 0000000..5d01428 --- /dev/null +++ b/tgbot/filters/granted.py @@ -0,0 +1,20 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter + +from tgbot.Utils.DBWorker import check_granted, check_queue + + +class IsNotGranted(BoundFilter): + key = "is_not_granted" + + def __init__(self, is_not_granted: bool): + self.is_not_granted = is_not_granted + + async def check(self, update: types.ChatMemberUpdated): + granted = await check_granted(user_id=update.new_chat_member.user.id, group_id=update.chat.id) + if granted[0][0]: + return False + in_queue = await check_queue(user_id=update.new_chat_member.user.id, group_id=update.chat.id) + if in_queue[0][0]: + return False + return True diff --git a/tgbot/filters/group_join.py b/tgbot/filters/group_join.py new file mode 100644 index 0000000..0c99b8a --- /dev/null +++ b/tgbot/filters/group_join.py @@ -0,0 +1,12 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter + + +class IsGroupJoin(BoundFilter): + key = "is_group_join" + + def __init__(self, is_group_join: bool): + self.is_group_join = is_group_join + + async def check(self, update: types.ChatMemberUpdated): + return update.new_chat_member.is_chat_member() diff --git a/tgbot/filters/moder_group.py b/tgbot/filters/moder_group.py new file mode 100644 index 0000000..a1f2920 --- /dev/null +++ b/tgbot/filters/moder_group.py @@ -0,0 +1,20 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter + +from tgbot.Utils.DBWorker import get_users_groups + + +class IsModerGroup(BoundFilter): + """ + Фильтр для проверки наличия назначенных групп пользователей и получения их id + """ + key = "is_moder_group" + + def __init__(self, is_moder_group: bool): + self.is_moder_group = is_moder_group + + async def check(self, message: types.Message): + ids = await get_users_groups(message.chat.id) + if ids: + return {"ids": ids} + return False diff --git a/tgbot/filters/user_group.py b/tgbot/filters/user_group.py new file mode 100644 index 0000000..988af24 --- /dev/null +++ b/tgbot/filters/user_group.py @@ -0,0 +1,20 @@ +from aiogram import types +from aiogram.dispatcher.filters import BoundFilter + +from tgbot.Utils.DBWorker import get_moder_groups + + +class IsUserGroup(BoundFilter): + """ + Фильтр для проверки наличия назначенных групп модераторов и получения их id + """ + key = "is_user_group" + + def __init__(self, is_user_group: bool): + self.is_user_group = is_user_group + + async def check(self, update: types.ChatMemberUpdated): + ids = await get_moder_groups(update.chat.id) + if ids: + return {"ids": ids} + return False diff --git a/tgbot/handlers/catch_update.py b/tgbot/handlers/catch_update.py new file mode 100644 index 0000000..96a3a26 --- /dev/null +++ b/tgbot/handlers/catch_update.py @@ -0,0 +1,37 @@ +from typing import List +from tgbot.keyboards.inline import get_gran_kb +from aiogram import Dispatcher, types +from aiogram.types import ChatType +import uuid +from tgbot.Utils.get_user_link import get_link + +from tgbot.Utils.DBWorker import set_data_queue + + +async def new_chat(update: types.ChatMemberUpdated, ids: List[tuple[int]], count: int): + link = await get_link(update.new_chat_member.user) + uid = str(uuid.uuid4()) + if update.new_chat_member.user.username: + username = f'@{update.new_chat_member.user.username}' + else: + username = 'ника нет' + text = f'🎉 В “{update.chat.title}” группу вступил юбилейный пользователь\n' \ + f'{link} ({username}),\n' \ + f'🔢{count}. 🕐Время вступления {update.date}' + + message = await update.bot.send_message(ids[0][0], text=text, reply_markup=await get_gran_kb(uid=uid)) + + await set_data_queue( + values=( + message.message_id, update.chat.id, update.chat.title, ids[0][0], update.new_chat_member.user.id, link, + count, update.date, uid, username)) + + +def register_catch(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] + dp.register_chat_member_handler(new_chat, + chat_type=chat_types, + is_group_join=True, + is_not_granted=True, + is_grant_count=True, + is_user_group=True) diff --git a/tgbot/handlers/check.py b/tgbot/handlers/check.py new file mode 100644 index 0000000..280fcd5 --- /dev/null +++ b/tgbot/handlers/check.py @@ -0,0 +1,26 @@ +from typing import List +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from tgbot.Utils.DBWorker import get_queue + + +async def check_queue(message: types.Message, ids: List[tuple[str]]): + users_groups_ids = ids[0][0].split(',') + + for group_id in users_groups_ids: + messages_in_queue = await get_queue(group_id) + if messages_in_queue: + text = f'Есть не поздравленные пользователи в группе {messages_in_queue[0][3]}:\n' + for message_in_queue in messages_in_queue: + text += f'- Пользователь {message_in_queue[6]} номер вступления {message_in_queue[7]}\n' + await message.answer(text=text) + else: + await message.answer('Нет не поздравленных пользователей') + + +def register_check_queue(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] + dp.register_message_handler(check_queue, + chat_type=chat_types, + commands=['проверка'], + is_moder_group=True) diff --git a/tgbot/handlers/echo.py b/tgbot/handlers/echo.py index e280f64..e26197b 100644 --- a/tgbot/handlers/echo.py +++ b/tgbot/handlers/echo.py @@ -7,7 +7,7 @@ async def bot_echo(message: types.Message): text = [ "Эхо без состояния.", "Сообщение:", - message.text + message.text, ] await message.answer('\n'.join(text)) @@ -26,3 +26,4 @@ async def bot_echo_all(message: types.Message, state: FSMContext): def register_echo(dp: Dispatcher): dp.register_message_handler(bot_echo) dp.register_message_handler(bot_echo_all, state="*", content_types=types.ContentTypes.ANY) + pass diff --git a/tgbot/handlers/get_granted.py b/tgbot/handlers/get_granted.py new file mode 100644 index 0000000..0f11a31 --- /dev/null +++ b/tgbot/handlers/get_granted.py @@ -0,0 +1,25 @@ +from typing import List +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from tgbot.Utils.DBWorker import get_data_granted + + +async def get_granted(message: types.Message, ids: List[tuple[str]]): + granted_list = await get_data_granted(message.chat.id) + if granted_list: + for granted in granted_list: + emoji = '🎉' + if granted[6]: + emoji = '👑👑👑' + await message.answer(text=f'{emoji} “{granted[2]}” 👤 {granted[4]} ({granted[10]}),\n' + f'🔢 {granted[7]} 🕐 {granted[8]}') + else: + await message.answer('В группах для модерированния еще нет поздравленных пользователей') + + +def register_get_granted(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] + dp.register_message_handler(get_granted, + chat_type=chat_types, + commands=['списокЮбилейный'], + is_moder_group=True) diff --git a/tgbot/handlers/grant_callback.py b/tgbot/handlers/grant_callback.py new file mode 100644 index 0000000..f6e0615 --- /dev/null +++ b/tgbot/handlers/grant_callback.py @@ -0,0 +1,70 @@ +from contextlib import suppress + +from aiogram import Dispatcher, types +from aiogram.dispatcher.handler import CancelHandler +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeEdited, MessageToEditNotFound, MessageNotModified + +from tgbot.Utils.DBWorker import get_message_in_queue, get_queue, delete_from_queue, vacuum, set_data_granted, \ + count_from_queue + + +async def grant_user(call: types.CallbackQuery): + uid = call.data.split('|')[1] + message_btn = await get_message_in_queue(uid) + if not message_btn: + raise CancelHandler() + message_id = message_btn[0][1] + group_id_users = message_btn[0][2] + group_id_mod = message_btn[0][4] + user_id = message_btn[0][5] + user = message_btn[0][6] + count = message_btn[0][7] + datetime_update = message_btn[0][8] + datetime_granted = call.message.date + moder_id = call.from_user.id + count_for_grant = await count_from_queue(group_id_users) + username = message_btn[0][10] + + chat_member = await call.bot.get_chat_member(group_id_users, user_id) + if not chat_member: + await call.answer(text="Такого пользователя уже нет в группе", show_alert=True) + await call.bot.edit_message_reply_markup(chat_id=call.message.chat.id, message_id=message_id, reply_markup=None) + raise CancelHandler() + + text = f'🎉 Поздравляю, {user}, как же удачно попали в нужное место и в нужное время!\n' \ + f'Вы {count_for_grant[0][0]} участник комьюнити.\n' \ + f'Вас ждут плюшки и печенюшки!🎉' + + grant_message = await call.bot.send_message(chat_id=group_id_users, text=text) + + await call.answer() + await call.message.answer(text=f"Пользователь {user} в группе {grant_message.chat.title} поздравлен") + + try: + await call.bot.edit_message_reply_markup(chat_id=group_id_mod, message_id=message_id, reply_markup=None) + except (MessageCantBeEdited, MessageToEditNotFound, MessageNotModified, MessageCantBeEdited) as exc: + pass + + granted = [(group_id_users, grant_message.chat.title, user_id, user, group_id_mod, moder_id, count, datetime_update, + datetime_granted, username)] + + queue = await get_queue(group_id=group_id_users, message_id=message_id) + if queue: + for message in queue: + with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified, MessageCantBeEdited): + await call.bot.edit_message_reply_markup(chat_id=group_id_mod, message_id=message[1], reply_markup=None) + granted.append((message[2], message[3], message[5], message[6], message[4], '', message[7], message[8], + '', message[10])) + + + await delete_from_queue(group_id_users) + await vacuum() + + await set_data_granted(values=granted) + + +def register_grant(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] + dp.register_callback_query_handler(grant_user, lambda call: call.data and call.data.split('|')[0] == "grant", + chat_type=chat_types) diff --git a/tgbot/handlers/grant_cancel_callback.py b/tgbot/handlers/grant_cancel_callback.py new file mode 100644 index 0000000..c6d37bb --- /dev/null +++ b/tgbot/handlers/grant_cancel_callback.py @@ -0,0 +1,19 @@ +from aiogram import Dispatcher, types +from aiogram.types import ChatType + +from tgbot.Utils.DBWorker import get_message_in_queue + + +async def cancel_grant_user(call: types.CallbackQuery): + uid = call.data.split('|')[1] + message = await get_message_in_queue(uid) + await call.answer() + if message: + await call.bot.edit_message_reply_markup(chat_id=call.message.chat.id, message_id=message[0][1], + reply_markup=None) + + +def register_cancel_grant(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] + dp.register_callback_query_handler(cancel_grant_user, lambda call: call.data and call.data.split('|')[0] == "can", + chat_type=chat_types) diff --git a/tgbot/handlers/restore.py b/tgbot/handlers/restore.py new file mode 100644 index 0000000..a8ca455 --- /dev/null +++ b/tgbot/handlers/restore.py @@ -0,0 +1,35 @@ +from contextlib import suppress +from typing import List + +from aiogram.utils.exceptions import MessageToDeleteNotFound, MessageCantBeDeleted + +from tgbot.keyboards.inline import get_gran_kb +from aiogram import Dispatcher, types +from aiogram.types import ChatType + +from tgbot.Utils.DBWorker import get_queue, update_data_queue + + +async def restore(message: types.Message, ids: List[tuple[str]]): + users_groups_ids = ids[0][0].split(',') + + for group_id in users_groups_ids: + messages_in_queue = await get_queue(group_id) + if messages_in_queue: + for message_in_queue in messages_in_queue: + with suppress(MessageToDeleteNotFound, MessageCantBeDeleted): + await message.bot.delete_message(message.chat.id, message_in_queue[1]) + text = f'🎉 “{message_in_queue[3]}” 👤 {message_in_queue[6]} ({message_in_queue[10]}),\n' \ + f'🔢 {message_in_queue[7]} 🕐 {message_in_queue[8]}' + new_message = await message.bot.send_message(message.chat.id, text=text, + reply_markup=await get_gran_kb(uid=message_in_queue[9])) + await update_data_queue(message_id=new_message.message_id, old_message_id=message_in_queue[1], + group_id=message_in_queue[2]) + + +def register_restore(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] + dp.register_message_handler(restore, + chat_type=chat_types, + commands=['восстановить'], + is_moder_group=True) diff --git a/tgbot/keyboards/inline.py b/tgbot/keyboards/inline.py index e69de29..d450840 100644 --- a/tgbot/keyboards/inline.py +++ b/tgbot/keyboards/inline.py @@ -0,0 +1,7 @@ +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + +async def get_gran_kb(uid): + grant_btn = InlineKeyboardButton('Поздравить!', callback_data=f'grant|{uid}') + cancel_btn = InlineKeyboardButton('Отмена', callback_data=f'can|{uid}') + grant_kb = InlineKeyboardMarkup().add(grant_btn, cancel_btn) + return grant_kb diff --git a/tgbot/middlewares/db.py b/tgbot/middlewares/db.py deleted file mode 100644 index c4e5569..0000000 --- a/tgbot/middlewares/db.py +++ /dev/null @@ -1,10 +0,0 @@ -from aiogram.dispatcher.middlewares import LifetimeControllerMiddleware - - -class DbMiddleware(LifetimeControllerMiddleware): - skip_patterns = ["error", "update"] - - async def pre_process(self, obj, data, *args): - db_session = obj.bot.get('db') - # Передаем данные из таблицы в хендлер - # data['some_model'] = await Model.get() From 56459e3d7ad828af27f18a6d29b5fbabf3e68689 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Tue, 12 Jul 2022 19:06:02 +0300 Subject: [PATCH 03/16] First commit --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4c33c9a..9fe4e99 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,7 @@ venv.bak/ # Pyre type checker .pyre/ .idea/* -.env \ No newline at end of file +.env + +# Database +*.db \ No newline at end of file From 9b0596d722671028c4342b71f84be49b88555047 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Wed, 13 Jul 2022 11:02:55 +0300 Subject: [PATCH 04/16] Little fix in filters for callbacks --- tgbot/handlers/echo.py | 1 - tgbot/handlers/grant_callback.py | 4 ++-- tgbot/handlers/grant_cancel_callback.py | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tgbot/handlers/echo.py b/tgbot/handlers/echo.py index e26197b..aa26706 100644 --- a/tgbot/handlers/echo.py +++ b/tgbot/handlers/echo.py @@ -26,4 +26,3 @@ async def bot_echo_all(message: types.Message, state: FSMContext): def register_echo(dp: Dispatcher): dp.register_message_handler(bot_echo) dp.register_message_handler(bot_echo_all, state="*", content_types=types.ContentTypes.ANY) - pass diff --git a/tgbot/handlers/grant_callback.py b/tgbot/handlers/grant_callback.py index f6e0615..7e9b688 100644 --- a/tgbot/handlers/grant_callback.py +++ b/tgbot/handlers/grant_callback.py @@ -1,6 +1,7 @@ from contextlib import suppress from aiogram import Dispatcher, types +from aiogram.dispatcher.filters import Text from aiogram.dispatcher.handler import CancelHandler from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeEdited, MessageToEditNotFound, MessageNotModified @@ -66,5 +67,4 @@ async def grant_user(call: types.CallbackQuery): def register_grant(dp: Dispatcher): chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] - dp.register_callback_query_handler(grant_user, lambda call: call.data and call.data.split('|')[0] == "grant", - chat_type=chat_types) + dp.register_callback_query_handler(grant_user, Text(startswith='grant'), chat_type=chat_types) diff --git a/tgbot/handlers/grant_cancel_callback.py b/tgbot/handlers/grant_cancel_callback.py index c6d37bb..56c3e1f 100644 --- a/tgbot/handlers/grant_cancel_callback.py +++ b/tgbot/handlers/grant_cancel_callback.py @@ -1,4 +1,5 @@ from aiogram import Dispatcher, types +from aiogram.dispatcher.filters import Text from aiogram.types import ChatType from tgbot.Utils.DBWorker import get_message_in_queue @@ -15,5 +16,4 @@ async def cancel_grant_user(call: types.CallbackQuery): def register_cancel_grant(dp: Dispatcher): chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] - dp.register_callback_query_handler(cancel_grant_user, lambda call: call.data and call.data.split('|')[0] == "can", - chat_type=chat_types) + dp.register_callback_query_handler(cancel_grant_user, Text(startswith='can'), chat_type=chat_types,) From 9b7f8e7437039efda1521123ef28e74efb298090 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Thu, 14 Jul 2022 19:54:42 +0300 Subject: [PATCH 05/16] Add admin interface --- bot.py | 18 +++++++ tgbot/Utils/DBWorker.py | 62 +++++++++++++++++++----- tgbot/Utils/check_message_user_groups.py | 10 ++++ tgbot/Utils/check_number.py | 7 +++ tgbot/Utils/delete_doubles.py | 2 + tgbot/Utils/get_ids_for_grant_numbers.py | 2 + tgbot/filters/count.py | 11 ++--- tgbot/handlers/add_groups_callback.py | 22 +++++++++ tgbot/handlers/configure_groups.py | 20 ++++++++ tgbot/handlers/delete_from_groups.py | 35 +++++++++++++ tgbot/handlers/delete_groups_callback.py | 26 ++++++++++ tgbot/handlers/get_mod_group.py | 30 ++++++++++++ tgbot/handlers/get_users_groups.py | 44 +++++++++++++++++ tgbot/handlers/reset_menu.py | 21 ++++++++ tgbot/handlers/restore.py | 2 + tgbot/handlers/show_groups_callback.py | 33 +++++++++++++ tgbot/handlers/user.py | 2 +- tgbot/keyboards/inline.py | 9 ++++ tgbot/misc/set_commands.py | 9 ++++ tgbot/misc/states.py | 8 +++ 20 files changed, 354 insertions(+), 19 deletions(-) create mode 100644 tgbot/Utils/check_message_user_groups.py create mode 100644 tgbot/Utils/check_number.py create mode 100644 tgbot/Utils/delete_doubles.py create mode 100644 tgbot/Utils/get_ids_for_grant_numbers.py create mode 100644 tgbot/handlers/add_groups_callback.py create mode 100644 tgbot/handlers/configure_groups.py create mode 100644 tgbot/handlers/delete_from_groups.py create mode 100644 tgbot/handlers/delete_groups_callback.py create mode 100644 tgbot/handlers/get_mod_group.py create mode 100644 tgbot/handlers/get_users_groups.py create mode 100644 tgbot/handlers/reset_menu.py create mode 100644 tgbot/handlers/show_groups_callback.py create mode 100644 tgbot/misc/set_commands.py diff --git a/bot.py b/bot.py index fbbebe9..e239949 100644 --- a/bot.py +++ b/bot.py @@ -8,9 +8,18 @@ from aiogram.types import AllowedUpdates from filters.moder_group import IsModerGroup +from handlers.add_groups_callback import register_add_groups from handlers.check import register_check_queue +from handlers.configure_groups import register_configure_groups +from handlers.delete_from_groups import register_delete_from_groups +from handlers.delete_groups_callback import register_delete_groups_cb from handlers.get_granted import register_get_granted +from handlers.get_mod_group import register_get_mod_group +from handlers.get_users_groups import register_get_users_group +from handlers.reset_menu import register_reset_menu from handlers.restore import register_restore +from handlers.show_groups_callback import register_show_groups +from misc.set_commands import set_default_commands from tgbot.handlers.grant_cancel_callback import register_cancel_grant from tgbot.handlers.grant_callback import register_grant from tgbot.filters.granted import IsNotGranted @@ -51,6 +60,14 @@ def register_all_handlers(dp): register_check_queue(dp) register_restore(dp) register_get_granted(dp) + register_configure_groups(dp) + register_show_groups(dp) + register_add_groups(dp) + register_get_mod_group(dp) + register_get_users_group(dp) + register_reset_menu(dp) + register_delete_groups_cb(dp) + register_delete_from_groups(dp) @@ -70,6 +87,7 @@ async def main(): register_all_middlewares(dp) register_all_filters(dp) register_all_handlers(dp) + await set_default_commands(dp) await create_tables() # start diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index 99cb10e..6dc1c76 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -2,24 +2,26 @@ import aiosqlite -async def db_execute(string, values=None, multiple=False, get=False) -> bool: +async def db_execute(string, values=None, multiple=False, get=False, get_delete_info=False) -> bool: """Функция для выполнения SQL запросов""" db_name = os.getenv('DB_NAME') async with aiosqlite.connect(db_name) as db: if multiple: - await db.executemany(string, values) - await db.commit() + async with db.executemany(string, values) as cursor: + await db.commit() + return cursor.rowcount elif values: - await db.execute(string, values) - await db.commit() + async with db.execute(string, values) as cursor: + await db.commit() + return cursor.rowcount else: if get: async with db.execute(string) as cursor: return await cursor.fetchall() else: - await db.execute(string) - await db.commit() - return True + async with db.execute(string) as cursor: + await db.commit() + return cursor.rowcount async def create_tables() -> None: @@ -42,7 +44,7 @@ async def create_tables() -> None: string = """CREATE TABLE IF NOT EXISTS groups( id INTEGER PRIMARY KEY autoincrement, - mod_group_id INTEGER, + mod_group_id INTEGER UNIQUE, user_group_ids TEXT); """ await db_execute(string) @@ -62,6 +64,13 @@ async def create_tables() -> None: """ await db_execute(string) + string = """CREATE TABLE IF NOT EXISTS grant_numbers( + id INTEGER PRIMARY KEY autoincrement, + group_id INTEGER UNIQUE, + numbers TEXT); + """ + await db_execute(string) + async def get_users_groups(group_id): return await db_execute(string=f'SELECT user_group_ids FROM groups WHERE mod_group_id={group_id}', @@ -73,11 +82,19 @@ async def get_moder_groups(group_id): get=True) +async def set_group_ids_grant_numbers(values): + return await db_execute(string= + f"INSERT OR IGNORE INTO grant_numbers(group_id) VALUES(?);", values=values, multiple=True) + + +async def delete_data_from_groups(ids): + return await db_execute(string=f'DELETE FROM groups WHERE id=?', values=ids, multiple=True) + + async def set_data_queue(values): return await db_execute(string= f"INSERT INTO queue(message_id, group_id_users, name_group, group_id_mod, user_id, user, count, datetime_update, UUID, username) " - f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", - values=values) + f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", values=values) async def update_data_queue(message_id, old_message_id, group_id): @@ -92,6 +109,7 @@ async def set_data_granted(values): f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", values=values, multiple=True) + async def get_data_granted(group_id_moder): return await db_execute(string=f'SELECT * FROM granted WHERE group_id_mod={group_id_moder} ORDER BY group_id_users', get=True) @@ -131,5 +149,27 @@ async def count_from_queue(group_id): get=True) +async def get_groups(): + return await db_execute(string='SELECT * FROM groups', get=True) + + +async def get_user_ids_from_groups(mod_group_id): + return await db_execute(string=f'SELECT user_group_ids FROM groups WHERE mod_group_id={mod_group_id}', get=True) + + +async def set_data_groups(values): + return await db_execute(string=f'INSERT OR REPLACE INTO groups(mod_group_id, user_group_ids)' + f' VALUES(?, ?);', values=values) + + +async def check_grant_numbers(group_id): + return await db_execute( + string=f"SELECT COUNT(*) FROM grant_numbers WHERE group_id LIKE '%{group_id}%'", get=True) + + +async def check_data_from_grant_numbers(group_id): + return await db_execute(string=f'SELECT COUNT(*) FROM grant_numbers WHERE group_id={group_id} LIMIT 1', get=True) + + async def vacuum(): return await db_execute(string="VACUUM") diff --git a/tgbot/Utils/check_message_user_groups.py b/tgbot/Utils/check_message_user_groups.py new file mode 100644 index 0000000..44ab30b --- /dev/null +++ b/tgbot/Utils/check_message_user_groups.py @@ -0,0 +1,10 @@ +from Utils.check_number import check_number_in_message + + +async def check_users_groups(message: str): + + users_groups_ids = message.split(',') + for number in users_groups_ids: + if not await check_number_in_message(number=number): + return False + return True diff --git a/tgbot/Utils/check_number.py b/tgbot/Utils/check_number.py new file mode 100644 index 0000000..80cf89a --- /dev/null +++ b/tgbot/Utils/check_number.py @@ -0,0 +1,7 @@ + +async def check_number_in_message(number: str): + if number[:1] == '-': + if number[1:].isdigit(): + return int(number) + elif number.isdigit(): + return int(number) diff --git a/tgbot/Utils/delete_doubles.py b/tgbot/Utils/delete_doubles.py new file mode 100644 index 0000000..620ec4f --- /dev/null +++ b/tgbot/Utils/delete_doubles.py @@ -0,0 +1,2 @@ +async def delete_doubles_ids(message: str): + return ','.join(set(message.replace(' ', '').split(','))) diff --git a/tgbot/Utils/get_ids_for_grant_numbers.py b/tgbot/Utils/get_ids_for_grant_numbers.py new file mode 100644 index 0000000..ca36ea0 --- /dev/null +++ b/tgbot/Utils/get_ids_for_grant_numbers.py @@ -0,0 +1,2 @@ +async def get_ids_for_multiple_record(ids: str): + return [(group_id,) for group_id in ids.split(',')] diff --git a/tgbot/filters/count.py b/tgbot/filters/count.py index e5d1b12..11f2b07 100644 --- a/tgbot/filters/count.py +++ b/tgbot/filters/count.py @@ -2,11 +2,11 @@ from aiogram.dispatcher.filters import BoundFilter from aiogram.dispatcher.handler import CancelHandler -from tgbot.Utils.DBWorker import get_count_queue +from tgbot.Utils.DBWorker import get_count_queue, check_data_from_grant_numbers class IsGrantCount(BoundFilter): - #TODO доделать + key = "is_grant_count" def __init__(self, is_grant_count: bool): @@ -18,10 +18,7 @@ async def check(self, update: types.ChatMemberUpdated): raise CancelHandler() count = await update.chat.get_member_count() count_to_delete = await get_count_queue(update.chat.id) - if count_to_delete: - if count_to_delete[0][0] < 3: - return {"count": count} - elif not count % config_count: + saved_grant_numbers = await check_data_from_grant_numbers(update.chat.id) + if count_to_delete[0][0] < 3 or saved_grant_numbers[0][0] or not count % config_count: return {"count": count} return False - diff --git a/tgbot/handlers/add_groups_callback.py b/tgbot/handlers/add_groups_callback.py new file mode 100644 index 0000000..4d7f88b --- /dev/null +++ b/tgbot/handlers/add_groups_callback.py @@ -0,0 +1,22 @@ +from contextlib import suppress +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted +from misc.states import Configure + + +async def add_groups(call: types.CallbackQuery): + with suppress(MessageCantBeDeleted): + await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + await call.message.answer(text='Введите id группы модераторов, целое число (/reset для сброса)') + await Configure.AddModGroups.set() + + +def register_add_groups(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(add_groups, + chat_type=chat_types, + text='add_groups', + state="*", + is_admin=True) diff --git a/tgbot/handlers/configure_groups.py b/tgbot/handlers/configure_groups.py new file mode 100644 index 0000000..980823d --- /dev/null +++ b/tgbot/handlers/configure_groups.py @@ -0,0 +1,20 @@ +from typing import List +from aiogram import Dispatcher, types +from aiogram.types import ChatType + +from keyboards.inline import get_conf_groups_kb +from tgbot.Utils.DBWorker import get_data_granted + + +async def configure_groups(message: types.Message): + await message.answer(text='⚙⚙⚙', reply_markup=await get_conf_groups_kb()) + + + +def register_configure_groups(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(configure_groups, + chat_type=chat_types, + commands=['configure_groups'], + is_admin=True + ) diff --git a/tgbot/handlers/delete_from_groups.py b/tgbot/handlers/delete_from_groups.py new file mode 100644 index 0000000..2408f8a --- /dev/null +++ b/tgbot/handlers/delete_from_groups.py @@ -0,0 +1,35 @@ +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType + +from Utils.DBWorker import delete_data_from_groups +from Utils.check_message_user_groups import check_users_groups +from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record + +from misc.states import Configure + + +async def delete_from_groups(message: types.Message, state: FSMContext): + if message.text == '/reset': + await state.finish() + return + group_id = await check_users_groups(message.text) + if not group_id: + await message.answer('Введите ids групп модераторов для удаления записей из базы, целые числа, ' + 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') + return + ids = await get_ids_for_multiple_record(message.text) + deleted_records = await delete_data_from_groups(ids) + if deleted_records: + await message.answer(f'Удалил {deleted_records} записи(-ей)') + else: + await message.answer(f'Таких групп нет в таблице') + await state.finish() + + +def register_delete_from_groups(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(delete_from_groups, + chat_type=chat_types, + state=Configure.DeleteUserGroups, + is_admin=True) diff --git a/tgbot/handlers/delete_groups_callback.py b/tgbot/handlers/delete_groups_callback.py new file mode 100644 index 0000000..5c2a116 --- /dev/null +++ b/tgbot/handlers/delete_groups_callback.py @@ -0,0 +1,26 @@ +from contextlib import suppress + +from aiogram import md +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted + +from misc.states import Configure + + +async def delete_groups(call: types.CallbackQuery): + with suppress(MessageCantBeDeleted): + await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + await call.message.answer('Введите ids групп модераторов для удаления записей из базы, целые числа, ' + 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') + await Configure.DeleteUserGroups.set() + + +def register_delete_groups_cb(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(delete_groups, + chat_type=chat_types, + text='delete_groups', + state="*", + is_admin=True) diff --git a/tgbot/handlers/get_mod_group.py b/tgbot/handlers/get_mod_group.py new file mode 100644 index 0000000..7c3a4f6 --- /dev/null +++ b/tgbot/handlers/get_mod_group.py @@ -0,0 +1,30 @@ +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType + +from Utils.check_number import check_number_in_message + +from misc.states import Configure + + +async def get_mod_group(message: types.Message, state: FSMContext): + if message.text == '/reset': + await state.finish() + return + group_id = await check_number_in_message(message.text) + if not group_id: + await message.answer('Введите id группы модераторов, целое число (/reset для сброса)') + return + + await state.update_data(id_mod=group_id) + await message.answer('Введите IDs групп пользователей, несколько групп,' + ' необходимо разделить через запятую (/reset для сброса)') + await Configure.AddUserGroups.set() + + +def register_get_mod_group(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(get_mod_group, + chat_type=chat_types, + state=Configure.AddModGroups, + is_admin=True) diff --git a/tgbot/handlers/get_users_groups.py b/tgbot/handlers/get_users_groups.py new file mode 100644 index 0000000..0181f71 --- /dev/null +++ b/tgbot/handlers/get_users_groups.py @@ -0,0 +1,44 @@ +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType + +from Utils.check_message_user_groups import check_users_groups +from Utils.delete_doubles import delete_doubles_ids +from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from misc.states import Configure +from tgbot.Utils.DBWorker import set_data_groups, get_user_ids_from_groups, set_group_ids_grant_numbers + + +async def get_users_group(message: types.Message, state: FSMContext): + if message.text == '/reset': + await state.finish() + return + group_ids_check = await check_users_groups(message.text) + + if not group_ids_check: + await message.answer('Введите IDs групп пользователей, целые числа, если групп несколько, ' + 'необходимо разделять с помощь запятой (/reset для сброса)') + return + data = await state.get_data() + id_mod_group = data.get('id_mod') + + existed = await get_user_ids_from_groups(mod_group_id=id_mod_group) + ids_user_groups = message.text + if existed: + ids_user_groups += f',{existed[0][0]}' + text_message = await delete_doubles_ids(ids_user_groups) + await set_data_groups(values=(id_mod_group, text_message,)) + + ids_grant_numbers = await get_ids_for_multiple_record(text_message) + await set_group_ids_grant_numbers(values=ids_grant_numbers) + + await message.answer('Записал') + await state.finish() + + +def register_get_users_group(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(get_users_group, + chat_type=chat_types, + state=Configure.AddUserGroups, + is_admin=True) diff --git a/tgbot/handlers/reset_menu.py b/tgbot/handlers/reset_menu.py new file mode 100644 index 0000000..4d492c0 --- /dev/null +++ b/tgbot/handlers/reset_menu.py @@ -0,0 +1,21 @@ +from contextlib import suppress +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted + + +async def reset_menu(call: types.CallbackQuery, state: FSMContext): + with suppress(MessageCantBeDeleted): + await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + await state.finish() + + +def register_reset_menu(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(reset_menu, + chat_type=chat_types, + text='reset', + state="*", + is_admin=True) diff --git a/tgbot/handlers/restore.py b/tgbot/handlers/restore.py index a8ca455..d18bbb1 100644 --- a/tgbot/handlers/restore.py +++ b/tgbot/handlers/restore.py @@ -25,6 +25,8 @@ async def restore(message: types.Message, ids: List[tuple[str]]): reply_markup=await get_gran_kb(uid=message_in_queue[9])) await update_data_queue(message_id=new_message.message_id, old_message_id=message_in_queue[1], group_id=message_in_queue[2]) + else: + await message.answer('Нет сообщений для восстановления') def register_restore(dp: Dispatcher): diff --git a/tgbot/handlers/show_groups_callback.py b/tgbot/handlers/show_groups_callback.py new file mode 100644 index 0000000..405213c --- /dev/null +++ b/tgbot/handlers/show_groups_callback.py @@ -0,0 +1,33 @@ +from contextlib import suppress + +from aiogram import md +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted + +from tgbot.Utils.DBWorker import get_groups + + +async def show_groups(call: types.CallbackQuery): + groups = await get_groups() + text = md.hunderline('ID | Группа модераторов | Группы пользователей\n') + + with suppress(MessageCantBeDeleted): + await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + if groups: + for group in groups: + text += md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') + text += ' ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\n' + await call.message.answer(text=text) + else: + await call.message.answer(text='Таблица еще пуста') + + +def register_show_groups(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(show_groups, + chat_type=chat_types, + text='show_groups', + state="*", + is_admin=True) \ No newline at end of file diff --git a/tgbot/handlers/user.py b/tgbot/handlers/user.py index f5b820a..a16e066 100644 --- a/tgbot/handlers/user.py +++ b/tgbot/handlers/user.py @@ -3,7 +3,7 @@ async def user_start(message: Message): - await message.reply("Hello, user!") + await message.reply(f"Hello, user!") def register_user(dp: Dispatcher): diff --git a/tgbot/keyboards/inline.py b/tgbot/keyboards/inline.py index d450840..2fb1933 100644 --- a/tgbot/keyboards/inline.py +++ b/tgbot/keyboards/inline.py @@ -5,3 +5,12 @@ async def get_gran_kb(uid): cancel_btn = InlineKeyboardButton('Отмена', callback_data=f'can|{uid}') grant_kb = InlineKeyboardMarkup().add(grant_btn, cancel_btn) return grant_kb + + +async def get_conf_groups_kb(): + show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_groups') + add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_groups') + delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_groups') + reset_btn = InlineKeyboardButton('Отмена', callback_data='reset') + conf_groups_kb = InlineKeyboardMarkup(row_width=1).add(show_btn, add_btn, delete_btn, reset_btn) + return conf_groups_kb diff --git a/tgbot/misc/set_commands.py b/tgbot/misc/set_commands.py new file mode 100644 index 0000000..69bf10d --- /dev/null +++ b/tgbot/misc/set_commands.py @@ -0,0 +1,9 @@ +from aiogram import types + + +async def set_default_commands(dp): + + await dp.bot.set_my_commands([ + types.BotCommand("start", "Запустить бота"), + types.BotCommand("/configure_groups", "Настроить группы") + ]) diff --git a/tgbot/misc/states.py b/tgbot/misc/states.py index e69de29..c382b3e 100644 --- a/tgbot/misc/states.py +++ b/tgbot/misc/states.py @@ -0,0 +1,8 @@ +from aiogram.dispatcher.filters.state import StatesGroup, State + + +class Configure(StatesGroup): + + AddModGroups = State() + AddUserGroups = State() + DeleteUserGroups = State() \ No newline at end of file From 70433ba9dea958d9b07c4c274e5589b8bcdc0b89 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Thu, 14 Jul 2022 21:51:56 +0300 Subject: [PATCH 06/16] Fix count --- tgbot/Utils/DBWorker.py | 6 +++--- tgbot/filters/count.py | 7 ++++--- tgbot/misc/set_commands.py | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index 6dc1c76..54ce709 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -2,7 +2,7 @@ import aiosqlite -async def db_execute(string, values=None, multiple=False, get=False, get_delete_info=False) -> bool: +async def db_execute(string, values=None, multiple=False, get=False) -> bool: """Функция для выполнения SQL запросов""" db_name = os.getenv('DB_NAME') async with aiosqlite.connect(db_name) as db: @@ -167,8 +167,8 @@ async def check_grant_numbers(group_id): string=f"SELECT COUNT(*) FROM grant_numbers WHERE group_id LIKE '%{group_id}%'", get=True) -async def check_data_from_grant_numbers(group_id): - return await db_execute(string=f'SELECT COUNT(*) FROM grant_numbers WHERE group_id={group_id} LIMIT 1', get=True) +async def get_data_from_grant_numbers(group_id): + return await db_execute(string=f'SELECT numbers FROM grant_numbers WHERE group_id={group_id}', get=True) async def vacuum(): diff --git a/tgbot/filters/count.py b/tgbot/filters/count.py index 11f2b07..cea6603 100644 --- a/tgbot/filters/count.py +++ b/tgbot/filters/count.py @@ -2,7 +2,8 @@ from aiogram.dispatcher.filters import BoundFilter from aiogram.dispatcher.handler import CancelHandler -from tgbot.Utils.DBWorker import get_count_queue, check_data_from_grant_numbers +from Utils.get_numbers import get_grant_numbers +from tgbot.Utils.DBWorker import get_count_queue class IsGrantCount(BoundFilter): @@ -18,7 +19,7 @@ async def check(self, update: types.ChatMemberUpdated): raise CancelHandler() count = await update.chat.get_member_count() count_to_delete = await get_count_queue(update.chat.id) - saved_grant_numbers = await check_data_from_grant_numbers(update.chat.id) - if count_to_delete[0][0] < 3 or saved_grant_numbers[0][0] or not count % config_count: + saved_grant_numbers = await get_grant_numbers(update.chat.id) + if 0 < count_to_delete[0][0] < 3 or (count in saved_grant_numbers) or not count % config_count: return {"count": count} return False diff --git a/tgbot/misc/set_commands.py b/tgbot/misc/set_commands.py index 69bf10d..1b301cc 100644 --- a/tgbot/misc/set_commands.py +++ b/tgbot/misc/set_commands.py @@ -5,5 +5,6 @@ async def set_default_commands(dp): await dp.bot.set_my_commands([ types.BotCommand("start", "Запустить бота"), - types.BotCommand("/configure_groups", "Настроить группы") + types.BotCommand("/configure_groups", "Настроить группы"), + types.BotCommand("/configure_grant_num", "Настроить номера для поздравлений") ]) From 27f079fb397f0f8f07900a948eb33616ae81efff Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Thu, 14 Jul 2022 21:52:17 +0300 Subject: [PATCH 07/16] Fix count --- tgbot/Utils/get_numbers.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tgbot/Utils/get_numbers.py diff --git a/tgbot/Utils/get_numbers.py b/tgbot/Utils/get_numbers.py new file mode 100644 index 0000000..fb5e135 --- /dev/null +++ b/tgbot/Utils/get_numbers.py @@ -0,0 +1,6 @@ +from Utils.DBWorker import get_data_from_grant_numbers + + +async def get_grant_numbers(group_id): + numbers = await get_data_from_grant_numbers(group_id) + return [int(number) for number in numbers[0][0].split(',')] From 0dc498b77106168a51190a2efde7bef427737f75 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Sat, 16 Jul 2022 09:50:59 +0300 Subject: [PATCH 08/16] Fix count --- bot.py | 15 ++++++--- tgbot/Utils/DBWorker.py | 10 ++++-- tgbot/handlers/back_to_main_menu.py | 21 +++++++++++++ tgbot/handlers/cancel.py | 18 +++++++++++ tgbot/handlers/configure_groups.py | 20 ------------ tgbot/handlers/configure_groups_callback.py | 22 +++++++++++++ tgbot/handlers/configure_numbers_callback.py | 21 +++++++++++++ tgbot/handlers/delete_from_groups.py | 3 ++ tgbot/handlers/get_users_groups.py | 3 ++ tgbot/handlers/main_menu.py | 20 ++++++++++++ tgbot/handlers/reset_menu.py | 21 ------------- tgbot/handlers/show_numbers_callback.py | 33 ++++++++++++++++++++ tgbot/keyboards/inline.py | 22 +++++++++++-- tgbot/misc/set_commands.py | 3 +- tgbot/misc/states.py | 2 +- 15 files changed, 181 insertions(+), 53 deletions(-) create mode 100644 tgbot/handlers/back_to_main_menu.py create mode 100644 tgbot/handlers/cancel.py delete mode 100644 tgbot/handlers/configure_groups.py create mode 100644 tgbot/handlers/configure_groups_callback.py create mode 100644 tgbot/handlers/configure_numbers_callback.py create mode 100644 tgbot/handlers/main_menu.py delete mode 100644 tgbot/handlers/reset_menu.py create mode 100644 tgbot/handlers/show_numbers_callback.py diff --git a/bot.py b/bot.py index e239949..d0067d7 100644 --- a/bot.py +++ b/bot.py @@ -9,16 +9,20 @@ from filters.moder_group import IsModerGroup from handlers.add_groups_callback import register_add_groups +from handlers.cancel import register_cancel_menu from handlers.check import register_check_queue -from handlers.configure_groups import register_configure_groups +from handlers.configure_groups_callback import register_configure_groups +from handlers.configure_numbers_callback import register_configure_numbers from handlers.delete_from_groups import register_delete_from_groups from handlers.delete_groups_callback import register_delete_groups_cb from handlers.get_granted import register_get_granted from handlers.get_mod_group import register_get_mod_group from handlers.get_users_groups import register_get_users_group -from handlers.reset_menu import register_reset_menu +from handlers.main_menu import register_main_menu +from handlers.back_to_main_menu import register_back_to_main from handlers.restore import register_restore from handlers.show_groups_callback import register_show_groups +from handlers.show_numbers_callback import register_show_numbers from misc.set_commands import set_default_commands from tgbot.handlers.grant_cancel_callback import register_cancel_grant from tgbot.handlers.grant_callback import register_grant @@ -65,10 +69,13 @@ def register_all_handlers(dp): register_add_groups(dp) register_get_mod_group(dp) register_get_users_group(dp) - register_reset_menu(dp) register_delete_groups_cb(dp) register_delete_from_groups(dp) - + register_main_menu(dp) + register_back_to_main(dp) + register_cancel_menu(dp) + register_configure_numbers(dp) + register_show_numbers(dp) async def main(): diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index 54ce709..0af46f2 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -162,14 +162,18 @@ async def set_data_groups(values): f' VALUES(?, ?);', values=values) -async def check_grant_numbers(group_id): - return await db_execute( - string=f"SELECT COUNT(*) FROM grant_numbers WHERE group_id LIKE '%{group_id}%'", get=True) +# async def check_grant_numbers(group_id): +# return await db_execute( +# string=f"SELECT COUNT(*) FROM grant_numbers WHERE group_id LIKE '%{group_id}%'", get=True) async def get_data_from_grant_numbers(group_id): return await db_execute(string=f'SELECT numbers FROM grant_numbers WHERE group_id={group_id}', get=True) +async def get_numbers(): + return await db_execute(string='SELECT * FROM grant_numbers', get=True) + + async def vacuum(): return await db_execute(string="VACUUM") diff --git a/tgbot/handlers/back_to_main_menu.py b/tgbot/handlers/back_to_main_menu.py new file mode 100644 index 0000000..427c9f4 --- /dev/null +++ b/tgbot/handlers/back_to_main_menu.py @@ -0,0 +1,21 @@ +from contextlib import suppress +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeEdited +from keyboards.inline import get_main_menu_kb + + +async def back_to_main(call: types.CallbackQuery, state: FSMContext): + with suppress(MessageCantBeEdited): + await call.message.edit_text(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=await get_main_menu_kb()) + await state.finish() + + +def register_back_to_main(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(back_to_main, + chat_type=chat_types, + text='back_to_main', + state="*", + is_admin=True) diff --git a/tgbot/handlers/cancel.py b/tgbot/handlers/cancel.py new file mode 100644 index 0000000..d315b2f --- /dev/null +++ b/tgbot/handlers/cancel.py @@ -0,0 +1,18 @@ +from contextlib import suppress +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted + + + +async def cancel_menu(call: types.CallbackQuery): + with suppress(MessageCantBeDeleted): + await call.message.delete() + + +def register_cancel_menu(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(cancel_menu, + chat_type=chat_types, + text='cancel', + is_admin=True) diff --git a/tgbot/handlers/configure_groups.py b/tgbot/handlers/configure_groups.py deleted file mode 100644 index 980823d..0000000 --- a/tgbot/handlers/configure_groups.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List -from aiogram import Dispatcher, types -from aiogram.types import ChatType - -from keyboards.inline import get_conf_groups_kb -from tgbot.Utils.DBWorker import get_data_granted - - -async def configure_groups(message: types.Message): - await message.answer(text='⚙⚙⚙', reply_markup=await get_conf_groups_kb()) - - - -def register_configure_groups(dp: Dispatcher): - chat_types = [ChatType.PRIVATE] - dp.register_message_handler(configure_groups, - chat_type=chat_types, - commands=['configure_groups'], - is_admin=True - ) diff --git a/tgbot/handlers/configure_groups_callback.py b/tgbot/handlers/configure_groups_callback.py new file mode 100644 index 0000000..05b326b --- /dev/null +++ b/tgbot/handlers/configure_groups_callback.py @@ -0,0 +1,22 @@ +from contextlib import suppress + +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeEdited + +from keyboards.inline import get_conf_groups_kb + + +async def configure_groups(call: types.CallbackQuery): + with suppress(MessageCantBeEdited): + await call.message.edit_text(text='⚙ Настройка таблицы соответствия групп ⚙', + reply_markup=await get_conf_groups_kb()) + + +def register_configure_groups(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(configure_groups, + chat_type=chat_types, + text='configure_groups', + is_admin=True + ) diff --git a/tgbot/handlers/configure_numbers_callback.py b/tgbot/handlers/configure_numbers_callback.py new file mode 100644 index 0000000..e25d2dc --- /dev/null +++ b/tgbot/handlers/configure_numbers_callback.py @@ -0,0 +1,21 @@ +from contextlib import suppress + +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeEdited + +from keyboards.inline import get_conf_numbers_kb + + +async def configure_numbers(call: types.CallbackQuery): + with suppress(MessageCantBeEdited): + await call.message.edit_text(text='⚙ Настройка таблицы с поздр. номерами ⚙', reply_markup=await get_conf_numbers_kb()) + + +def register_configure_numbers(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(configure_numbers, + chat_type=chat_types, + text='configure_numbers', + is_admin=True + ) diff --git a/tgbot/handlers/delete_from_groups.py b/tgbot/handlers/delete_from_groups.py index 2408f8a..3b237c9 100644 --- a/tgbot/handlers/delete_from_groups.py +++ b/tgbot/handlers/delete_from_groups.py @@ -5,6 +5,7 @@ from Utils.DBWorker import delete_data_from_groups from Utils.check_message_user_groups import check_users_groups from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from keyboards.inline import get_conf_groups_kb from misc.states import Configure @@ -25,6 +26,8 @@ async def delete_from_groups(message: types.Message, state: FSMContext): else: await message.answer(f'Таких групп нет в таблице') await state.finish() + await message.answer(text='⚙ Настройка таблицы соответствия групп ⚙', + reply_markup=await get_conf_groups_kb()) def register_delete_from_groups(dp: Dispatcher): diff --git a/tgbot/handlers/get_users_groups.py b/tgbot/handlers/get_users_groups.py index 0181f71..71e835a 100644 --- a/tgbot/handlers/get_users_groups.py +++ b/tgbot/handlers/get_users_groups.py @@ -5,6 +5,7 @@ from Utils.check_message_user_groups import check_users_groups from Utils.delete_doubles import delete_doubles_ids from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from keyboards.inline import get_conf_groups_kb from misc.states import Configure from tgbot.Utils.DBWorker import set_data_groups, get_user_ids_from_groups, set_group_ids_grant_numbers @@ -34,6 +35,8 @@ async def get_users_group(message: types.Message, state: FSMContext): await message.answer('Записал') await state.finish() + await message.answer(text='⚙ Настройка таблицы соответствия групп ⚙', + reply_markup=await get_conf_groups_kb()) def register_get_users_group(dp: Dispatcher): diff --git a/tgbot/handlers/main_menu.py b/tgbot/handlers/main_menu.py new file mode 100644 index 0000000..b681cc4 --- /dev/null +++ b/tgbot/handlers/main_menu.py @@ -0,0 +1,20 @@ +from typing import List +from aiogram import Dispatcher, types +from aiogram.types import ChatType + +from keyboards.inline import get_main_menu_kb +from misc.states import Configure +from tgbot.Utils.DBWorker import get_data_granted + + +async def main_menu(message: types.Message): + await message.answer(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=await get_main_menu_kb()) + + +def register_main_menu(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(main_menu, + chat_type=chat_types, + commands=['configure'], + is_admin=True + ) diff --git a/tgbot/handlers/reset_menu.py b/tgbot/handlers/reset_menu.py deleted file mode 100644 index 4d492c0..0000000 --- a/tgbot/handlers/reset_menu.py +++ /dev/null @@ -1,21 +0,0 @@ -from contextlib import suppress -from aiogram import Dispatcher, types -from aiogram.dispatcher import FSMContext -from aiogram.types import ChatType -from aiogram.utils.exceptions import MessageCantBeDeleted - - -async def reset_menu(call: types.CallbackQuery, state: FSMContext): - with suppress(MessageCantBeDeleted): - await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) - - await state.finish() - - -def register_reset_menu(dp: Dispatcher): - chat_types = [ChatType.PRIVATE] - dp.register_callback_query_handler(reset_menu, - chat_type=chat_types, - text='reset', - state="*", - is_admin=True) diff --git a/tgbot/handlers/show_numbers_callback.py b/tgbot/handlers/show_numbers_callback.py new file mode 100644 index 0000000..546f924 --- /dev/null +++ b/tgbot/handlers/show_numbers_callback.py @@ -0,0 +1,33 @@ +from contextlib import suppress + +from aiogram import md +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted + +from tgbot.Utils.DBWorker import get_numbers + + +async def show_numbers(call: types.CallbackQuery): + groups = await get_numbers() + text = md.hunderline('ID | ID Группы | Номера для поздравления\n') + + with suppress(MessageCantBeDeleted): + await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + if groups: + for group in groups: + text += md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') + text += ' ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\n' + await call.message.answer(text=text) + else: + await call.message.answer(text='Таблица еще пуста') + + +def register_show_numbers(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(show_numbers, + chat_type=chat_types, + text='show_numbers', + state="*", + is_admin=True) \ No newline at end of file diff --git a/tgbot/keyboards/inline.py b/tgbot/keyboards/inline.py index 2fb1933..8acf58e 100644 --- a/tgbot/keyboards/inline.py +++ b/tgbot/keyboards/inline.py @@ -1,5 +1,6 @@ from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + async def get_gran_kb(uid): grant_btn = InlineKeyboardButton('Поздравить!', callback_data=f'grant|{uid}') cancel_btn = InlineKeyboardButton('Отмена', callback_data=f'can|{uid}') @@ -11,6 +12,23 @@ async def get_conf_groups_kb(): show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_groups') add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_groups') delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_groups') - reset_btn = InlineKeyboardButton('Отмена', callback_data='reset') - conf_groups_kb = InlineKeyboardMarkup(row_width=1).add(show_btn, add_btn, delete_btn, reset_btn) + back_to_main_btn = InlineKeyboardButton('Главное меню', callback_data='back_to_main') + conf_groups_kb = InlineKeyboardMarkup(row_width=1).add(show_btn, add_btn, delete_btn, back_to_main_btn) return conf_groups_kb + + +async def get_main_menu_kb(): + config_groups_btn = InlineKeyboardButton('Настройка таблицы групп', callback_data='configure_groups') + config_numbers_btn = InlineKeyboardButton('Настройка таблицы номеров', callback_data='configure_numbers') + cancel_btn = InlineKeyboardButton('Отмена', callback_data='cancel') + main_kb = InlineKeyboardMarkup(row_width=1).add(config_groups_btn, config_numbers_btn, cancel_btn) + return main_kb + + +async def get_conf_numbers_kb(): + show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_numbers') + add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_numbers') + delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_numbers') + back_to_main_btn = InlineKeyboardButton('Главное меню', callback_data='back_to_main') + conf_numbers_kb = InlineKeyboardMarkup(row_width=1).add(show_btn, add_btn, delete_btn, back_to_main_btn) + return conf_numbers_kb diff --git a/tgbot/misc/set_commands.py b/tgbot/misc/set_commands.py index 1b301cc..5a793ac 100644 --- a/tgbot/misc/set_commands.py +++ b/tgbot/misc/set_commands.py @@ -5,6 +5,5 @@ async def set_default_commands(dp): await dp.bot.set_my_commands([ types.BotCommand("start", "Запустить бота"), - types.BotCommand("/configure_groups", "Настроить группы"), - types.BotCommand("/configure_grant_num", "Настроить номера для поздравлений") + types.BotCommand("/configure", "Конфигурация"), ]) diff --git a/tgbot/misc/states.py b/tgbot/misc/states.py index c382b3e..8ac03ea 100644 --- a/tgbot/misc/states.py +++ b/tgbot/misc/states.py @@ -5,4 +5,4 @@ class Configure(StatesGroup): AddModGroups = State() AddUserGroups = State() - DeleteUserGroups = State() \ No newline at end of file + DeleteUserGroups = State() From 48170a2a77f259a350b83116204736b160a88ef5 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Sat, 16 Jul 2022 19:26:22 +0300 Subject: [PATCH 09/16] Finish admins --- bot.py | 10 +++++ tgbot/Utils/DBWorker.py | 9 ++++ tgbot/Utils/delete_doubles.py | 9 +++- tgbot/handlers/add_numbers_callback.py | 21 ++++++++++ tgbot/handlers/configure_numbers_callback.py | 3 +- tgbot/handlers/delete_from_groups.py | 4 +- tgbot/handlers/delete_from_numbers.py | 38 +++++++++++++++++ tgbot/handlers/delete_groups_callback.py | 2 +- tgbot/handlers/delete_numbers_callback.py | 25 +++++++++++ tgbot/handlers/get_numbers.py | 44 ++++++++++++++++++++ tgbot/handlers/get_numbers_group.py | 30 +++++++++++++ tgbot/handlers/grant_callback.py | 2 +- tgbot/misc/states.py | 3 ++ 13 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 tgbot/handlers/add_numbers_callback.py create mode 100644 tgbot/handlers/delete_from_numbers.py create mode 100644 tgbot/handlers/delete_numbers_callback.py create mode 100644 tgbot/handlers/get_numbers.py create mode 100644 tgbot/handlers/get_numbers_group.py diff --git a/bot.py b/bot.py index d0067d7..e37c4ee 100644 --- a/bot.py +++ b/bot.py @@ -9,14 +9,19 @@ from filters.moder_group import IsModerGroup from handlers.add_groups_callback import register_add_groups +from handlers.add_numbers_callback import register_add_numbers from handlers.cancel import register_cancel_menu from handlers.check import register_check_queue from handlers.configure_groups_callback import register_configure_groups from handlers.configure_numbers_callback import register_configure_numbers from handlers.delete_from_groups import register_delete_from_groups +from handlers.delete_from_numbers import register_delete_numbers from handlers.delete_groups_callback import register_delete_groups_cb +from handlers.delete_numbers_callback import register_delete_numbers_cb from handlers.get_granted import register_get_granted from handlers.get_mod_group import register_get_mod_group +from handlers.get_numbers import register_get_grant_numbers +from handlers.get_numbers_group import register_numbers_group from handlers.get_users_groups import register_get_users_group from handlers.main_menu import register_main_menu from handlers.back_to_main_menu import register_back_to_main @@ -76,6 +81,11 @@ def register_all_handlers(dp): register_cancel_menu(dp) register_configure_numbers(dp) register_show_numbers(dp) + register_add_numbers(dp) + register_numbers_group(dp) + register_get_grant_numbers(dp) + register_delete_numbers_cb(dp) + register_delete_numbers(dp) async def main(): diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index 0af46f2..faa591b 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -171,6 +171,15 @@ async def get_data_from_grant_numbers(group_id): return await db_execute(string=f'SELECT numbers FROM grant_numbers WHERE group_id={group_id}', get=True) +async def set_data_numbers(values): + return await db_execute(string=f'INSERT OR REPLACE INTO grant_numbers(group_id, numbers)' + f' VALUES(?, ?);', values=values) + + +async def delete_data_from_grant_numbers(ids): + return await db_execute(string=f'DELETE FROM grant_numbers WHERE id=?', values=ids, multiple=True) + + async def get_numbers(): return await db_execute(string='SELECT * FROM grant_numbers', get=True) diff --git a/tgbot/Utils/delete_doubles.py b/tgbot/Utils/delete_doubles.py index 620ec4f..3664923 100644 --- a/tgbot/Utils/delete_doubles.py +++ b/tgbot/Utils/delete_doubles.py @@ -1,2 +1,7 @@ -async def delete_doubles_ids(message: str): - return ','.join(set(message.replace(' ', '').split(','))) +async def delete_doubles_ids(message: str, sort=False): + without_doubles = set(message.replace(' ', '').split(',')) + if sort: + for_sorts = map(int, without_doubles) + return ','.join(map(str, sorted(for_sorts))) + else: + return ','.join(without_doubles) diff --git a/tgbot/handlers/add_numbers_callback.py b/tgbot/handlers/add_numbers_callback.py new file mode 100644 index 0000000..4f50046 --- /dev/null +++ b/tgbot/handlers/add_numbers_callback.py @@ -0,0 +1,21 @@ +from contextlib import suppress +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted +from misc.states import Configure + + +async def add_numbers(call: types.CallbackQuery): + with suppress(MessageCantBeDeleted): + await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + await call.message.answer(text='Введите id группы, целое число (/reset для сброса)') + await Configure.AddNumbersGroup.set() + + +def register_add_numbers(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(add_numbers, + chat_type=chat_types, + text='add_numbers', + is_admin=True) diff --git a/tgbot/handlers/configure_numbers_callback.py b/tgbot/handlers/configure_numbers_callback.py index e25d2dc..dbb098f 100644 --- a/tgbot/handlers/configure_numbers_callback.py +++ b/tgbot/handlers/configure_numbers_callback.py @@ -9,7 +9,8 @@ async def configure_numbers(call: types.CallbackQuery): with suppress(MessageCantBeEdited): - await call.message.edit_text(text='⚙ Настройка таблицы с поздр. номерами ⚙', reply_markup=await get_conf_numbers_kb()) + await call.message.edit_text(text='⚙ Настройка таблицы с поздр. номерами ⚙', + reply_markup=await get_conf_numbers_kb()) def register_configure_numbers(dp: Dispatcher): diff --git a/tgbot/handlers/delete_from_groups.py b/tgbot/handlers/delete_from_groups.py index 3b237c9..fb65349 100644 --- a/tgbot/handlers/delete_from_groups.py +++ b/tgbot/handlers/delete_from_groups.py @@ -16,7 +16,7 @@ async def delete_from_groups(message: types.Message, state: FSMContext): return group_id = await check_users_groups(message.text) if not group_id: - await message.answer('Введите ids групп модераторов для удаления записей из базы, целые числа, ' + await message.answer('Введите IDs групп модераторов для удаления записей из базы, целые числа, ' 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') return ids = await get_ids_for_multiple_record(message.text) @@ -24,7 +24,7 @@ async def delete_from_groups(message: types.Message, state: FSMContext): if deleted_records: await message.answer(f'Удалил {deleted_records} записи(-ей)') else: - await message.answer(f'Таких групп нет в таблице') + await message.answer(f'Таких строк нет в таблице') await state.finish() await message.answer(text='⚙ Настройка таблицы соответствия групп ⚙', reply_markup=await get_conf_groups_kb()) diff --git a/tgbot/handlers/delete_from_numbers.py b/tgbot/handlers/delete_from_numbers.py new file mode 100644 index 0000000..a7fa4f7 --- /dev/null +++ b/tgbot/handlers/delete_from_numbers.py @@ -0,0 +1,38 @@ +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType + +from Utils.DBWorker import delete_data_from_groups, delete_data_from_grant_numbers +from Utils.check_message_user_groups import check_users_groups +from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from keyboards.inline import get_conf_numbers_kb + +from misc.states import Configure + + +async def delete_numbers(message: types.Message, state: FSMContext): + if message.text == '/reset': + await state.finish() + return + group_id = await check_users_groups(message.text) + if not group_id: + await message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' + 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') + return + ids = await get_ids_for_multiple_record(message.text) + deleted_records = await delete_data_from_grant_numbers(ids) + if deleted_records: + await message.answer(f'Удалил {deleted_records} записи(-ей)') + else: + await message.answer(f'Таких строк нет в таблице') + await state.finish() + await message.answer(text='⚙ Настройка таблицы с поздр. номерами ⚙', + reply_markup=await get_conf_numbers_kb()) + + +def register_delete_numbers(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(delete_numbers, + chat_type=chat_types, + state=Configure.DeleteNumbers, + is_admin=True) diff --git a/tgbot/handlers/delete_groups_callback.py b/tgbot/handlers/delete_groups_callback.py index 5c2a116..251731c 100644 --- a/tgbot/handlers/delete_groups_callback.py +++ b/tgbot/handlers/delete_groups_callback.py @@ -12,7 +12,7 @@ async def delete_groups(call: types.CallbackQuery): with suppress(MessageCantBeDeleted): await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) - await call.message.answer('Введите ids групп модераторов для удаления записей из базы, целые числа, ' + await call.message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') await Configure.DeleteUserGroups.set() diff --git a/tgbot/handlers/delete_numbers_callback.py b/tgbot/handlers/delete_numbers_callback.py new file mode 100644 index 0000000..e7c1694 --- /dev/null +++ b/tgbot/handlers/delete_numbers_callback.py @@ -0,0 +1,25 @@ +from contextlib import suppress + +from aiogram import md +from aiogram import Dispatcher, types +from aiogram.types import ChatType +from aiogram.utils.exceptions import MessageCantBeDeleted + +from misc.states import Configure + + +async def delete_numbers(call: types.CallbackQuery): + with suppress(MessageCantBeDeleted): + await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + + await call.message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' + 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') + await Configure.DeleteNumbers.set() + + +def register_delete_numbers_cb(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_callback_query_handler(delete_numbers, + chat_type=chat_types, + text='delete_numbers', + is_admin=True) diff --git a/tgbot/handlers/get_numbers.py b/tgbot/handlers/get_numbers.py new file mode 100644 index 0000000..be2ef25 --- /dev/null +++ b/tgbot/handlers/get_numbers.py @@ -0,0 +1,44 @@ +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType + +from Utils.check_message_user_groups import check_users_groups +from Utils.delete_doubles import delete_doubles_ids +from keyboards.inline import get_conf_numbers_kb +from misc.states import Configure +from tgbot.Utils.DBWorker import get_data_from_grant_numbers, set_data_numbers + + +async def get_grant_numbers(message: types.Message, state: FSMContext): + if message.text == '/reset': + await state.finish() + return + group_ids_check = await check_users_groups(message.text) + + if not group_ids_check: + await message.answer('Введите номера для поздравления, несколько номеров' + ' необходимо разделить через запятую (/reset для сброса)') + return + data = await state.get_data() + id_group = data.get('id_group') + + existed = await get_data_from_grant_numbers(group_id=id_group) + numbers = message.text + if existed: + numbers += f',{existed[0][0]}' + text_message = await delete_doubles_ids(message=numbers, sort=True) + + await set_data_numbers(values=(id_group, text_message,)) + + await message.answer('Записал') + await state.finish() + await message.answer(text='⚙ Настройка таблицы с поздр. номерами ⚙', + reply_markup=await get_conf_numbers_kb()) + + +def register_get_grant_numbers(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(get_grant_numbers, + chat_type=chat_types, + state=Configure.AddNumbers, + is_admin=True) diff --git a/tgbot/handlers/get_numbers_group.py b/tgbot/handlers/get_numbers_group.py new file mode 100644 index 0000000..20cdabe --- /dev/null +++ b/tgbot/handlers/get_numbers_group.py @@ -0,0 +1,30 @@ +from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext +from aiogram.types import ChatType + +from Utils.check_number import check_number_in_message + +from misc.states import Configure + + +async def get_numbers_group(message: types.Message, state: FSMContext): + if message.text == '/reset': + await state.finish() + return + group_id = await check_number_in_message(message.text) + if not group_id: + await message.answer('Введите id группы, целое число (/reset для сброса)') + return + + await state.update_data(id_group=group_id) + await message.answer('Введите номера для поздравления, несколько номеров' + ' необходимо разделить через запятую (/reset для сброса)') + await Configure.AddNumbers.set() + + +def register_numbers_group(dp: Dispatcher): + chat_types = [ChatType.PRIVATE] + dp.register_message_handler(get_numbers_group, + chat_type=chat_types, + state=Configure.AddNumbersGroup, + is_admin=True) diff --git a/tgbot/handlers/grant_callback.py b/tgbot/handlers/grant_callback.py index 7e9b688..2370460 100644 --- a/tgbot/handlers/grant_callback.py +++ b/tgbot/handlers/grant_callback.py @@ -29,8 +29,8 @@ async def grant_user(call: types.CallbackQuery): chat_member = await call.bot.get_chat_member(group_id_users, user_id) if not chat_member: - await call.answer(text="Такого пользователя уже нет в группе", show_alert=True) await call.bot.edit_message_reply_markup(chat_id=call.message.chat.id, message_id=message_id, reply_markup=None) + await call.answer(text="Такого пользователя уже нет в группе", show_alert=True) raise CancelHandler() text = f'🎉 Поздравляю, {user}, как же удачно попали в нужное место и в нужное время!\n' \ diff --git a/tgbot/misc/states.py b/tgbot/misc/states.py index 8ac03ea..08a0aec 100644 --- a/tgbot/misc/states.py +++ b/tgbot/misc/states.py @@ -3,6 +3,9 @@ class Configure(StatesGroup): + AddNumbersGroup = State() + AddNumbers = State() + DeleteNumbers = State() AddModGroups = State() AddUserGroups = State() DeleteUserGroups = State() From b7cdcf9575619a874a8eb5e97197d6ae75dcbcc9 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Sat, 16 Jul 2022 20:38:31 +0300 Subject: [PATCH 10/16] Finish admins --- bot.py | 71 ++++++++++--------- .../{ => admin}/add_groups_callback.py | 0 .../{ => admin}/add_numbers_callback.py | 0 tgbot/handlers/{ => admin}/admin.py | 0 .../handlers/{ => admin}/back_to_main_menu.py | 0 tgbot/handlers/{ => admin}/cancel.py | 0 .../{ => admin}/configure_groups_callback.py | 0 .../{ => admin}/configure_numbers_callback.py | 0 .../{ => admin}/delete_from_groups.py | 3 +- .../{ => admin}/delete_from_numbers.py | 3 +- .../{ => admin}/delete_groups_callback.py | 0 .../{ => admin}/delete_numbers_callback.py | 0 tgbot/handlers/{ => admin}/get_mod_group.py | 0 tgbot/handlers/{ => admin}/get_numbers.py | 0 .../handlers/{ => admin}/get_numbers_group.py | 0 .../handlers/{ => admin}/get_users_groups.py | 0 tgbot/handlers/{ => admin}/main_menu.py | 0 .../{ => admin}/show_groups_callback.py | 5 +- .../{ => admin}/show_numbers_callback.py | 7 +- tgbot/handlers/{ => admin}/user.py | 0 tgbot/handlers/groups/__init__.py | 0 tgbot/handlers/{ => groups}/catch_update.py | 0 tgbot/handlers/{ => groups}/check.py | 0 tgbot/handlers/{ => groups}/echo.py | 0 tgbot/handlers/{ => groups}/get_granted.py | 0 tgbot/handlers/{ => groups}/grant_callback.py | 1 - .../{ => groups}/grant_cancel_callback.py | 0 tgbot/handlers/{ => groups}/restore.py | 0 28 files changed, 48 insertions(+), 42 deletions(-) rename tgbot/handlers/{ => admin}/add_groups_callback.py (100%) rename tgbot/handlers/{ => admin}/add_numbers_callback.py (100%) rename tgbot/handlers/{ => admin}/admin.py (100%) rename tgbot/handlers/{ => admin}/back_to_main_menu.py (100%) rename tgbot/handlers/{ => admin}/cancel.py (100%) rename tgbot/handlers/{ => admin}/configure_groups_callback.py (100%) rename tgbot/handlers/{ => admin}/configure_numbers_callback.py (100%) rename tgbot/handlers/{ => admin}/delete_from_groups.py (95%) rename tgbot/handlers/{ => admin}/delete_from_numbers.py (94%) rename tgbot/handlers/{ => admin}/delete_groups_callback.py (100%) rename tgbot/handlers/{ => admin}/delete_numbers_callback.py (100%) rename tgbot/handlers/{ => admin}/get_mod_group.py (100%) rename tgbot/handlers/{ => admin}/get_numbers.py (100%) rename tgbot/handlers/{ => admin}/get_numbers_group.py (100%) rename tgbot/handlers/{ => admin}/get_users_groups.py (100%) rename tgbot/handlers/{ => admin}/main_menu.py (100%) rename tgbot/handlers/{ => admin}/show_groups_callback.py (81%) rename tgbot/handlers/{ => admin}/show_numbers_callback.py (74%) rename tgbot/handlers/{ => admin}/user.py (100%) create mode 100644 tgbot/handlers/groups/__init__.py rename tgbot/handlers/{ => groups}/catch_update.py (100%) rename tgbot/handlers/{ => groups}/check.py (100%) rename tgbot/handlers/{ => groups}/echo.py (100%) rename tgbot/handlers/{ => groups}/get_granted.py (100%) rename tgbot/handlers/{ => groups}/grant_callback.py (99%) rename tgbot/handlers/{ => groups}/grant_cancel_callback.py (100%) rename tgbot/handlers/{ => groups}/restore.py (100%) diff --git a/bot.py b/bot.py index e37c4ee..e0566e0 100644 --- a/bot.py +++ b/bot.py @@ -7,41 +7,44 @@ from aiogram.contrib.middlewares.logging import LoggingMiddleware from aiogram.types import AllowedUpdates -from filters.moder_group import IsModerGroup -from handlers.add_groups_callback import register_add_groups -from handlers.add_numbers_callback import register_add_numbers -from handlers.cancel import register_cancel_menu -from handlers.check import register_check_queue -from handlers.configure_groups_callback import register_configure_groups -from handlers.configure_numbers_callback import register_configure_numbers -from handlers.delete_from_groups import register_delete_from_groups -from handlers.delete_from_numbers import register_delete_numbers -from handlers.delete_groups_callback import register_delete_groups_cb -from handlers.delete_numbers_callback import register_delete_numbers_cb -from handlers.get_granted import register_get_granted -from handlers.get_mod_group import register_get_mod_group -from handlers.get_numbers import register_get_grant_numbers -from handlers.get_numbers_group import register_numbers_group -from handlers.get_users_groups import register_get_users_group -from handlers.main_menu import register_main_menu -from handlers.back_to_main_menu import register_back_to_main -from handlers.restore import register_restore -from handlers.show_groups_callback import register_show_groups -from handlers.show_numbers_callback import register_show_numbers +from handlers.admin.add_groups_callback import register_add_groups +from handlers.admin.add_numbers_callback import register_add_numbers +from handlers.admin.cancel import register_cancel_menu +from handlers.admin.configure_groups_callback import register_configure_groups +from handlers.admin.configure_numbers_callback import register_configure_numbers +from handlers.admin.delete_from_groups import register_delete_from_groups +from handlers.admin.delete_from_numbers import register_delete_numbers +from handlers.admin.delete_groups_callback import register_delete_groups_cb +from handlers.admin.delete_numbers_callback import register_delete_numbers_cb +from handlers.admin.get_mod_group import register_get_mod_group +from handlers.admin.get_numbers import register_get_grant_numbers +from handlers.admin.get_numbers_group import register_numbers_group +from handlers.admin.get_users_groups import register_get_users_group +from handlers.admin.main_menu import register_main_menu +from handlers.admin.back_to_main_menu import register_back_to_main +from handlers.admin.show_groups_callback import register_show_groups +from handlers.admin.show_numbers_callback import register_show_numbers +from handlers.admin.user import register_user +from handlers.admin.admin import register_admin + +from handlers.groups.check import register_check_queue +from handlers.groups.get_granted import register_get_granted +from handlers.groups.restore import register_restore +from handlers.groups.grant_cancel_callback import register_cancel_grant +from handlers.groups.grant_callback import register_grant +from handlers.groups.catch_update import register_catch +from handlers.groups.echo import register_echo + from misc.set_commands import set_default_commands -from tgbot.handlers.grant_cancel_callback import register_cancel_grant -from tgbot.handlers.grant_callback import register_grant -from tgbot.filters.granted import IsNotGranted -from tgbot.filters.count import IsGrantCount -from tgbot.filters.user_group import IsUserGroup -from tgbot.Utils.DBWorker import create_tables -from tgbot.config import load_config -from tgbot.filters.admin import AdminFilter -from tgbot.filters.group_join import IsGroupJoin -from tgbot.handlers.admin import register_admin -from tgbot.handlers.catch_update import register_catch -from tgbot.handlers.echo import register_echo -from tgbot.handlers.user import register_user + +from filters.moder_group import IsModerGroup +from filters.granted import IsNotGranted +from filters.count import IsGrantCount +from filters.user_group import IsUserGroup +from Utils.DBWorker import create_tables +from config import load_config +from filters.admin import AdminFilter +from filters.group_join import IsGroupJoin logger = logging.getLogger(__name__) diff --git a/tgbot/handlers/add_groups_callback.py b/tgbot/handlers/admin/add_groups_callback.py similarity index 100% rename from tgbot/handlers/add_groups_callback.py rename to tgbot/handlers/admin/add_groups_callback.py diff --git a/tgbot/handlers/add_numbers_callback.py b/tgbot/handlers/admin/add_numbers_callback.py similarity index 100% rename from tgbot/handlers/add_numbers_callback.py rename to tgbot/handlers/admin/add_numbers_callback.py diff --git a/tgbot/handlers/admin.py b/tgbot/handlers/admin/admin.py similarity index 100% rename from tgbot/handlers/admin.py rename to tgbot/handlers/admin/admin.py diff --git a/tgbot/handlers/back_to_main_menu.py b/tgbot/handlers/admin/back_to_main_menu.py similarity index 100% rename from tgbot/handlers/back_to_main_menu.py rename to tgbot/handlers/admin/back_to_main_menu.py diff --git a/tgbot/handlers/cancel.py b/tgbot/handlers/admin/cancel.py similarity index 100% rename from tgbot/handlers/cancel.py rename to tgbot/handlers/admin/cancel.py diff --git a/tgbot/handlers/configure_groups_callback.py b/tgbot/handlers/admin/configure_groups_callback.py similarity index 100% rename from tgbot/handlers/configure_groups_callback.py rename to tgbot/handlers/admin/configure_groups_callback.py diff --git a/tgbot/handlers/configure_numbers_callback.py b/tgbot/handlers/admin/configure_numbers_callback.py similarity index 100% rename from tgbot/handlers/configure_numbers_callback.py rename to tgbot/handlers/admin/configure_numbers_callback.py diff --git a/tgbot/handlers/delete_from_groups.py b/tgbot/handlers/admin/delete_from_groups.py similarity index 95% rename from tgbot/handlers/delete_from_groups.py rename to tgbot/handlers/admin/delete_from_groups.py index fb65349..cc97616 100644 --- a/tgbot/handlers/delete_from_groups.py +++ b/tgbot/handlers/admin/delete_from_groups.py @@ -2,7 +2,7 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.DBWorker import delete_data_from_groups +from Utils.DBWorker import delete_data_from_groups, vacuum from Utils.check_message_user_groups import check_users_groups from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record from keyboards.inline import get_conf_groups_kb @@ -23,6 +23,7 @@ async def delete_from_groups(message: types.Message, state: FSMContext): deleted_records = await delete_data_from_groups(ids) if deleted_records: await message.answer(f'Удалил {deleted_records} записи(-ей)') + await vacuum() else: await message.answer(f'Таких строк нет в таблице') await state.finish() diff --git a/tgbot/handlers/delete_from_numbers.py b/tgbot/handlers/admin/delete_from_numbers.py similarity index 94% rename from tgbot/handlers/delete_from_numbers.py rename to tgbot/handlers/admin/delete_from_numbers.py index a7fa4f7..9c9565d 100644 --- a/tgbot/handlers/delete_from_numbers.py +++ b/tgbot/handlers/admin/delete_from_numbers.py @@ -2,7 +2,7 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.DBWorker import delete_data_from_groups, delete_data_from_grant_numbers +from Utils.DBWorker import delete_data_from_grant_numbers, vacuum from Utils.check_message_user_groups import check_users_groups from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record from keyboards.inline import get_conf_numbers_kb @@ -23,6 +23,7 @@ async def delete_numbers(message: types.Message, state: FSMContext): deleted_records = await delete_data_from_grant_numbers(ids) if deleted_records: await message.answer(f'Удалил {deleted_records} записи(-ей)') + await vacuum() else: await message.answer(f'Таких строк нет в таблице') await state.finish() diff --git a/tgbot/handlers/delete_groups_callback.py b/tgbot/handlers/admin/delete_groups_callback.py similarity index 100% rename from tgbot/handlers/delete_groups_callback.py rename to tgbot/handlers/admin/delete_groups_callback.py diff --git a/tgbot/handlers/delete_numbers_callback.py b/tgbot/handlers/admin/delete_numbers_callback.py similarity index 100% rename from tgbot/handlers/delete_numbers_callback.py rename to tgbot/handlers/admin/delete_numbers_callback.py diff --git a/tgbot/handlers/get_mod_group.py b/tgbot/handlers/admin/get_mod_group.py similarity index 100% rename from tgbot/handlers/get_mod_group.py rename to tgbot/handlers/admin/get_mod_group.py diff --git a/tgbot/handlers/get_numbers.py b/tgbot/handlers/admin/get_numbers.py similarity index 100% rename from tgbot/handlers/get_numbers.py rename to tgbot/handlers/admin/get_numbers.py diff --git a/tgbot/handlers/get_numbers_group.py b/tgbot/handlers/admin/get_numbers_group.py similarity index 100% rename from tgbot/handlers/get_numbers_group.py rename to tgbot/handlers/admin/get_numbers_group.py diff --git a/tgbot/handlers/get_users_groups.py b/tgbot/handlers/admin/get_users_groups.py similarity index 100% rename from tgbot/handlers/get_users_groups.py rename to tgbot/handlers/admin/get_users_groups.py diff --git a/tgbot/handlers/main_menu.py b/tgbot/handlers/admin/main_menu.py similarity index 100% rename from tgbot/handlers/main_menu.py rename to tgbot/handlers/admin/main_menu.py diff --git a/tgbot/handlers/show_groups_callback.py b/tgbot/handlers/admin/show_groups_callback.py similarity index 81% rename from tgbot/handlers/show_groups_callback.py rename to tgbot/handlers/admin/show_groups_callback.py index 405213c..f6b1588 100644 --- a/tgbot/handlers/show_groups_callback.py +++ b/tgbot/handlers/admin/show_groups_callback.py @@ -17,8 +17,9 @@ async def show_groups(call: types.CallbackQuery): if groups: for group in groups: - text += md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') - text += ' ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\n' + string = md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') + text += string + text += f'{"‾" * (len(string) // 2 + 11)}\n' await call.message.answer(text=text) else: await call.message.answer(text='Таблица еще пуста') diff --git a/tgbot/handlers/show_numbers_callback.py b/tgbot/handlers/admin/show_numbers_callback.py similarity index 74% rename from tgbot/handlers/show_numbers_callback.py rename to tgbot/handlers/admin/show_numbers_callback.py index 546f924..c12e809 100644 --- a/tgbot/handlers/show_numbers_callback.py +++ b/tgbot/handlers/admin/show_numbers_callback.py @@ -10,15 +10,16 @@ async def show_numbers(call: types.CallbackQuery): groups = await get_numbers() - text = md.hunderline('ID | ID Группы | Номера для поздравления\n') + text = md.hunderline('ID |ID Группы|Номера для поздравления\n') with suppress(MessageCantBeDeleted): await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) if groups: for group in groups: - text += md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') - text += ' ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\n' + string = md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') + text += string + text += f'{"‾" * (len(string) // 2 + 5)}\n' await call.message.answer(text=text) else: await call.message.answer(text='Таблица еще пуста') diff --git a/tgbot/handlers/user.py b/tgbot/handlers/admin/user.py similarity index 100% rename from tgbot/handlers/user.py rename to tgbot/handlers/admin/user.py diff --git a/tgbot/handlers/groups/__init__.py b/tgbot/handlers/groups/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/handlers/catch_update.py b/tgbot/handlers/groups/catch_update.py similarity index 100% rename from tgbot/handlers/catch_update.py rename to tgbot/handlers/groups/catch_update.py diff --git a/tgbot/handlers/check.py b/tgbot/handlers/groups/check.py similarity index 100% rename from tgbot/handlers/check.py rename to tgbot/handlers/groups/check.py diff --git a/tgbot/handlers/echo.py b/tgbot/handlers/groups/echo.py similarity index 100% rename from tgbot/handlers/echo.py rename to tgbot/handlers/groups/echo.py diff --git a/tgbot/handlers/get_granted.py b/tgbot/handlers/groups/get_granted.py similarity index 100% rename from tgbot/handlers/get_granted.py rename to tgbot/handlers/groups/get_granted.py diff --git a/tgbot/handlers/grant_callback.py b/tgbot/handlers/groups/grant_callback.py similarity index 99% rename from tgbot/handlers/grant_callback.py rename to tgbot/handlers/groups/grant_callback.py index 2370460..8714a36 100644 --- a/tgbot/handlers/grant_callback.py +++ b/tgbot/handlers/groups/grant_callback.py @@ -58,7 +58,6 @@ async def grant_user(call: types.CallbackQuery): granted.append((message[2], message[3], message[5], message[6], message[4], '', message[7], message[8], '', message[10])) - await delete_from_queue(group_id_users) await vacuum() diff --git a/tgbot/handlers/grant_cancel_callback.py b/tgbot/handlers/groups/grant_cancel_callback.py similarity index 100% rename from tgbot/handlers/grant_cancel_callback.py rename to tgbot/handlers/groups/grant_cancel_callback.py diff --git a/tgbot/handlers/restore.py b/tgbot/handlers/groups/restore.py similarity index 100% rename from tgbot/handlers/restore.py rename to tgbot/handlers/groups/restore.py From 57412548feddc3ea4904b6a58088893d7597577f Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Mon, 18 Jul 2022 13:40:59 +0300 Subject: [PATCH 11/16] Full functions --- bot.py | 2 ++ tgbot/Utils/DBWorker.py | 11 +++---- tgbot/Utils/check_message_user_groups.py | 6 ++-- tgbot/Utils/get_numbers.py | 2 ++ tgbot/Utils/get_user_link.py | 3 +- tgbot/filters/count.py | 1 - tgbot/filters/granted.py | 5 ++-- tgbot/filters/moder_group.py | 1 - tgbot/filters/user_group.py | 1 - tgbot/handlers/admin/__init__.py | 0 tgbot/handlers/admin/back_to_main_menu.py | 2 +- .../admin/configure_groups_callback.py | 2 +- .../admin/configure_numbers_callback.py | 2 +- tgbot/handlers/admin/delete_from_groups.py | 2 +- tgbot/handlers/admin/delete_from_numbers.py | 2 +- tgbot/handlers/admin/get_numbers.py | 2 +- tgbot/handlers/admin/get_users_groups.py | 2 +- tgbot/handlers/admin/main_menu.py | 2 +- tgbot/handlers/admin/show_groups_callback.py | 6 ++-- tgbot/handlers/admin/show_numbers_callback.py | 6 ++-- tgbot/handlers/groups/catch_update.py | 7 +++-- tgbot/handlers/groups/echo.py | 2 ++ tgbot/handlers/groups/get_granted.py | 21 +++++++------ tgbot/handlers/groups/grant_callback.py | 13 ++++---- .../handlers/groups/grant_cancel_callback.py | 3 +- .../handlers/groups/show_granted_callback.py | 22 ++++++++++++++ .../groups/show_granted_cancel_callback.py | 15 ++++++++++ tgbot/keyboards/inline.py | 30 ++++++++++++++++--- tgbot/misc/grant_text.py | 5 ++++ tgbot/misc/show_granted.py | 10 +++++++ tgbot/misc/states.py | 1 - 31 files changed, 132 insertions(+), 57 deletions(-) create mode 100644 tgbot/handlers/admin/__init__.py create mode 100644 tgbot/handlers/groups/show_granted_callback.py create mode 100644 tgbot/handlers/groups/show_granted_cancel_callback.py create mode 100644 tgbot/misc/grant_text.py create mode 100644 tgbot/misc/show_granted.py diff --git a/bot.py b/bot.py index e0566e0..501315e 100644 --- a/bot.py +++ b/bot.py @@ -34,6 +34,7 @@ from handlers.groups.grant_callback import register_grant from handlers.groups.catch_update import register_catch from handlers.groups.echo import register_echo +from handlers.groups.show_granted_callback import register_show_granted_cb from misc.set_commands import set_default_commands @@ -89,6 +90,7 @@ def register_all_handlers(dp): register_get_grant_numbers(dp) register_delete_numbers_cb(dp) register_delete_numbers(dp) + register_show_granted_cb(dp) async def main(): diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index faa591b..db9e4e4 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -115,6 +115,12 @@ async def get_data_granted(group_id_moder): get=True) +async def get_data_granted_for_kb(group_id_users): + return await db_execute( + string=f'SELECT * FROM granted WHERE group_id_users={group_id_users} ORDER BY datetime_update', + get=True) + + async def get_count_queue(group_id): return await db_execute(string=f"SELECT COUNT(*) FROM queue WHERE group_id_users={group_id}", get=True) @@ -162,11 +168,6 @@ async def set_data_groups(values): f' VALUES(?, ?);', values=values) -# async def check_grant_numbers(group_id): -# return await db_execute( -# string=f"SELECT COUNT(*) FROM grant_numbers WHERE group_id LIKE '%{group_id}%'", get=True) - - async def get_data_from_grant_numbers(group_id): return await db_execute(string=f'SELECT numbers FROM grant_numbers WHERE group_id={group_id}', get=True) diff --git a/tgbot/Utils/check_message_user_groups.py b/tgbot/Utils/check_message_user_groups.py index 44ab30b..2740cc6 100644 --- a/tgbot/Utils/check_message_user_groups.py +++ b/tgbot/Utils/check_message_user_groups.py @@ -5,6 +5,6 @@ async def check_users_groups(message: str): users_groups_ids = message.split(',') for number in users_groups_ids: - if not await check_number_in_message(number=number): - return False - return True + if await check_number_in_message(number=number): + return True + diff --git a/tgbot/Utils/get_numbers.py b/tgbot/Utils/get_numbers.py index fb5e135..923b605 100644 --- a/tgbot/Utils/get_numbers.py +++ b/tgbot/Utils/get_numbers.py @@ -3,4 +3,6 @@ async def get_grant_numbers(group_id): numbers = await get_data_from_grant_numbers(group_id) + if not numbers[0][0]: + return [] return [int(number) for number in numbers[0][0].split(',')] diff --git a/tgbot/Utils/get_user_link.py b/tgbot/Utils/get_user_link.py index da7bbe1..4ac0b65 100644 --- a/tgbot/Utils/get_user_link.py +++ b/tgbot/Utils/get_user_link.py @@ -1,5 +1,6 @@ from aiogram import md from aiogram import types +from aiogram.utils.markdown import quote_html async def get_link(user: types.User): @@ -10,7 +11,7 @@ async def get_link(user: types.User): if user.last_name: username += f' {user.last_name}' elif user.username: - username = user.username + username = quote_html(user.username) else: username = 'пользователь' return md.hlink(username, user.url) diff --git a/tgbot/filters/count.py b/tgbot/filters/count.py index cea6603..30d6c0a 100644 --- a/tgbot/filters/count.py +++ b/tgbot/filters/count.py @@ -22,4 +22,3 @@ async def check(self, update: types.ChatMemberUpdated): saved_grant_numbers = await get_grant_numbers(update.chat.id) if 0 < count_to_delete[0][0] < 3 or (count in saved_grant_numbers) or not count % config_count: return {"count": count} - return False diff --git a/tgbot/filters/granted.py b/tgbot/filters/granted.py index 5d01428..955264b 100644 --- a/tgbot/filters/granted.py +++ b/tgbot/filters/granted.py @@ -15,6 +15,5 @@ async def check(self, update: types.ChatMemberUpdated): if granted[0][0]: return False in_queue = await check_queue(user_id=update.new_chat_member.user.id, group_id=update.chat.id) - if in_queue[0][0]: - return False - return True + if not in_queue[0][0]: + return True diff --git a/tgbot/filters/moder_group.py b/tgbot/filters/moder_group.py index a1f2920..bb55ff5 100644 --- a/tgbot/filters/moder_group.py +++ b/tgbot/filters/moder_group.py @@ -17,4 +17,3 @@ async def check(self, message: types.Message): ids = await get_users_groups(message.chat.id) if ids: return {"ids": ids} - return False diff --git a/tgbot/filters/user_group.py b/tgbot/filters/user_group.py index 988af24..d65afa9 100644 --- a/tgbot/filters/user_group.py +++ b/tgbot/filters/user_group.py @@ -17,4 +17,3 @@ async def check(self, update: types.ChatMemberUpdated): ids = await get_moder_groups(update.chat.id) if ids: return {"ids": ids} - return False diff --git a/tgbot/handlers/admin/__init__.py b/tgbot/handlers/admin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tgbot/handlers/admin/back_to_main_menu.py b/tgbot/handlers/admin/back_to_main_menu.py index 427c9f4..603c5e8 100644 --- a/tgbot/handlers/admin/back_to_main_menu.py +++ b/tgbot/handlers/admin/back_to_main_menu.py @@ -8,7 +8,7 @@ async def back_to_main(call: types.CallbackQuery, state: FSMContext): with suppress(MessageCantBeEdited): - await call.message.edit_text(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=await get_main_menu_kb()) + await call.message.edit_text(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=get_main_menu_kb()) await state.finish() diff --git a/tgbot/handlers/admin/configure_groups_callback.py b/tgbot/handlers/admin/configure_groups_callback.py index 05b326b..89fad80 100644 --- a/tgbot/handlers/admin/configure_groups_callback.py +++ b/tgbot/handlers/admin/configure_groups_callback.py @@ -10,7 +10,7 @@ async def configure_groups(call: types.CallbackQuery): with suppress(MessageCantBeEdited): await call.message.edit_text(text='⚙ Настройка таблицы соответствия групп ⚙', - reply_markup=await get_conf_groups_kb()) + reply_markup=get_conf_groups_kb()) def register_configure_groups(dp: Dispatcher): diff --git a/tgbot/handlers/admin/configure_numbers_callback.py b/tgbot/handlers/admin/configure_numbers_callback.py index dbb098f..fe62605 100644 --- a/tgbot/handlers/admin/configure_numbers_callback.py +++ b/tgbot/handlers/admin/configure_numbers_callback.py @@ -10,7 +10,7 @@ async def configure_numbers(call: types.CallbackQuery): with suppress(MessageCantBeEdited): await call.message.edit_text(text='⚙ Настройка таблицы с поздр. номерами ⚙', - reply_markup=await get_conf_numbers_kb()) + reply_markup=get_conf_numbers_kb()) def register_configure_numbers(dp: Dispatcher): diff --git a/tgbot/handlers/admin/delete_from_groups.py b/tgbot/handlers/admin/delete_from_groups.py index cc97616..36f6842 100644 --- a/tgbot/handlers/admin/delete_from_groups.py +++ b/tgbot/handlers/admin/delete_from_groups.py @@ -28,7 +28,7 @@ async def delete_from_groups(message: types.Message, state: FSMContext): await message.answer(f'Таких строк нет в таблице') await state.finish() await message.answer(text='⚙ Настройка таблицы соответствия групп ⚙', - reply_markup=await get_conf_groups_kb()) + reply_markup=get_conf_groups_kb()) def register_delete_from_groups(dp: Dispatcher): diff --git a/tgbot/handlers/admin/delete_from_numbers.py b/tgbot/handlers/admin/delete_from_numbers.py index 9c9565d..bf54233 100644 --- a/tgbot/handlers/admin/delete_from_numbers.py +++ b/tgbot/handlers/admin/delete_from_numbers.py @@ -28,7 +28,7 @@ async def delete_numbers(message: types.Message, state: FSMContext): await message.answer(f'Таких строк нет в таблице') await state.finish() await message.answer(text='⚙ Настройка таблицы с поздр. номерами ⚙', - reply_markup=await get_conf_numbers_kb()) + reply_markup=get_conf_numbers_kb()) def register_delete_numbers(dp: Dispatcher): diff --git a/tgbot/handlers/admin/get_numbers.py b/tgbot/handlers/admin/get_numbers.py index be2ef25..cb98b9b 100644 --- a/tgbot/handlers/admin/get_numbers.py +++ b/tgbot/handlers/admin/get_numbers.py @@ -33,7 +33,7 @@ async def get_grant_numbers(message: types.Message, state: FSMContext): await message.answer('Записал') await state.finish() await message.answer(text='⚙ Настройка таблицы с поздр. номерами ⚙', - reply_markup=await get_conf_numbers_kb()) + reply_markup=get_conf_numbers_kb()) def register_get_grant_numbers(dp: Dispatcher): diff --git a/tgbot/handlers/admin/get_users_groups.py b/tgbot/handlers/admin/get_users_groups.py index 71e835a..7a47b3a 100644 --- a/tgbot/handlers/admin/get_users_groups.py +++ b/tgbot/handlers/admin/get_users_groups.py @@ -36,7 +36,7 @@ async def get_users_group(message: types.Message, state: FSMContext): await message.answer('Записал') await state.finish() await message.answer(text='⚙ Настройка таблицы соответствия групп ⚙', - reply_markup=await get_conf_groups_kb()) + reply_markup=get_conf_groups_kb()) def register_get_users_group(dp: Dispatcher): diff --git a/tgbot/handlers/admin/main_menu.py b/tgbot/handlers/admin/main_menu.py index b681cc4..42de49b 100644 --- a/tgbot/handlers/admin/main_menu.py +++ b/tgbot/handlers/admin/main_menu.py @@ -8,7 +8,7 @@ async def main_menu(message: types.Message): - await message.answer(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=await get_main_menu_kb()) + await message.answer(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=get_main_menu_kb()) def register_main_menu(dp: Dispatcher): diff --git a/tgbot/handlers/admin/show_groups_callback.py b/tgbot/handlers/admin/show_groups_callback.py index f6b1588..a2243bd 100644 --- a/tgbot/handlers/admin/show_groups_callback.py +++ b/tgbot/handlers/admin/show_groups_callback.py @@ -10,16 +10,14 @@ async def show_groups(call: types.CallbackQuery): groups = await get_groups() - text = md.hunderline('ID | Группа модераторов | Группы пользователей\n') + text = md.hbold('ID | Группа модераторов | Группы пользователей\n\n') with suppress(MessageCantBeDeleted): await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) if groups: for group in groups: - string = md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') - text += string - text += f'{"‾" * (len(string) // 2 + 11)}\n' + text += md.hunderline(f'{group[0]} | {group[1]} | {group[2]} |\n') await call.message.answer(text=text) else: await call.message.answer(text='Таблица еще пуста') diff --git a/tgbot/handlers/admin/show_numbers_callback.py b/tgbot/handlers/admin/show_numbers_callback.py index c12e809..75b9858 100644 --- a/tgbot/handlers/admin/show_numbers_callback.py +++ b/tgbot/handlers/admin/show_numbers_callback.py @@ -10,16 +10,14 @@ async def show_numbers(call: types.CallbackQuery): groups = await get_numbers() - text = md.hunderline('ID |ID Группы|Номера для поздравления\n') + text = md.hbold('ID |ID Группы|Номера для поздравления\n\n') with suppress(MessageCantBeDeleted): await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) if groups: for group in groups: - string = md.hbold(f'{group[0]} | {group[1]} | {group[2]} |\n') - text += string - text += f'{"‾" * (len(string) // 2 + 5)}\n' + text += md.hunderline(f'{group[0]} | {group[1]} | {group[2]} |\n') await call.message.answer(text=text) else: await call.message.answer(text='Таблица еще пуста') diff --git a/tgbot/handlers/groups/catch_update.py b/tgbot/handlers/groups/catch_update.py index 96a3a26..bd783ff 100644 --- a/tgbot/handlers/groups/catch_update.py +++ b/tgbot/handlers/groups/catch_update.py @@ -1,4 +1,7 @@ from typing import List + +from aiogram.utils.markdown import quote_html + from tgbot.keyboards.inline import get_gran_kb from aiogram import Dispatcher, types from aiogram.types import ChatType @@ -12,7 +15,7 @@ async def new_chat(update: types.ChatMemberUpdated, ids: List[tuple[int]], count link = await get_link(update.new_chat_member.user) uid = str(uuid.uuid4()) if update.new_chat_member.user.username: - username = f'@{update.new_chat_member.user.username}' + username = f'@{quote_html(update.new_chat_member.user.username)}' else: username = 'ника нет' text = f'🎉 В “{update.chat.title}” группу вступил юбилейный пользователь\n' \ @@ -28,7 +31,7 @@ async def new_chat(update: types.ChatMemberUpdated, ids: List[tuple[int]], count def register_catch(dp: Dispatcher): - chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] dp.register_chat_member_handler(new_chat, chat_type=chat_types, is_group_join=True, diff --git a/tgbot/handlers/groups/echo.py b/tgbot/handlers/groups/echo.py index aa26706..1b822d3 100644 --- a/tgbot/handlers/groups/echo.py +++ b/tgbot/handlers/groups/echo.py @@ -2,6 +2,8 @@ from aiogram.dispatcher import FSMContext from aiogram.utils.markdown import hcode +from Utils.get_user_link import get_link + async def bot_echo(message: types.Message): text = [ diff --git a/tgbot/handlers/groups/get_granted.py b/tgbot/handlers/groups/get_granted.py index 0f11a31..358d178 100644 --- a/tgbot/handlers/groups/get_granted.py +++ b/tgbot/handlers/groups/get_granted.py @@ -1,20 +1,23 @@ from typing import List from aiogram import Dispatcher, types +from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from tgbot.Utils.DBWorker import get_data_granted +from keyboards.inline import get_list_granted_kb +from misc.show_granted import send_granted_message +from tgbot.Utils.DBWorker import get_data_granted, get_users_groups -async def get_granted(message: types.Message, ids: List[tuple[str]]): + +async def get_granted(message: types.Message, ids: List[tuple[str]], state: FSMContext): granted_list = await get_data_granted(message.chat.id) if granted_list: - for granted in granted_list: - emoji = '🎉' - if granted[6]: - emoji = '👑👑👑' - await message.answer(text=f'{emoji} “{granted[2]}” 👤 {granted[4]} ({granted[10]}),\n' - f'🔢 {granted[7]} 🕐 {granted[8]}') + user_groups_ids = {id_user_gr[1]: id_user_gr[2] for id_user_gr in granted_list} + if len(user_groups_ids) > 1: + await message.answer(text='Выберите группу', reply_markup=get_list_granted_kb(user_groups_ids)) + else: + await send_granted_message(granted_list, message) else: - await message.answer('В группах для модерированния еще нет поздравленных пользователей') + await message.answer('В группах для модерирования еще нет поздравленных пользователей') def register_get_granted(dp: Dispatcher): diff --git a/tgbot/handlers/groups/grant_callback.py b/tgbot/handlers/groups/grant_callback.py index 8714a36..287a650 100644 --- a/tgbot/handlers/groups/grant_callback.py +++ b/tgbot/handlers/groups/grant_callback.py @@ -6,6 +6,7 @@ from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeEdited, MessageToEditNotFound, MessageNotModified +from misc.grant_text import get_great_text from tgbot.Utils.DBWorker import get_message_in_queue, get_queue, delete_from_queue, vacuum, set_data_granted, \ count_from_queue @@ -33,19 +34,15 @@ async def grant_user(call: types.CallbackQuery): await call.answer(text="Такого пользователя уже нет в группе", show_alert=True) raise CancelHandler() - text = f'🎉 Поздравляю, {user}, как же удачно попали в нужное место и в нужное время!\n' \ - f'Вы {count_for_grant[0][0]} участник комьюнити.\n' \ - f'Вас ждут плюшки и печенюшки!🎉' + text = get_great_text(user, count_for_grant[0][0]) grant_message = await call.bot.send_message(chat_id=group_id_users, text=text) await call.answer() await call.message.answer(text=f"Пользователь {user} в группе {grant_message.chat.title} поздравлен") - try: - await call.bot.edit_message_reply_markup(chat_id=group_id_mod, message_id=message_id, reply_markup=None) - except (MessageCantBeEdited, MessageToEditNotFound, MessageNotModified, MessageCantBeEdited) as exc: - pass + with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified, MessageCantBeEdited): + await call.message.delete_reply_markup() granted = [(group_id_users, grant_message.chat.title, user_id, user, group_id_mod, moder_id, count, datetime_update, datetime_granted, username)] @@ -65,5 +62,5 @@ async def grant_user(call: types.CallbackQuery): def register_grant(dp: Dispatcher): - chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] dp.register_callback_query_handler(grant_user, Text(startswith='grant'), chat_type=chat_types) diff --git a/tgbot/handlers/groups/grant_cancel_callback.py b/tgbot/handlers/groups/grant_cancel_callback.py index 56c3e1f..b164130 100644 --- a/tgbot/handlers/groups/grant_cancel_callback.py +++ b/tgbot/handlers/groups/grant_cancel_callback.py @@ -10,8 +10,7 @@ async def cancel_grant_user(call: types.CallbackQuery): message = await get_message_in_queue(uid) await call.answer() if message: - await call.bot.edit_message_reply_markup(chat_id=call.message.chat.id, message_id=message[0][1], - reply_markup=None) + await call.message.delete_reply_markup() def register_cancel_grant(dp: Dispatcher): diff --git a/tgbot/handlers/groups/show_granted_callback.py b/tgbot/handlers/groups/show_granted_callback.py new file mode 100644 index 0000000..ad67920 --- /dev/null +++ b/tgbot/handlers/groups/show_granted_callback.py @@ -0,0 +1,22 @@ +from contextlib import suppress + +from aiogram import Dispatcher +from aiogram.types import CallbackQuery, ChatType +from aiogram.utils.exceptions import MessageToEditNotFound, MessageCantBeDeleted + +from Utils.DBWorker import get_data_granted_for_kb +from keyboards.inline import cb +from misc.show_granted import send_granted_message + + +async def show_granted_cb(call: CallbackQuery, callback_data: dict): + id_group = callback_data["ids"] + granted_list = await get_data_granted_for_kb(id_group) + with suppress(MessageCantBeDeleted, MessageToEditNotFound): + await call.message.delete() + await send_granted_message(granted_list, call.message) + + +def register_show_granted_cb(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] + dp.register_callback_query_handler(show_granted_cb, cb.filter(), chat_type=chat_types) diff --git a/tgbot/handlers/groups/show_granted_cancel_callback.py b/tgbot/handlers/groups/show_granted_cancel_callback.py new file mode 100644 index 0000000..226dd6f --- /dev/null +++ b/tgbot/handlers/groups/show_granted_cancel_callback.py @@ -0,0 +1,15 @@ +from contextlib import suppress +from aiogram import Dispatcher +from aiogram.types import CallbackQuery, ChatType +from aiogram.utils.exceptions import MessageToEditNotFound, MessageCantBeDeleted +from keyboards.inline import cb + + +async def show_granted_cb(call: CallbackQuery, callback_data: dict): + with suppress(MessageCantBeDeleted, MessageToEditNotFound): + await call.message.delete() + + +def register_show_granted_cb(dp: Dispatcher): + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] + dp.register_callback_query_handler(show_granted_cb, cb.filter(ids=0), chat_type=chat_types) diff --git a/tgbot/keyboards/inline.py b/tgbot/keyboards/inline.py index 8acf58e..f62144b 100644 --- a/tgbot/keyboards/inline.py +++ b/tgbot/keyboards/inline.py @@ -1,14 +1,16 @@ +from aiogram import types from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.utils.callback_data import CallbackData -async def get_gran_kb(uid): +def get_gran_kb(uid): grant_btn = InlineKeyboardButton('Поздравить!', callback_data=f'grant|{uid}') cancel_btn = InlineKeyboardButton('Отмена', callback_data=f'can|{uid}') grant_kb = InlineKeyboardMarkup().add(grant_btn, cancel_btn) return grant_kb -async def get_conf_groups_kb(): +def get_conf_groups_kb(): show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_groups') add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_groups') delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_groups') @@ -17,7 +19,7 @@ async def get_conf_groups_kb(): return conf_groups_kb -async def get_main_menu_kb(): +def get_main_menu_kb(): config_groups_btn = InlineKeyboardButton('Настройка таблицы групп', callback_data='configure_groups') config_numbers_btn = InlineKeyboardButton('Настройка таблицы номеров', callback_data='configure_numbers') cancel_btn = InlineKeyboardButton('Отмена', callback_data='cancel') @@ -25,10 +27,30 @@ async def get_main_menu_kb(): return main_kb -async def get_conf_numbers_kb(): +def get_conf_numbers_kb(): show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_numbers') add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_numbers') delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_numbers') back_to_main_btn = InlineKeyboardButton('Главное меню', callback_data='back_to_main') conf_numbers_kb = InlineKeyboardMarkup(row_width=1).add(show_btn, add_btn, delete_btn, back_to_main_btn) return conf_numbers_kb + + +cb = CallbackData('gr', 'ids') + + +def get_list_granted_kb(user_groups: dict) -> types.InlineKeyboardMarkup: + + markup = types.InlineKeyboardMarkup() + for ids, user_group in user_groups.items(): + markup.add( + types.InlineKeyboardButton( + user_group, + callback_data=cb.new(ids=ids)), + ) + markup.add( + types.InlineKeyboardButton( + 'Отмена', + callback_data=cb.new(ids=0)), + ) + return markup diff --git a/tgbot/misc/grant_text.py b/tgbot/misc/grant_text.py new file mode 100644 index 0000000..7f843f3 --- /dev/null +++ b/tgbot/misc/grant_text.py @@ -0,0 +1,5 @@ +def get_great_text(user, count): + text = f'🎉 Поздравляю, {user}, как же удачно попали в нужное место и в нужное время!\n' \ + f'Вы {count} участник комьюнити.\n' \ + f'Вас ждут плюшки и печенюшки!🎉' + return text diff --git a/tgbot/misc/show_granted.py b/tgbot/misc/show_granted.py new file mode 100644 index 0000000..3229f77 --- /dev/null +++ b/tgbot/misc/show_granted.py @@ -0,0 +1,10 @@ +from aiogram import types + + +async def send_granted_message(granted_list: list[tuple], message: types.Message): + for granted in granted_list: + emoji = '🎉' + if granted[6]: + emoji = '👑👑👑' + await message.answer(text=f'{emoji} “{granted[2]}” 👤 {granted[4]} ({granted[10]}),\n' + f'🔢 {granted[7]} 🕐 {granted[8]}') diff --git a/tgbot/misc/states.py b/tgbot/misc/states.py index 08a0aec..381a89e 100644 --- a/tgbot/misc/states.py +++ b/tgbot/misc/states.py @@ -2,7 +2,6 @@ class Configure(StatesGroup): - AddNumbersGroup = State() AddNumbers = State() DeleteNumbers = State() From bdb3d4b6429914ecbcf9623e4646cf79e458090a Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Mon, 18 Jul 2022 14:33:28 +0300 Subject: [PATCH 12/16] Fix imports --- bot.py | 80 +++++++++---------- tgbot/Utils/check_message_user_groups.py | 2 +- tgbot/Utils/check_number.py | 1 - tgbot/Utils/get_numbers.py | 2 +- tgbot/filters/count.py | 2 +- tgbot/handlers/__init__.py | 0 tgbot/handlers/admin/add_groups_callback.py | 2 +- tgbot/handlers/admin/add_numbers_callback.py | 4 +- tgbot/handlers/admin/admin.py | 2 +- tgbot/handlers/admin/back_to_main_menu.py | 2 +- .../admin/configure_groups_callback.py | 2 +- .../admin/configure_numbers_callback.py | 2 +- tgbot/handlers/admin/delete_from_groups.py | 10 +-- tgbot/handlers/admin/delete_from_numbers.py | 10 +-- .../handlers/admin/delete_groups_callback.py | 4 +- .../handlers/admin/delete_numbers_callback.py | 4 +- tgbot/handlers/admin/get_mod_group.py | 4 +- tgbot/handlers/admin/get_numbers.py | 8 +- tgbot/handlers/admin/get_numbers_group.py | 4 +- tgbot/handlers/admin/get_users_groups.py | 10 +-- tgbot/handlers/admin/main_menu.py | 6 +- tgbot/handlers/admin/show_groups_callback.py | 2 +- tgbot/handlers/admin/show_numbers_callback.py | 2 +- tgbot/handlers/admin/user.py | 2 +- tgbot/handlers/groups/catch_update.py | 3 - tgbot/handlers/groups/echo.py | 2 - tgbot/handlers/groups/get_granted.py | 4 +- tgbot/handlers/groups/grant_callback.py | 10 +-- tgbot/handlers/groups/restore.py | 2 +- .../handlers/groups/show_granted_callback.py | 6 +- .../groups/show_granted_cancel_callback.py | 2 +- 31 files changed, 93 insertions(+), 103 deletions(-) delete mode 100644 tgbot/handlers/__init__.py diff --git a/bot.py b/bot.py index 501315e..b9ac991 100644 --- a/bot.py +++ b/bot.py @@ -7,45 +7,45 @@ from aiogram.contrib.middlewares.logging import LoggingMiddleware from aiogram.types import AllowedUpdates -from handlers.admin.add_groups_callback import register_add_groups -from handlers.admin.add_numbers_callback import register_add_numbers -from handlers.admin.cancel import register_cancel_menu -from handlers.admin.configure_groups_callback import register_configure_groups -from handlers.admin.configure_numbers_callback import register_configure_numbers -from handlers.admin.delete_from_groups import register_delete_from_groups -from handlers.admin.delete_from_numbers import register_delete_numbers -from handlers.admin.delete_groups_callback import register_delete_groups_cb -from handlers.admin.delete_numbers_callback import register_delete_numbers_cb -from handlers.admin.get_mod_group import register_get_mod_group -from handlers.admin.get_numbers import register_get_grant_numbers -from handlers.admin.get_numbers_group import register_numbers_group -from handlers.admin.get_users_groups import register_get_users_group -from handlers.admin.main_menu import register_main_menu -from handlers.admin.back_to_main_menu import register_back_to_main -from handlers.admin.show_groups_callback import register_show_groups -from handlers.admin.show_numbers_callback import register_show_numbers -from handlers.admin.user import register_user -from handlers.admin.admin import register_admin - -from handlers.groups.check import register_check_queue -from handlers.groups.get_granted import register_get_granted -from handlers.groups.restore import register_restore -from handlers.groups.grant_cancel_callback import register_cancel_grant -from handlers.groups.grant_callback import register_grant -from handlers.groups.catch_update import register_catch -from handlers.groups.echo import register_echo -from handlers.groups.show_granted_callback import register_show_granted_cb - -from misc.set_commands import set_default_commands - -from filters.moder_group import IsModerGroup -from filters.granted import IsNotGranted -from filters.count import IsGrantCount -from filters.user_group import IsUserGroup -from Utils.DBWorker import create_tables -from config import load_config -from filters.admin import AdminFilter -from filters.group_join import IsGroupJoin +from tgbot.handlers.admin.add_groups_callback import register_add_groups +from tgbot.handlers.admin.add_numbers_callback import register_add_numbers +from tgbot.handlers.admin.cancel import register_cancel_menu +from tgbot.handlers.admin.configure_groups_callback import register_configure_groups +from tgbot.handlers.admin.configure_numbers_callback import register_configure_numbers +from tgbot.handlers.admin.delete_from_groups import register_delete_from_groups +from tgbot.handlers.admin.delete_from_numbers import register_delete_numbers +from tgbot.handlers.admin.delete_groups_callback import register_delete_groups_cb +from tgbot.handlers.admin.delete_numbers_callback import register_delete_numbers_cb +from tgbot.handlers.admin.get_mod_group import register_get_mod_group +from tgbot.handlers.admin.get_numbers import register_get_grant_numbers +from tgbot.handlers.admin.get_numbers_group import register_numbers_group +from tgbot.handlers.admin.get_users_groups import register_get_users_group +from tgbot.handlers.admin.main_menu import register_main_menu +from tgbot.handlers.admin.back_to_main_menu import register_back_to_main +from tgbot.handlers.admin.show_groups_callback import register_show_groups +from tgbot.handlers.admin.show_numbers_callback import register_show_numbers +from tgbot.handlers.admin.user import register_user +from tgbot.handlers.admin.admin import register_admin + +from tgbot.handlers.groups.check import register_check_queue +from tgbot.handlers.groups.get_granted import register_get_granted +from tgbot.handlers.groups.restore import register_restore +from tgbot.handlers.groups.grant_cancel_callback import register_cancel_grant +from tgbot.handlers.groups.grant_callback import register_grant +from tgbot.handlers.groups.catch_update import register_catch +from tgbot.handlers.groups.echo import register_echo +from tgbot.handlers.groups.show_granted_callback import register_show_granted_cb + +from tgbot.misc.set_commands import set_default_commands + +from tgbot.filters.moder_group import IsModerGroup +from tgbot.filters.granted import IsNotGranted +from tgbot.filters.count import IsGrantCount +from tgbot.filters.user_group import IsUserGroup +from tgbot.Utils.DBWorker import create_tables +from tgbot.config import load_config +from tgbot.filters.admin import AdminFilter +from tgbot.filters.group_join import IsGroupJoin logger = logging.getLogger(__name__) @@ -125,6 +125,6 @@ async def main(): if __name__ == '__main__': try: - asyncio.run(main()) + asyncio.get_event_loop().run_until_complete(main()) except (KeyboardInterrupt, SystemExit): logger.error("Bot stopped!") diff --git a/tgbot/Utils/check_message_user_groups.py b/tgbot/Utils/check_message_user_groups.py index 2740cc6..6226548 100644 --- a/tgbot/Utils/check_message_user_groups.py +++ b/tgbot/Utils/check_message_user_groups.py @@ -1,4 +1,4 @@ -from Utils.check_number import check_number_in_message +from tgbot.Utils.check_number import check_number_in_message async def check_users_groups(message: str): diff --git a/tgbot/Utils/check_number.py b/tgbot/Utils/check_number.py index 80cf89a..0b884e9 100644 --- a/tgbot/Utils/check_number.py +++ b/tgbot/Utils/check_number.py @@ -1,4 +1,3 @@ - async def check_number_in_message(number: str): if number[:1] == '-': if number[1:].isdigit(): diff --git a/tgbot/Utils/get_numbers.py b/tgbot/Utils/get_numbers.py index 923b605..a40d41b 100644 --- a/tgbot/Utils/get_numbers.py +++ b/tgbot/Utils/get_numbers.py @@ -1,4 +1,4 @@ -from Utils.DBWorker import get_data_from_grant_numbers +from tgbot.Utils.DBWorker import get_data_from_grant_numbers async def get_grant_numbers(group_id): diff --git a/tgbot/filters/count.py b/tgbot/filters/count.py index 30d6c0a..5ee48f1 100644 --- a/tgbot/filters/count.py +++ b/tgbot/filters/count.py @@ -2,7 +2,7 @@ from aiogram.dispatcher.filters import BoundFilter from aiogram.dispatcher.handler import CancelHandler -from Utils.get_numbers import get_grant_numbers +from tgbot.Utils.get_numbers import get_grant_numbers from tgbot.Utils.DBWorker import get_count_queue diff --git a/tgbot/handlers/__init__.py b/tgbot/handlers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tgbot/handlers/admin/add_groups_callback.py b/tgbot/handlers/admin/add_groups_callback.py index 4d7f88b..74f9382 100644 --- a/tgbot/handlers/admin/add_groups_callback.py +++ b/tgbot/handlers/admin/add_groups_callback.py @@ -2,7 +2,7 @@ from aiogram import Dispatcher, types from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeDeleted -from misc.states import Configure +from tgbot.misc.states import Configure async def add_groups(call: types.CallbackQuery): diff --git a/tgbot/handlers/admin/add_numbers_callback.py b/tgbot/handlers/admin/add_numbers_callback.py index 4f50046..7edf012 100644 --- a/tgbot/handlers/admin/add_numbers_callback.py +++ b/tgbot/handlers/admin/add_numbers_callback.py @@ -2,12 +2,12 @@ from aiogram import Dispatcher, types from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeDeleted -from misc.states import Configure +from tgbot.misc.states import Configure async def add_numbers(call: types.CallbackQuery): with suppress(MessageCantBeDeleted): - await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + await call.message.delete() await call.message.answer(text='Введите id группы, целое число (/reset для сброса)') await Configure.AddNumbersGroup.set() diff --git a/tgbot/handlers/admin/admin.py b/tgbot/handlers/admin/admin.py index a40a47f..1b0728c 100644 --- a/tgbot/handlers/admin/admin.py +++ b/tgbot/handlers/admin/admin.py @@ -3,7 +3,7 @@ async def admin_start(message: Message): - await message.reply("Hello, admin!") + await message.reply("Добрый день! Конфигурация доступна из меню.") def register_admin(dp: Dispatcher): diff --git a/tgbot/handlers/admin/back_to_main_menu.py b/tgbot/handlers/admin/back_to_main_menu.py index 603c5e8..2cc0f4b 100644 --- a/tgbot/handlers/admin/back_to_main_menu.py +++ b/tgbot/handlers/admin/back_to_main_menu.py @@ -3,7 +3,7 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeEdited -from keyboards.inline import get_main_menu_kb +from tgbot.keyboards.inline import get_main_menu_kb async def back_to_main(call: types.CallbackQuery, state: FSMContext): diff --git a/tgbot/handlers/admin/configure_groups_callback.py b/tgbot/handlers/admin/configure_groups_callback.py index 89fad80..f944694 100644 --- a/tgbot/handlers/admin/configure_groups_callback.py +++ b/tgbot/handlers/admin/configure_groups_callback.py @@ -4,7 +4,7 @@ from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeEdited -from keyboards.inline import get_conf_groups_kb +from tgbot.keyboards.inline import get_conf_groups_kb async def configure_groups(call: types.CallbackQuery): diff --git a/tgbot/handlers/admin/configure_numbers_callback.py b/tgbot/handlers/admin/configure_numbers_callback.py index fe62605..8c09a7e 100644 --- a/tgbot/handlers/admin/configure_numbers_callback.py +++ b/tgbot/handlers/admin/configure_numbers_callback.py @@ -4,7 +4,7 @@ from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeEdited -from keyboards.inline import get_conf_numbers_kb +from tgbot.keyboards.inline import get_conf_numbers_kb async def configure_numbers(call: types.CallbackQuery): diff --git a/tgbot/handlers/admin/delete_from_groups.py b/tgbot/handlers/admin/delete_from_groups.py index 36f6842..d5065ff 100644 --- a/tgbot/handlers/admin/delete_from_groups.py +++ b/tgbot/handlers/admin/delete_from_groups.py @@ -2,12 +2,12 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.DBWorker import delete_data_from_groups, vacuum -from Utils.check_message_user_groups import check_users_groups -from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record -from keyboards.inline import get_conf_groups_kb +from tgbot.Utils.DBWorker import delete_data_from_groups, vacuum +from tgbot.Utils.check_message_user_groups import check_users_groups +from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from tgbot.keyboards.inline import get_conf_groups_kb -from misc.states import Configure +from tgbot.misc.states import Configure async def delete_from_groups(message: types.Message, state: FSMContext): diff --git a/tgbot/handlers/admin/delete_from_numbers.py b/tgbot/handlers/admin/delete_from_numbers.py index bf54233..3d6037f 100644 --- a/tgbot/handlers/admin/delete_from_numbers.py +++ b/tgbot/handlers/admin/delete_from_numbers.py @@ -2,12 +2,12 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.DBWorker import delete_data_from_grant_numbers, vacuum -from Utils.check_message_user_groups import check_users_groups -from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record -from keyboards.inline import get_conf_numbers_kb +from tgbot.Utils.DBWorker import delete_data_from_grant_numbers, vacuum +from tgbot.Utils.check_message_user_groups import check_users_groups +from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from tgbot.keyboards.inline import get_conf_numbers_kb -from misc.states import Configure +from tgbot.misc.states import Configure async def delete_numbers(message: types.Message, state: FSMContext): diff --git a/tgbot/handlers/admin/delete_groups_callback.py b/tgbot/handlers/admin/delete_groups_callback.py index 251731c..0f5e0f4 100644 --- a/tgbot/handlers/admin/delete_groups_callback.py +++ b/tgbot/handlers/admin/delete_groups_callback.py @@ -5,12 +5,12 @@ from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeDeleted -from misc.states import Configure +from tgbot.misc.states import Configure async def delete_groups(call: types.CallbackQuery): with suppress(MessageCantBeDeleted): - await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + await call.message.delete() await call.message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') diff --git a/tgbot/handlers/admin/delete_numbers_callback.py b/tgbot/handlers/admin/delete_numbers_callback.py index e7c1694..b4a1ded 100644 --- a/tgbot/handlers/admin/delete_numbers_callback.py +++ b/tgbot/handlers/admin/delete_numbers_callback.py @@ -5,12 +5,12 @@ from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeDeleted -from misc.states import Configure +from tgbot.misc.states import Configure async def delete_numbers(call: types.CallbackQuery): with suppress(MessageCantBeDeleted): - await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + await call.message.delete() await call.message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') diff --git a/tgbot/handlers/admin/get_mod_group.py b/tgbot/handlers/admin/get_mod_group.py index 7c3a4f6..e52af84 100644 --- a/tgbot/handlers/admin/get_mod_group.py +++ b/tgbot/handlers/admin/get_mod_group.py @@ -2,9 +2,9 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.check_number import check_number_in_message +from tgbot.Utils.check_number import check_number_in_message -from misc.states import Configure +from tgbot.misc.states import Configure async def get_mod_group(message: types.Message, state: FSMContext): diff --git a/tgbot/handlers/admin/get_numbers.py b/tgbot/handlers/admin/get_numbers.py index cb98b9b..73f2f8c 100644 --- a/tgbot/handlers/admin/get_numbers.py +++ b/tgbot/handlers/admin/get_numbers.py @@ -2,10 +2,10 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.check_message_user_groups import check_users_groups -from Utils.delete_doubles import delete_doubles_ids -from keyboards.inline import get_conf_numbers_kb -from misc.states import Configure +from tgbot.Utils.check_message_user_groups import check_users_groups +from tgbot.Utils.delete_doubles import delete_doubles_ids +from tgbot.keyboards.inline import get_conf_numbers_kb +from tgbot.misc.states import Configure from tgbot.Utils.DBWorker import get_data_from_grant_numbers, set_data_numbers diff --git a/tgbot/handlers/admin/get_numbers_group.py b/tgbot/handlers/admin/get_numbers_group.py index 20cdabe..3092cd0 100644 --- a/tgbot/handlers/admin/get_numbers_group.py +++ b/tgbot/handlers/admin/get_numbers_group.py @@ -2,9 +2,9 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.check_number import check_number_in_message +from tgbot.Utils.check_number import check_number_in_message -from misc.states import Configure +from tgbot.misc.states import Configure async def get_numbers_group(message: types.Message, state: FSMContext): diff --git a/tgbot/handlers/admin/get_users_groups.py b/tgbot/handlers/admin/get_users_groups.py index 7a47b3a..2777ef5 100644 --- a/tgbot/handlers/admin/get_users_groups.py +++ b/tgbot/handlers/admin/get_users_groups.py @@ -2,11 +2,11 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from Utils.check_message_user_groups import check_users_groups -from Utils.delete_doubles import delete_doubles_ids -from Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record -from keyboards.inline import get_conf_groups_kb -from misc.states import Configure +from tgbot.Utils.check_message_user_groups import check_users_groups +from tgbot.Utils.delete_doubles import delete_doubles_ids +from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record +from tgbot.keyboards.inline import get_conf_groups_kb +from tgbot.misc.states import Configure from tgbot.Utils.DBWorker import set_data_groups, get_user_ids_from_groups, set_group_ids_grant_numbers diff --git a/tgbot/handlers/admin/main_menu.py b/tgbot/handlers/admin/main_menu.py index 42de49b..d844199 100644 --- a/tgbot/handlers/admin/main_menu.py +++ b/tgbot/handlers/admin/main_menu.py @@ -1,10 +1,6 @@ -from typing import List from aiogram import Dispatcher, types from aiogram.types import ChatType - -from keyboards.inline import get_main_menu_kb -from misc.states import Configure -from tgbot.Utils.DBWorker import get_data_granted +from tgbot.keyboards.inline import get_main_menu_kb async def main_menu(message: types.Message): diff --git a/tgbot/handlers/admin/show_groups_callback.py b/tgbot/handlers/admin/show_groups_callback.py index a2243bd..2914fde 100644 --- a/tgbot/handlers/admin/show_groups_callback.py +++ b/tgbot/handlers/admin/show_groups_callback.py @@ -13,7 +13,7 @@ async def show_groups(call: types.CallbackQuery): text = md.hbold('ID | Группа модераторов | Группы пользователей\n\n') with suppress(MessageCantBeDeleted): - await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + await call.message.delete() if groups: for group in groups: diff --git a/tgbot/handlers/admin/show_numbers_callback.py b/tgbot/handlers/admin/show_numbers_callback.py index 75b9858..0c265cc 100644 --- a/tgbot/handlers/admin/show_numbers_callback.py +++ b/tgbot/handlers/admin/show_numbers_callback.py @@ -13,7 +13,7 @@ async def show_numbers(call: types.CallbackQuery): text = md.hbold('ID |ID Группы|Номера для поздравления\n\n') with suppress(MessageCantBeDeleted): - await call.message.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) + await call.message.delete() if groups: for group in groups: diff --git a/tgbot/handlers/admin/user.py b/tgbot/handlers/admin/user.py index a16e066..e3aa61b 100644 --- a/tgbot/handlers/admin/user.py +++ b/tgbot/handlers/admin/user.py @@ -3,7 +3,7 @@ async def user_start(message: Message): - await message.reply(f"Hello, user!") + await message.reply(f"Добрый день, у вас нет прав для конфигурирования!") def register_user(dp: Dispatcher): diff --git a/tgbot/handlers/groups/catch_update.py b/tgbot/handlers/groups/catch_update.py index bd783ff..8d5fba8 100644 --- a/tgbot/handlers/groups/catch_update.py +++ b/tgbot/handlers/groups/catch_update.py @@ -1,13 +1,10 @@ from typing import List - from aiogram.utils.markdown import quote_html - from tgbot.keyboards.inline import get_gran_kb from aiogram import Dispatcher, types from aiogram.types import ChatType import uuid from tgbot.Utils.get_user_link import get_link - from tgbot.Utils.DBWorker import set_data_queue diff --git a/tgbot/handlers/groups/echo.py b/tgbot/handlers/groups/echo.py index 1b822d3..aa26706 100644 --- a/tgbot/handlers/groups/echo.py +++ b/tgbot/handlers/groups/echo.py @@ -2,8 +2,6 @@ from aiogram.dispatcher import FSMContext from aiogram.utils.markdown import hcode -from Utils.get_user_link import get_link - async def bot_echo(message: types.Message): text = [ diff --git a/tgbot/handlers/groups/get_granted.py b/tgbot/handlers/groups/get_granted.py index 358d178..39d93dd 100644 --- a/tgbot/handlers/groups/get_granted.py +++ b/tgbot/handlers/groups/get_granted.py @@ -3,8 +3,8 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType -from keyboards.inline import get_list_granted_kb -from misc.show_granted import send_granted_message +from tgbot.keyboards.inline import get_list_granted_kb +from tgbot.misc.show_granted import send_granted_message from tgbot.Utils.DBWorker import get_data_granted, get_users_groups diff --git a/tgbot/handlers/groups/grant_callback.py b/tgbot/handlers/groups/grant_callback.py index 287a650..f7ce92f 100644 --- a/tgbot/handlers/groups/grant_callback.py +++ b/tgbot/handlers/groups/grant_callback.py @@ -6,7 +6,7 @@ from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeEdited, MessageToEditNotFound, MessageNotModified -from misc.grant_text import get_great_text +from tgbot.misc.grant_text import get_great_text from tgbot.Utils.DBWorker import get_message_in_queue, get_queue, delete_from_queue, vacuum, set_data_granted, \ count_from_queue @@ -30,7 +30,7 @@ async def grant_user(call: types.CallbackQuery): chat_member = await call.bot.get_chat_member(group_id_users, user_id) if not chat_member: - await call.bot.edit_message_reply_markup(chat_id=call.message.chat.id, message_id=message_id, reply_markup=None) + await call.message.delete_reply_markup() await call.answer(text="Такого пользователя уже нет в группе", show_alert=True) raise CancelHandler() @@ -41,7 +41,7 @@ async def grant_user(call: types.CallbackQuery): await call.answer() await call.message.answer(text=f"Пользователь {user} в группе {grant_message.chat.title} поздравлен") - with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified, MessageCantBeEdited): + with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified): await call.message.delete_reply_markup() granted = [(group_id_users, grant_message.chat.title, user_id, user, group_id_mod, moder_id, count, datetime_update, @@ -50,8 +50,8 @@ async def grant_user(call: types.CallbackQuery): queue = await get_queue(group_id=group_id_users, message_id=message_id) if queue: for message in queue: - with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified, MessageCantBeEdited): - await call.bot.edit_message_reply_markup(chat_id=group_id_mod, message_id=message[1], reply_markup=None) + with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified): + await call.message.delete_reply_markup() granted.append((message[2], message[3], message[5], message[6], message[4], '', message[7], message[8], '', message[10])) diff --git a/tgbot/handlers/groups/restore.py b/tgbot/handlers/groups/restore.py index d18bbb1..7822ad9 100644 --- a/tgbot/handlers/groups/restore.py +++ b/tgbot/handlers/groups/restore.py @@ -22,7 +22,7 @@ async def restore(message: types.Message, ids: List[tuple[str]]): text = f'🎉 “{message_in_queue[3]}” 👤 {message_in_queue[6]} ({message_in_queue[10]}),\n' \ f'🔢 {message_in_queue[7]} 🕐 {message_in_queue[8]}' new_message = await message.bot.send_message(message.chat.id, text=text, - reply_markup=await get_gran_kb(uid=message_in_queue[9])) + reply_markup=get_gran_kb(uid=message_in_queue[9])) await update_data_queue(message_id=new_message.message_id, old_message_id=message_in_queue[1], group_id=message_in_queue[2]) else: diff --git a/tgbot/handlers/groups/show_granted_callback.py b/tgbot/handlers/groups/show_granted_callback.py index ad67920..ea87dcd 100644 --- a/tgbot/handlers/groups/show_granted_callback.py +++ b/tgbot/handlers/groups/show_granted_callback.py @@ -4,9 +4,9 @@ from aiogram.types import CallbackQuery, ChatType from aiogram.utils.exceptions import MessageToEditNotFound, MessageCantBeDeleted -from Utils.DBWorker import get_data_granted_for_kb -from keyboards.inline import cb -from misc.show_granted import send_granted_message +from tgbot.Utils.DBWorker import get_data_granted_for_kb +from tgbot.keyboards.inline import cb +from tgbot.misc.show_granted import send_granted_message async def show_granted_cb(call: CallbackQuery, callback_data: dict): diff --git a/tgbot/handlers/groups/show_granted_cancel_callback.py b/tgbot/handlers/groups/show_granted_cancel_callback.py index 226dd6f..0b2437e 100644 --- a/tgbot/handlers/groups/show_granted_cancel_callback.py +++ b/tgbot/handlers/groups/show_granted_cancel_callback.py @@ -2,7 +2,7 @@ from aiogram import Dispatcher from aiogram.types import CallbackQuery, ChatType from aiogram.utils.exceptions import MessageToEditNotFound, MessageCantBeDeleted -from keyboards.inline import cb +from tgbot.keyboards.inline import cb async def show_granted_cb(call: CallbackQuery, callback_data: dict): From 56c37a15699e41dd1aa1511e4869b51aec81fc7f Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Mon, 18 Jul 2022 20:21:32 +0300 Subject: [PATCH 13/16] Fix DBWorker --- bot.py | 4 +- systemd/tgbot.service | 2 +- tgbot/Utils/DBWorker.py | 106 ++++++++++-------- tgbot/handlers/admin/get_numbers.py | 2 +- tgbot/handlers/groups/catch_update.py | 2 +- tgbot/handlers/groups/grant_callback.py | 2 +- .../handlers/groups/grant_cancel_callback.py | 2 +- 7 files changed, 65 insertions(+), 55 deletions(-) diff --git a/bot.py b/bot.py index b9ac991..6e9fd14 100644 --- a/bot.py +++ b/bot.py @@ -125,6 +125,8 @@ async def main(): if __name__ == '__main__': try: - asyncio.get_event_loop().run_until_complete(main()) + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop.run_until_complete(main()) except (KeyboardInterrupt, SystemExit): logger.error("Bot stopped!") diff --git a/systemd/tgbot.service b/systemd/tgbot.service index ccf3b2c..a3fffa6 100644 --- a/systemd/tgbot.service +++ b/systemd/tgbot.service @@ -1,5 +1,5 @@ [Unit] -Description=Course Bot +Description=Сongratulate Bot After=network.target [Service] diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index db9e4e4..0d9b015 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -10,18 +10,17 @@ async def db_execute(string, values=None, multiple=False, get=False) -> bool: async with db.executemany(string, values) as cursor: await db.commit() return cursor.rowcount + elif get: + async with db.execute(string, values) as cursor: + return await cursor.fetchall() elif values: async with db.execute(string, values) as cursor: await db.commit() return cursor.rowcount else: - if get: - async with db.execute(string) as cursor: - return await cursor.fetchall() - else: - async with db.execute(string) as cursor: - await db.commit() - return cursor.rowcount + async with db.execute(string) as cursor: + await db.commit() + return cursor.rowcount async def create_tables() -> None: @@ -73,112 +72,121 @@ async def create_tables() -> None: async def get_users_groups(group_id): - return await db_execute(string=f'SELECT user_group_ids FROM groups WHERE mod_group_id={group_id}', + return await db_execute(string='SELECT user_group_ids FROM groups WHERE mod_group_id=?', values=(group_id,), get=True) async def get_moder_groups(group_id): - return await db_execute(string=f'SELECT mod_group_id FROM groups WHERE user_group_ids LIKE "%{group_id}%"', + return await db_execute(string='SELECT mod_group_id FROM groups WHERE user_group_ids LIKE ?', + values=('%'+str(group_id)+'%',), get=True) -async def set_group_ids_grant_numbers(values): - return await db_execute(string= - f"INSERT OR IGNORE INTO grant_numbers(group_id) VALUES(?);", values=values, multiple=True) +async def delete_data_from_groups(ids): + return await db_execute(string='DELETE FROM groups WHERE id=?', values=ids, multiple=True) -async def delete_data_from_groups(ids): - return await db_execute(string=f'DELETE FROM groups WHERE id=?', values=ids, multiple=True) +async def get_groups(): + return await db_execute(string='SELECT * FROM groups', get=True) + + +async def get_user_ids_from_groups(mod_group_id): + return await db_execute(string='SELECT user_group_ids FROM groups WHERE mod_group_id=?', + values=(mod_group_id,), + get=True) + + +async def set_data_groups(values): + return await db_execute(string='INSERT OR REPLACE INTO groups(mod_group_id, user_group_ids)' + ' VALUES(?, ?);', values=values) + + +async def set_group_ids_grant_numbers(values): + return await db_execute(string= + "INSERT OR IGNORE INTO grant_numbers(group_id) VALUES(?);", values=values, multiple=True) async def set_data_queue(values): return await db_execute(string= - f"INSERT INTO queue(message_id, group_id_users, name_group, group_id_mod, user_id, user, count, datetime_update, UUID, username) " - f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", values=values) + "INSERT INTO queue(message_id, group_id_users, name_group, group_id_mod, user_id, user, " + "count, datetime_update, UUID, username) " + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", values=values) async def update_data_queue(message_id, old_message_id, group_id): return await db_execute( - string=f'UPDATE queue SET message_id={message_id} WHERE message_id={old_message_id} AND ' - f'group_id_users LIKE "%{group_id}%"') + string='UPDATE queue SET message_id=? WHERE message_id=? AND ' + 'group_id_users LIKE ?', values=(message_id, old_message_id, '%'+str(group_id)+'%',)) async def set_data_granted(values): return await db_execute(string= - f"INSERT INTO granted(group_id_users, name_group, user_id, user, group_id_mod, moder_id, count, datetime_update, datetime_granted, username) " - f"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + "INSERT INTO granted(group_id_users, name_group, user_id, user, group_id_mod, moder_id, " + "count, datetime_update, datetime_granted, username) " + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", values=values, multiple=True) async def get_data_granted(group_id_moder): - return await db_execute(string=f'SELECT * FROM granted WHERE group_id_mod={group_id_moder} ORDER BY group_id_users', + return await db_execute(string='SELECT * FROM granted WHERE group_id_mod=? ORDER BY datetime_update', + values=(group_id_moder,), get=True) async def get_data_granted_for_kb(group_id_users): return await db_execute( - string=f'SELECT * FROM granted WHERE group_id_users={group_id_users} ORDER BY datetime_update', + string='SELECT * FROM granted WHERE group_id_users=? ORDER BY datetime_update', values=(group_id_users,), get=True) -async def get_count_queue(group_id): - return await db_execute(string=f"SELECT COUNT(*) FROM queue WHERE group_id_users={group_id}", get=True) - - async def check_granted(user_id, group_id): return await db_execute( - string=f"SELECT COUNT(*) FROM granted WHERE user_id={user_id} AND group_id_users={group_id}", get=True) + string="SELECT COUNT(*) FROM granted WHERE user_id=? AND group_id_users=?", values=(user_id, group_id,), + get=True) + + +async def get_count_queue(group_id): + return await db_execute(string="SELECT COUNT(*) FROM queue WHERE group_id_users=?", values=(group_id,), + get=True) async def check_queue(user_id, group_id): return await db_execute( - string=f"SELECT COUNT(*) FROM queue WHERE user_id={user_id} AND group_id_users={group_id}", get=True) + string="SELECT COUNT(*) FROM queue WHERE user_id=? AND group_id_users=?", values=(user_id, group_id,), + get=True) async def get_message_in_queue(uid): - return await db_execute(string=f"SELECT * FROM queue WHERE UUID='{uid}'", get=True) + return await db_execute(string="SELECT * FROM queue WHERE UUID=?", values=(uid,), get=True) async def get_queue(group_id, message_id=0): return await db_execute( - string=f"SELECT * FROM queue WHERE group_id_users={group_id} AND message_id!={message_id}", + string="SELECT * FROM queue WHERE group_id_users=? AND message_id!=?", values=(group_id, message_id,), get=True) async def delete_from_queue(group_id): - return await db_execute(string=f"DELETE FROM queue WHERE group_id_users={group_id}") + return await db_execute(string="DELETE FROM queue WHERE group_id_users=?", values=(group_id,)) async def count_from_queue(group_id): return await db_execute( - string=f"SELECT count FROM queue WHERE group_id_users={group_id} ORDER BY datetime_update limit 1", + string="SELECT count FROM queue WHERE group_id_users=? ORDER BY datetime_update limit 1", values=(group_id,), get=True) -async def get_groups(): - return await db_execute(string='SELECT * FROM groups', get=True) - - -async def get_user_ids_from_groups(mod_group_id): - return await db_execute(string=f'SELECT user_group_ids FROM groups WHERE mod_group_id={mod_group_id}', get=True) - - -async def set_data_groups(values): - return await db_execute(string=f'INSERT OR REPLACE INTO groups(mod_group_id, user_group_ids)' - f' VALUES(?, ?);', values=values) - - async def get_data_from_grant_numbers(group_id): - return await db_execute(string=f'SELECT numbers FROM grant_numbers WHERE group_id={group_id}', get=True) + return await db_execute(string='SELECT numbers FROM grant_numbers WHERE group_id=?', values=(group_id,), get=True) async def set_data_numbers(values): - return await db_execute(string=f'INSERT OR REPLACE INTO grant_numbers(group_id, numbers)' - f' VALUES(?, ?);', values=values) + return await db_execute(string='INSERT OR REPLACE INTO grant_numbers(group_id, numbers)' + ' VALUES(?, ?);', values=values) async def delete_data_from_grant_numbers(ids): - return await db_execute(string=f'DELETE FROM grant_numbers WHERE id=?', values=ids, multiple=True) + return await db_execute(string='DELETE FROM grant_numbers WHERE id=?', values=ids, multiple=True) async def get_numbers(): diff --git a/tgbot/handlers/admin/get_numbers.py b/tgbot/handlers/admin/get_numbers.py index 73f2f8c..adcfba2 100644 --- a/tgbot/handlers/admin/get_numbers.py +++ b/tgbot/handlers/admin/get_numbers.py @@ -24,7 +24,7 @@ async def get_grant_numbers(message: types.Message, state: FSMContext): existed = await get_data_from_grant_numbers(group_id=id_group) numbers = message.text - if existed: + if existed[0][0]: numbers += f',{existed[0][0]}' text_message = await delete_doubles_ids(message=numbers, sort=True) diff --git a/tgbot/handlers/groups/catch_update.py b/tgbot/handlers/groups/catch_update.py index 8d5fba8..b57ab9e 100644 --- a/tgbot/handlers/groups/catch_update.py +++ b/tgbot/handlers/groups/catch_update.py @@ -19,7 +19,7 @@ async def new_chat(update: types.ChatMemberUpdated, ids: List[tuple[int]], count f'{link} ({username}),\n' \ f'🔢{count}. 🕐Время вступления {update.date}' - message = await update.bot.send_message(ids[0][0], text=text, reply_markup=await get_gran_kb(uid=uid)) + message = await update.bot.send_message(ids[0][0], text=text, reply_markup=get_gran_kb(uid=uid)) await set_data_queue( values=( diff --git a/tgbot/handlers/groups/grant_callback.py b/tgbot/handlers/groups/grant_callback.py index f7ce92f..06b1618 100644 --- a/tgbot/handlers/groups/grant_callback.py +++ b/tgbot/handlers/groups/grant_callback.py @@ -51,7 +51,7 @@ async def grant_user(call: types.CallbackQuery): if queue: for message in queue: with suppress(MessageCantBeEdited, MessageToEditNotFound, MessageNotModified): - await call.message.delete_reply_markup() + await call.bot.edit_message_reply_markup(chat_id=message[4], message_id=message[1], reply_markup=None) granted.append((message[2], message[3], message[5], message[6], message[4], '', message[7], message[8], '', message[10])) diff --git a/tgbot/handlers/groups/grant_cancel_callback.py b/tgbot/handlers/groups/grant_cancel_callback.py index b164130..90e3f1f 100644 --- a/tgbot/handlers/groups/grant_cancel_callback.py +++ b/tgbot/handlers/groups/grant_cancel_callback.py @@ -14,5 +14,5 @@ async def cancel_grant_user(call: types.CallbackQuery): def register_cancel_grant(dp: Dispatcher): - chat_types = [ChatType.GROUP, ChatType.SUPERGROUP, ChatType.CHANNEL] + chat_types = [ChatType.GROUP, ChatType.SUPERGROUP] dp.register_callback_query_handler(cancel_grant_user, Text(startswith='can'), chat_type=chat_types,) From e24f32096c60d5e5bef2311355ae330514159abc Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Tue, 19 Jul 2022 19:01:24 +0300 Subject: [PATCH 14/16] Add annotation and docs --- .env.dist | 2 +- bot.py | 2 - tgbot/Utils/DBWorker.py | 178 ++++++++++++++---- tgbot/Utils/check_ids_records.py | 13 ++ tgbot/Utils/check_message_user_groups.py | 10 +- tgbot/Utils/check_number.py | 7 +- tgbot/Utils/delete_doubles.py | 8 +- tgbot/Utils/get_ids_for_grant_numbers.py | 10 +- tgbot/Utils/get_numbers.py | 11 +- tgbot/Utils/get_user_link.py | 7 +- tgbot/filters/admin.py | 3 + tgbot/filters/count.py | 8 +- tgbot/filters/granted.py | 7 +- tgbot/filters/group_join.py | 7 +- tgbot/filters/moder_group.py | 10 +- tgbot/filters/user_group.py | 11 +- tgbot/handlers/admin/add_groups_callback.py | 7 +- tgbot/handlers/admin/add_numbers_callback.py | 7 +- tgbot/handlers/admin/admin.py | 7 +- tgbot/handlers/admin/back_to_main_menu.py | 8 +- tgbot/handlers/admin/cancel.py | 8 +- .../admin/configure_groups_callback.py | 7 +- .../admin/configure_numbers_callback.py | 7 +- tgbot/handlers/admin/delete_from_groups.py | 16 +- tgbot/handlers/admin/delete_from_numbers.py | 14 +- .../handlers/admin/delete_groups_callback.py | 8 +- .../handlers/admin/delete_numbers_callback.py | 8 +- tgbot/handlers/admin/get_mod_group.py | 10 +- tgbot/handlers/admin/get_numbers.py | 11 +- tgbot/handlers/admin/get_numbers_group.py | 10 +- tgbot/handlers/admin/get_users_groups.py | 12 +- tgbot/handlers/admin/main_menu.py | 7 +- tgbot/handlers/admin/show_groups_callback.py | 11 +- tgbot/handlers/admin/show_numbers_callback.py | 13 +- tgbot/handlers/admin/user.py | 7 +- tgbot/handlers/groups/catch_update.py | 9 +- tgbot/handlers/groups/check.py | 8 +- tgbot/handlers/groups/echo.py | 28 --- tgbot/handlers/groups/get_granted.py | 9 +- tgbot/handlers/groups/grant_callback.py | 7 +- .../handlers/groups/grant_cancel_callback.py | 7 +- tgbot/handlers/groups/restore.py | 10 +- .../handlers/groups/show_granted_callback.py | 8 +- .../groups/show_granted_cancel_callback.py | 8 +- tgbot/keyboards/inline.py | 29 ++- tgbot/keyboards/reply.py | 0 tgbot/misc/grant_text.py | 8 +- tgbot/misc/set_commands.py | 9 +- tgbot/misc/show_granted.py | 8 +- 49 files changed, 480 insertions(+), 140 deletions(-) create mode 100644 tgbot/Utils/check_ids_records.py delete mode 100644 tgbot/handlers/groups/echo.py delete mode 100644 tgbot/keyboards/reply.py diff --git a/.env.dist b/.env.dist index 86d3d93..22c3f52 100644 --- a/.env.dist +++ b/.env.dist @@ -7,4 +7,4 @@ USE_REDIS=False DB_NAME=Granted.db -GRANT_NUMBER=1 +GRANT_NUMBER=500 diff --git a/bot.py b/bot.py index 6e9fd14..78ad208 100644 --- a/bot.py +++ b/bot.py @@ -33,7 +33,6 @@ from tgbot.handlers.groups.grant_cancel_callback import register_cancel_grant from tgbot.handlers.groups.grant_callback import register_grant from tgbot.handlers.groups.catch_update import register_catch -from tgbot.handlers.groups.echo import register_echo from tgbot.handlers.groups.show_granted_callback import register_show_granted_cb from tgbot.misc.set_commands import set_default_commands @@ -64,7 +63,6 @@ def register_all_filters(dp): def register_all_handlers(dp): - # register_echo(dp) register_admin(dp) register_user(dp) register_catch(dp) diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index 0d9b015..3664e3e 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -1,8 +1,11 @@ import os +from typing import List, Union + import aiosqlite -async def db_execute(string, values=None, multiple=False, get=False) -> bool: +async def db_execute(string: str, values: Union[List[tuple], tuple] = None, multiple: bool = False, + get: bool = False) -> Union[List[tuple], int]: """Функция для выполнения SQL запросов""" db_name = os.getenv('DB_NAME') async with aiosqlite.connect(db_name) as db: @@ -71,55 +74,95 @@ async def create_tables() -> None: await db_execute(string) -async def get_users_groups(group_id): +async def get_users_groups(group_id: int) -> List[tuple]: + """ + Функция для получения ids модерируемых групп из таблицы groups + :param group_id: int + :return: List[tuple] + """ return await db_execute(string='SELECT user_group_ids FROM groups WHERE mod_group_id=?', values=(group_id,), get=True) -async def get_moder_groups(group_id): +async def get_moder_groups(group_id: int) -> List[tuple]: + """ + Функция для получения ids групп модераторов из таблицы groups + :param group_id: int + :return: List[tuple] + """ return await db_execute(string='SELECT mod_group_id FROM groups WHERE user_group_ids LIKE ?', - values=('%'+str(group_id)+'%',), + values=('%' + str(group_id) + '%',), get=True) -async def delete_data_from_groups(ids): +async def delete_data_from_groups(ids: List[tuple]) -> int: + """ + Функция для удаления записей из таблицы groups + :param ids: List[tuple] + :return: int + """ return await db_execute(string='DELETE FROM groups WHERE id=?', values=ids, multiple=True) -async def get_groups(): +async def get_groups() -> List[tuple]: + """ + Функция для получения всех данных из таблицы groups + :return: List[tuple] + """ return await db_execute(string='SELECT * FROM groups', get=True) -async def get_user_ids_from_groups(mod_group_id): - return await db_execute(string='SELECT user_group_ids FROM groups WHERE mod_group_id=?', - values=(mod_group_id,), - get=True) - - -async def set_data_groups(values): +async def set_data_groups(values: tuple) -> int: + """ + Функция для вставки новой записи в таблицу groups, или замены + :param values: + :return: int + """ return await db_execute(string='INSERT OR REPLACE INTO groups(mod_group_id, user_group_ids)' ' VALUES(?, ?);', values=values) -async def set_group_ids_grant_numbers(values): +async def set_group_ids_grant_numbers(values: List[tuple]) -> int: + """ + Функция для вставки новой записи в таблицу grant_numbers, или замены + :param values: tuple + :return: int + """ return await db_execute(string= "INSERT OR IGNORE INTO grant_numbers(group_id) VALUES(?);", values=values, multiple=True) -async def set_data_queue(values): +async def set_data_queue(values: tuple) -> int: + """ + Функция для вставки новой записи в таблицу queue + :param values: tuple + :return: int + """ return await db_execute(string= "INSERT INTO queue(message_id, group_id_users, name_group, group_id_mod, user_id, user, " "count, datetime_update, UUID, username) " "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", values=values) -async def update_data_queue(message_id, old_message_id, group_id): +async def update_data_queue(message_id: int, old_message_id: int, group_id: int) -> int: + """ + Функция для обновления записи в таблице queue + :param message_id: int + :param old_message_id: int + :param group_id: int + :return: int + """ return await db_execute( string='UPDATE queue SET message_id=? WHERE message_id=? AND ' - 'group_id_users LIKE ?', values=(message_id, old_message_id, '%'+str(group_id)+'%',)) + 'group_id_users LIKE ?', values=(message_id, old_message_id, '%' + str(group_id) + '%',)) -async def set_data_granted(values): +async def set_data_granted(values: List[tuple]) -> int: + """ + Функция для вставки новых записей в таблицу granted + :param values: List[tuple] + :return: int + """ return await db_execute(string= "INSERT INTO granted(group_id_users, name_group, user_id, user, group_id_mod, moder_id, " "count, datetime_update, datetime_granted, username) " @@ -127,71 +170,142 @@ async def set_data_granted(values): values=values, multiple=True) -async def get_data_granted(group_id_moder): +async def get_data_granted(group_id_moder: int) -> List[tuple]: + """ + Функция для получения данных из таблицы granted с отбором по полю group_id_mod + :param group_id_moder: int + :return: List[tuple] + """ return await db_execute(string='SELECT * FROM granted WHERE group_id_mod=? ORDER BY datetime_update', values=(group_id_moder,), get=True) -async def get_data_granted_for_kb(group_id_users): +async def get_data_granted_for_kb(group_id_users: int) -> List[tuple]: + """ + Функция для получения данных из таблицы granted отсортированных по datetime_update и отборо по group_id_users + :param group_id_users: int + :return: List[tuple] + """ return await db_execute( string='SELECT * FROM granted WHERE group_id_users=? ORDER BY datetime_update', values=(group_id_users,), get=True) -async def check_granted(user_id, group_id): +async def check_granted(user_id: int, group_id: int) -> List[tuple]: + """ + Функция для получения данных из таблицы granted c отбором по group_id_users и user_id + :param user_id: int + :param group_id: int + :return: List[tuple] + """ return await db_execute( string="SELECT COUNT(*) FROM granted WHERE user_id=? AND group_id_users=?", values=(user_id, group_id,), get=True) -async def get_count_queue(group_id): +async def get_count_queue(group_id: int) -> List[tuple]: + """ + Функция для получения данных из таблицы queue c отбором по group_id_users + :param group_id: int + :return: List[tuple] + """ return await db_execute(string="SELECT COUNT(*) FROM queue WHERE group_id_users=?", values=(group_id,), get=True) -async def check_queue(user_id, group_id): +async def check_queue(user_id: int, group_id: int) -> List[tuple]: + """ + Функция для получения кол-ва существующих записей с отбором по user_id и group_id_users + :param user_id: int + :param group_id: int + :return: List[tuple] + """ return await db_execute( string="SELECT COUNT(*) FROM queue WHERE user_id=? AND group_id_users=?", values=(user_id, group_id,), get=True) -async def get_message_in_queue(uid): +async def get_message_in_queue(uid: str) -> List[tuple]: + """ + Функция для получения все данных из таблицы queue с отбором по UUID + :param uid: str + :return: List[tuple] + """ return await db_execute(string="SELECT * FROM queue WHERE UUID=?", values=(uid,), get=True) -async def get_queue(group_id, message_id=0): +async def get_queue(group_id: int, message_id: int = 0) -> List[tuple]: + """ + Функция для получения всех данных из таблицы queue с отбором по group_id_users и message_id + :param group_id: int + :param message_id: int + :return: List[tuple] + """ return await db_execute( string="SELECT * FROM queue WHERE group_id_users=? AND message_id!=?", values=(group_id, message_id,), get=True) -async def delete_from_queue(group_id): +async def delete_from_queue(group_id: int) -> List[tuple]: + """ + Функция для получения все данных из таблицы queue с отбором по group_id_users + :param group_id: int + :return: List[tuple] + """ return await db_execute(string="DELETE FROM queue WHERE group_id_users=?", values=(group_id,)) -async def count_from_queue(group_id): +async def count_from_queue(group_id: int) -> List[tuple]: + """ + Функция для проверки существования записи с отбором по group_id_users + :param group_id: int + :return: List[tuple] + """ return await db_execute( string="SELECT count FROM queue WHERE group_id_users=? ORDER BY datetime_update limit 1", values=(group_id,), get=True) -async def get_data_from_grant_numbers(group_id): +async def get_data_from_grant_numbers(group_id: int) -> List[tuple]: + """ + Функция для получения поля numbers из таблицы grant_numbers с отбором по group_id + :param group_id: int + :return: List[tuple] + """ return await db_execute(string='SELECT numbers FROM grant_numbers WHERE group_id=?', values=(group_id,), get=True) -async def set_data_numbers(values): +async def set_data_numbers(values: tuple) -> int: + """ + Функция для вставки новой записи в grant_numbers, или замены существующей + :param values: tuple + :return: int + """ return await db_execute(string='INSERT OR REPLACE INTO grant_numbers(group_id, numbers)' ' VALUES(?, ?);', values=values) -async def delete_data_from_grant_numbers(ids): +async def delete_data_from_grant_numbers(ids: List[tuple]) -> int: + """ + Функция для удаления записей из grant_numbers с отбором по id + :param ids: List[tuple] + :return: int + """ return await db_execute(string='DELETE FROM grant_numbers WHERE id=?', values=ids, multiple=True) -async def get_numbers(): +async def get_numbers() -> List[tuple]: + """ + Функция для получения всех данных из grant_numbers + :return: List[tuple] + """ return await db_execute(string='SELECT * FROM grant_numbers', get=True) -async def vacuum(): +async def vacuum() -> int: + """ + Пылесос:) + :return: int + """ return await db_execute(string="VACUUM") diff --git a/tgbot/Utils/check_ids_records.py b/tgbot/Utils/check_ids_records.py new file mode 100644 index 0000000..9c265e9 --- /dev/null +++ b/tgbot/Utils/check_ids_records.py @@ -0,0 +1,13 @@ +from tgbot.Utils.check_number import check_number_in_message + + +async def check_ids(message: str) -> bool: + """ + Функция для проверки ids записей на корректность + :param message: str + :return: bool + """ + users_groups_ids = message.split(',') + for number in users_groups_ids: + if await check_number_in_message(number=number): + return True diff --git a/tgbot/Utils/check_message_user_groups.py b/tgbot/Utils/check_message_user_groups.py index 6226548..04cb566 100644 --- a/tgbot/Utils/check_message_user_groups.py +++ b/tgbot/Utils/check_message_user_groups.py @@ -1,10 +1,14 @@ from tgbot.Utils.check_number import check_number_in_message -async def check_users_groups(message: str): - +async def check_users_groups(message: str) -> bool: + """ + Функция для проверки ids групп на корректность + :param message: str + :return: bool + """ users_groups_ids = message.split(',') for number in users_groups_ids: - if await check_number_in_message(number=number): + if await check_number_in_message(number=number) and len(number) > 4: return True diff --git a/tgbot/Utils/check_number.py b/tgbot/Utils/check_number.py index 0b884e9..7e92e0f 100644 --- a/tgbot/Utils/check_number.py +++ b/tgbot/Utils/check_number.py @@ -1,4 +1,9 @@ -async def check_number_in_message(number: str): +async def check_number_in_message(number: str) -> int: + """ + Функция для проверки ids групп на целое число + :param number: str + :return: int + """ if number[:1] == '-': if number[1:].isdigit(): return int(number) diff --git a/tgbot/Utils/delete_doubles.py b/tgbot/Utils/delete_doubles.py index 3664923..5af2874 100644 --- a/tgbot/Utils/delete_doubles.py +++ b/tgbot/Utils/delete_doubles.py @@ -1,4 +1,10 @@ -async def delete_doubles_ids(message: str, sort=False): +async def delete_doubles_ids(message: str, sort: bool = False) -> str: + """ + Функция для удаления дублей из строки с ids групп и сортировки если необходимо + :param message: str + :param sort: + :return: str + """ without_doubles = set(message.replace(' ', '').split(',')) if sort: for_sorts = map(int, without_doubles) diff --git a/tgbot/Utils/get_ids_for_grant_numbers.py b/tgbot/Utils/get_ids_for_grant_numbers.py index ca36ea0..0387b57 100644 --- a/tgbot/Utils/get_ids_for_grant_numbers.py +++ b/tgbot/Utils/get_ids_for_grant_numbers.py @@ -1,2 +1,10 @@ -async def get_ids_for_multiple_record(ids: str): +from typing import List + + +async def get_ids_for_multiple_record(ids: str) -> List[tuple]: + """ + Функция формирует список с кортежами с ids групп для работы с БД + :param ids: str + :return: List[tuple] + """ return [(group_id,) for group_id in ids.split(',')] diff --git a/tgbot/Utils/get_numbers.py b/tgbot/Utils/get_numbers.py index a40d41b..9e4f9c5 100644 --- a/tgbot/Utils/get_numbers.py +++ b/tgbot/Utils/get_numbers.py @@ -1,8 +1,15 @@ +from typing import List + from tgbot.Utils.DBWorker import get_data_from_grant_numbers -async def get_grant_numbers(group_id): - numbers = await get_data_from_grant_numbers(group_id) +async def get_grant_numbers(group_id: int) -> List[int]: + """ + Возвращает данные о юбилейных пользователях для фильтра + :param group_id: int + :return: List[int] + """ + numbers = await get_data_from_grant_numbers(group_id=group_id) if not numbers[0][0]: return [] return [int(number) for number in numbers[0][0].split(',')] diff --git a/tgbot/Utils/get_user_link.py b/tgbot/Utils/get_user_link.py index 4ac0b65..d5a8235 100644 --- a/tgbot/Utils/get_user_link.py +++ b/tgbot/Utils/get_user_link.py @@ -3,7 +3,12 @@ from aiogram.utils.markdown import quote_html -async def get_link(user: types.User): +async def get_link(user: types.User) -> str: + """ + Возвращает ссылку с пользователем для вывода сообщения + :param user: types.User + :return: str + """ if not user.url: return 'пользователь' if user.first_name: diff --git a/tgbot/filters/admin.py b/tgbot/filters/admin.py index 02422a5..0c3dc9c 100644 --- a/tgbot/filters/admin.py +++ b/tgbot/filters/admin.py @@ -6,6 +6,9 @@ class AdminFilter(BoundFilter): + """ + Класс фильтра, проверяет доступ к админке бота + """ key = 'is_admin' def __init__(self, is_admin: typing.Optional[bool] = None): diff --git a/tgbot/filters/count.py b/tgbot/filters/count.py index 5ee48f1..c9a0023 100644 --- a/tgbot/filters/count.py +++ b/tgbot/filters/count.py @@ -7,13 +7,17 @@ class IsGrantCount(BoundFilter): - key = "is_grant_count" def __init__(self, is_grant_count: bool): self.is_grant_count = is_grant_count - async def check(self, update: types.ChatMemberUpdated): + async def check(self, update: types.ChatMemberUpdated) -> dict: + """ + Метод фильтра, проверяет попадание нового пользователя в счастливчики, возвращает текущий номер вступившего + :param update: types.ChatMemberUpdated + :return: dict + """ config_count = update.bot.data['config'].misc.grant_count if not config_count: raise CancelHandler() diff --git a/tgbot/filters/granted.py b/tgbot/filters/granted.py index 955264b..ba1a874 100644 --- a/tgbot/filters/granted.py +++ b/tgbot/filters/granted.py @@ -10,7 +10,12 @@ class IsNotGranted(BoundFilter): def __init__(self, is_not_granted: bool): self.is_not_granted = is_not_granted - async def check(self, update: types.ChatMemberUpdated): + async def check(self, update: types.ChatMemberUpdated) -> bool: + """ + Проверяет наличие нового пользователя в таблицах награжденных или в очереди + :param update: types.ChatMemberUpdated + :return: bool + """ granted = await check_granted(user_id=update.new_chat_member.user.id, group_id=update.chat.id) if granted[0][0]: return False diff --git a/tgbot/filters/group_join.py b/tgbot/filters/group_join.py index 0c99b8a..67e6993 100644 --- a/tgbot/filters/group_join.py +++ b/tgbot/filters/group_join.py @@ -8,5 +8,10 @@ class IsGroupJoin(BoundFilter): def __init__(self, is_group_join: bool): self.is_group_join = is_group_join - async def check(self, update: types.ChatMemberUpdated): + async def check(self, update: types.ChatMemberUpdated) -> bool: + """ + Проверяет Update на событие присоединение нового пользователя + :param update: + :return: bool + """ return update.new_chat_member.is_chat_member() diff --git a/tgbot/filters/moder_group.py b/tgbot/filters/moder_group.py index bb55ff5..f5410df 100644 --- a/tgbot/filters/moder_group.py +++ b/tgbot/filters/moder_group.py @@ -5,15 +5,17 @@ class IsModerGroup(BoundFilter): - """ - Фильтр для проверки наличия назначенных групп пользователей и получения их id - """ key = "is_moder_group" def __init__(self, is_moder_group: bool): self.is_moder_group = is_moder_group - async def check(self, message: types.Message): + async def check(self, message: types.Message) -> dict: + """ + Фильтр для проверки группы в списке модераторских и получения ids связанных модерируемых групп + :param message: types.Message + :return: dict + """ ids = await get_users_groups(message.chat.id) if ids: return {"ids": ids} diff --git a/tgbot/filters/user_group.py b/tgbot/filters/user_group.py index d65afa9..67f7b00 100644 --- a/tgbot/filters/user_group.py +++ b/tgbot/filters/user_group.py @@ -5,15 +5,18 @@ class IsUserGroup(BoundFilter): - """ - Фильтр для проверки наличия назначенных групп модераторов и получения их id - """ + key = "is_user_group" def __init__(self, is_user_group: bool): self.is_user_group = is_user_group - async def check(self, update: types.ChatMemberUpdated): + async def check(self, update: types.ChatMemberUpdated) -> dict: + """ + Фильтр для проверки наличия назначенных групп модераторов и получения их id + :param update: types.ChatMemberUpdated + :return: dict + """ ids = await get_moder_groups(update.chat.id) if ids: return {"ids": ids} diff --git a/tgbot/handlers/admin/add_groups_callback.py b/tgbot/handlers/admin/add_groups_callback.py index 74f9382..55fd95c 100644 --- a/tgbot/handlers/admin/add_groups_callback.py +++ b/tgbot/handlers/admin/add_groups_callback.py @@ -5,7 +5,12 @@ from tgbot.misc.states import Configure -async def add_groups(call: types.CallbackQuery): +async def add_groups(call: types.CallbackQuery) -> None: + """ + Функция коллбека для добавления записи в таблицу groups + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeDeleted): await call.bot.delete_message(message_id=call.message.message_id, chat_id=call.message.chat.id) diff --git a/tgbot/handlers/admin/add_numbers_callback.py b/tgbot/handlers/admin/add_numbers_callback.py index 7edf012..4409315 100644 --- a/tgbot/handlers/admin/add_numbers_callback.py +++ b/tgbot/handlers/admin/add_numbers_callback.py @@ -5,7 +5,12 @@ from tgbot.misc.states import Configure -async def add_numbers(call: types.CallbackQuery): +async def add_numbers(call: types.CallbackQuery) -> None: + """ + Функция коллбека для добавления записи в таблицу numbers + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeDeleted): await call.message.delete() diff --git a/tgbot/handlers/admin/admin.py b/tgbot/handlers/admin/admin.py index 1b0728c..66d452e 100644 --- a/tgbot/handlers/admin/admin.py +++ b/tgbot/handlers/admin/admin.py @@ -2,7 +2,12 @@ from aiogram.types import Message -async def admin_start(message: Message): +async def admin_start(message: Message) -> None: + """ + Если админ отправляет команду /start, бот здоровается и предлагает воспользоваться меню + :param message: Message + :return: None + """ await message.reply("Добрый день! Конфигурация доступна из меню.") diff --git a/tgbot/handlers/admin/back_to_main_menu.py b/tgbot/handlers/admin/back_to_main_menu.py index 2cc0f4b..0ea2ad3 100644 --- a/tgbot/handlers/admin/back_to_main_menu.py +++ b/tgbot/handlers/admin/back_to_main_menu.py @@ -6,7 +6,13 @@ from tgbot.keyboards.inline import get_main_menu_kb -async def back_to_main(call: types.CallbackQuery, state: FSMContext): +async def back_to_main(call: types.CallbackQuery, state: FSMContext) -> None: + """ + Функция коллбэка для возрврата в главное меню и сброса состояний + :param call: types.CallbackQuery + :param state: FSMContext + :return: None + """ with suppress(MessageCantBeEdited): await call.message.edit_text(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=get_main_menu_kb()) await state.finish() diff --git a/tgbot/handlers/admin/cancel.py b/tgbot/handlers/admin/cancel.py index d315b2f..ab50c59 100644 --- a/tgbot/handlers/admin/cancel.py +++ b/tgbot/handlers/admin/cancel.py @@ -4,8 +4,12 @@ from aiogram.utils.exceptions import MessageCantBeDeleted - -async def cancel_menu(call: types.CallbackQuery): +async def cancel_menu(call: types.CallbackQuery) -> None: + """ + Функция колльека для закрытия главного меню + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeDeleted): await call.message.delete() diff --git a/tgbot/handlers/admin/configure_groups_callback.py b/tgbot/handlers/admin/configure_groups_callback.py index f944694..946e3c3 100644 --- a/tgbot/handlers/admin/configure_groups_callback.py +++ b/tgbot/handlers/admin/configure_groups_callback.py @@ -7,7 +7,12 @@ from tgbot.keyboards.inline import get_conf_groups_kb -async def configure_groups(call: types.CallbackQuery): +async def configure_groups(call: types.CallbackQuery) -> None: + """ + Функция коллбека для вызова меню конфигурирования таблицы соответствия групп + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeEdited): await call.message.edit_text(text='⚙ Настройка таблицы соответствия групп ⚙', reply_markup=get_conf_groups_kb()) diff --git a/tgbot/handlers/admin/configure_numbers_callback.py b/tgbot/handlers/admin/configure_numbers_callback.py index 8c09a7e..e8a2c62 100644 --- a/tgbot/handlers/admin/configure_numbers_callback.py +++ b/tgbot/handlers/admin/configure_numbers_callback.py @@ -7,7 +7,12 @@ from tgbot.keyboards.inline import get_conf_numbers_kb -async def configure_numbers(call: types.CallbackQuery): +async def configure_numbers(call: types.CallbackQuery) -> None: + """ + Функция коллбека для вызова меню конфигурирования таблицы таблицы с поздр. номерами + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeEdited): await call.message.edit_text(text='⚙ Настройка таблицы с поздр. номерами ⚙', reply_markup=get_conf_numbers_kb()) diff --git a/tgbot/handlers/admin/delete_from_groups.py b/tgbot/handlers/admin/delete_from_groups.py index d5065ff..cdb3f9c 100644 --- a/tgbot/handlers/admin/delete_from_groups.py +++ b/tgbot/handlers/admin/delete_from_groups.py @@ -3,20 +3,26 @@ from aiogram.types import ChatType from tgbot.Utils.DBWorker import delete_data_from_groups, vacuum -from tgbot.Utils.check_message_user_groups import check_users_groups +from tgbot.Utils.check_ids_records import check_ids from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record from tgbot.keyboards.inline import get_conf_groups_kb from tgbot.misc.states import Configure -async def delete_from_groups(message: types.Message, state: FSMContext): +async def delete_from_groups(message: types.Message, state: FSMContext) -> None: + """ + Функция для удаления записей из таблицы групп + :param message: types.Message + :param state: FSMContext + :return: None + """ if message.text == '/reset': await state.finish() return - group_id = await check_users_groups(message.text) - if not group_id: - await message.answer('Введите IDs групп модераторов для удаления записей из базы, целые числа, ' + record_id = await check_ids(message.text) + if not record_id: + await message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') return ids = await get_ids_for_multiple_record(message.text) diff --git a/tgbot/handlers/admin/delete_from_numbers.py b/tgbot/handlers/admin/delete_from_numbers.py index 3d6037f..14c714a 100644 --- a/tgbot/handlers/admin/delete_from_numbers.py +++ b/tgbot/handlers/admin/delete_from_numbers.py @@ -3,19 +3,25 @@ from aiogram.types import ChatType from tgbot.Utils.DBWorker import delete_data_from_grant_numbers, vacuum -from tgbot.Utils.check_message_user_groups import check_users_groups +from tgbot.Utils.check_ids_records import check_ids from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record from tgbot.keyboards.inline import get_conf_numbers_kb from tgbot.misc.states import Configure -async def delete_numbers(message: types.Message, state: FSMContext): +async def delete_numbers(message: types.Message, state: FSMContext) -> None: + """ + Функция для удаления записей из таблицы c поздр. номерами + :param message: types.Message + :param state: FSMContext + :return: None + """ if message.text == '/reset': await state.finish() return - group_id = await check_users_groups(message.text) - if not group_id: + record_id = await check_ids(message.text) + if not record_id: await message.answer('Введите IDs строк для удаления записей из базы, целые числа, ' 'если нужно удалить несколько, вводите через запятую (/reset для сброса)') return diff --git a/tgbot/handlers/admin/delete_groups_callback.py b/tgbot/handlers/admin/delete_groups_callback.py index 0f5e0f4..6e10af8 100644 --- a/tgbot/handlers/admin/delete_groups_callback.py +++ b/tgbot/handlers/admin/delete_groups_callback.py @@ -1,6 +1,5 @@ from contextlib import suppress -from aiogram import md from aiogram import Dispatcher, types from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeDeleted @@ -8,7 +7,12 @@ from tgbot.misc.states import Configure -async def delete_groups(call: types.CallbackQuery): +async def delete_groups(call: types.CallbackQuery) -> None: + """ + Функция коллбека для удаления записей из таблицы соотв. групп + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeDeleted): await call.message.delete() diff --git a/tgbot/handlers/admin/delete_numbers_callback.py b/tgbot/handlers/admin/delete_numbers_callback.py index b4a1ded..f481a2b 100644 --- a/tgbot/handlers/admin/delete_numbers_callback.py +++ b/tgbot/handlers/admin/delete_numbers_callback.py @@ -1,6 +1,5 @@ from contextlib import suppress -from aiogram import md from aiogram import Dispatcher, types from aiogram.types import ChatType from aiogram.utils.exceptions import MessageCantBeDeleted @@ -8,7 +7,12 @@ from tgbot.misc.states import Configure -async def delete_numbers(call: types.CallbackQuery): +async def delete_numbers(call: types.CallbackQuery) -> None: + """ + Функция коллбека для удаления записей из таблицы c поздр. номерами + :param call: types.CallbackQuery + :return: None + """ with suppress(MessageCantBeDeleted): await call.message.delete() diff --git a/tgbot/handlers/admin/get_mod_group.py b/tgbot/handlers/admin/get_mod_group.py index e52af84..d01d864 100644 --- a/tgbot/handlers/admin/get_mod_group.py +++ b/tgbot/handlers/admin/get_mod_group.py @@ -7,12 +7,18 @@ from tgbot.misc.states import Configure -async def get_mod_group(message: types.Message, state: FSMContext): +async def get_mod_group(message: types.Message, state: FSMContext) -> None: + """ + Функция доя получения ID группы модераторов при добавлениий новой записи в таблицу соотв. групп + :param message: types.Message + :param state: FSMContext + :return: None + """ if message.text == '/reset': await state.finish() return group_id = await check_number_in_message(message.text) - if not group_id: + if not group_id or len(message.text) < 5: await message.answer('Введите id группы модераторов, целое число (/reset для сброса)') return diff --git a/tgbot/handlers/admin/get_numbers.py b/tgbot/handlers/admin/get_numbers.py index adcfba2..5cc4512 100644 --- a/tgbot/handlers/admin/get_numbers.py +++ b/tgbot/handlers/admin/get_numbers.py @@ -2,6 +2,7 @@ from aiogram.dispatcher import FSMContext from aiogram.types import ChatType +from tgbot.Utils.check_ids_records import check_ids from tgbot.Utils.check_message_user_groups import check_users_groups from tgbot.Utils.delete_doubles import delete_doubles_ids from tgbot.keyboards.inline import get_conf_numbers_kb @@ -9,11 +10,17 @@ from tgbot.Utils.DBWorker import get_data_from_grant_numbers, set_data_numbers -async def get_grant_numbers(message: types.Message, state: FSMContext): +async def get_grant_numbers(message: types.Message, state: FSMContext) -> None: + """ + Функция для ввода номеров для поздрв. для записи в таблицу БД + :param message: types.Message + :param state: FSMContext + :return: None + """ if message.text == '/reset': await state.finish() return - group_ids_check = await check_users_groups(message.text) + group_ids_check = await check_ids(message.text) if not group_ids_check: await message.answer('Введите номера для поздравления, несколько номеров' diff --git a/tgbot/handlers/admin/get_numbers_group.py b/tgbot/handlers/admin/get_numbers_group.py index 3092cd0..73ef1cb 100644 --- a/tgbot/handlers/admin/get_numbers_group.py +++ b/tgbot/handlers/admin/get_numbers_group.py @@ -7,12 +7,18 @@ from tgbot.misc.states import Configure -async def get_numbers_group(message: types.Message, state: FSMContext): +async def get_numbers_group(message: types.Message, state: FSMContext) -> None: + """ + Функция для ввода групп пользователей для записи в таблицу БД + :param message: types.Message + :param state: FSMContext + :return: None + """ if message.text == '/reset': await state.finish() return group_id = await check_number_in_message(message.text) - if not group_id: + if not group_id or len(message.text) < 5: await message.answer('Введите id группы, целое число (/reset для сброса)') return diff --git a/tgbot/handlers/admin/get_users_groups.py b/tgbot/handlers/admin/get_users_groups.py index 2777ef5..6a15a78 100644 --- a/tgbot/handlers/admin/get_users_groups.py +++ b/tgbot/handlers/admin/get_users_groups.py @@ -7,10 +7,16 @@ from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record from tgbot.keyboards.inline import get_conf_groups_kb from tgbot.misc.states import Configure -from tgbot.Utils.DBWorker import set_data_groups, get_user_ids_from_groups, set_group_ids_grant_numbers +from tgbot.Utils.DBWorker import set_data_groups, set_group_ids_grant_numbers, get_users_groups -async def get_users_group(message: types.Message, state: FSMContext): +async def get_users_group(message: types.Message, state: FSMContext) -> None: + """ + Функция для получения IDs групп пользователей, для таблицы соответствия групп + :param message: types.Message + :param state: FSMContext + :return: None + """ if message.text == '/reset': await state.finish() return @@ -23,7 +29,7 @@ async def get_users_group(message: types.Message, state: FSMContext): data = await state.get_data() id_mod_group = data.get('id_mod') - existed = await get_user_ids_from_groups(mod_group_id=id_mod_group) + existed = await get_users_groups(group_id=id_mod_group) ids_user_groups = message.text if existed: ids_user_groups += f',{existed[0][0]}' diff --git a/tgbot/handlers/admin/main_menu.py b/tgbot/handlers/admin/main_menu.py index d844199..33a4f83 100644 --- a/tgbot/handlers/admin/main_menu.py +++ b/tgbot/handlers/admin/main_menu.py @@ -3,7 +3,12 @@ from tgbot.keyboards.inline import get_main_menu_kb -async def main_menu(message: types.Message): +async def main_menu(message: types.Message) -> None: + """ + Функция для вызова главного меню при отправке комманды /configure + :param message: types.Message + :return: None + """ await message.answer(text='⚙ ГЛАВНОЕ МЕНЮ ⚙', reply_markup=get_main_menu_kb()) diff --git a/tgbot/handlers/admin/show_groups_callback.py b/tgbot/handlers/admin/show_groups_callback.py index 2914fde..9e1b5e2 100644 --- a/tgbot/handlers/admin/show_groups_callback.py +++ b/tgbot/handlers/admin/show_groups_callback.py @@ -8,16 +8,21 @@ from tgbot.Utils.DBWorker import get_groups -async def show_groups(call: types.CallbackQuery): +async def show_groups(call: types.CallbackQuery) -> None: + """ + Функция коллбека для показа данных из таблицы соответствия groups + :param call: types.CallbackQuery + :return: None + """ groups = await get_groups() - text = md.hbold('ID | Группа модераторов | Группы пользователей\n\n') + text = md.hbold('| ID | Группа модераторов | Группы пользователей |\n\n') with suppress(MessageCantBeDeleted): await call.message.delete() if groups: for group in groups: - text += md.hunderline(f'{group[0]} | {group[1]} | {group[2]} |\n') + text += md.hunderline(f'| {group[0]} | {group[1]} | {group[2]} |\n') await call.message.answer(text=text) else: await call.message.answer(text='Таблица еще пуста') diff --git a/tgbot/handlers/admin/show_numbers_callback.py b/tgbot/handlers/admin/show_numbers_callback.py index 0c265cc..819b34b 100644 --- a/tgbot/handlers/admin/show_numbers_callback.py +++ b/tgbot/handlers/admin/show_numbers_callback.py @@ -8,16 +8,21 @@ from tgbot.Utils.DBWorker import get_numbers -async def show_numbers(call: types.CallbackQuery): +async def show_numbers(call: types.CallbackQuery) -> None: + """ + Функция коллбека для показа данных из таблицы с позд. номерами grant_numbers + :param call: types.CallbackQuery + :return: None + """ groups = await get_numbers() - text = md.hbold('ID |ID Группы|Номера для поздравления\n\n') + text = md.hbold('| ID | ID Группы | Номера для поздравления |\n\n') with suppress(MessageCantBeDeleted): await call.message.delete() if groups: for group in groups: - text += md.hunderline(f'{group[0]} | {group[1]} | {group[2]} |\n') + text += md.hunderline(f'| {group[0]} | {group[1]} | {group[2]} |\n') await call.message.answer(text=text) else: await call.message.answer(text='Таблица еще пуста') @@ -29,4 +34,4 @@ def register_show_numbers(dp: Dispatcher): chat_type=chat_types, text='show_numbers', state="*", - is_admin=True) \ No newline at end of file + is_admin=True) diff --git a/tgbot/handlers/admin/user.py b/tgbot/handlers/admin/user.py index e3aa61b..06b6024 100644 --- a/tgbot/handlers/admin/user.py +++ b/tgbot/handlers/admin/user.py @@ -2,7 +2,12 @@ from aiogram.types import Message -async def user_start(message: Message): +async def user_start(message: Message) -> None: + """ + Функция отправляет приветствие и сообщает, что у пользователя нет прав для конфигурирования + :param message: Message + :return: None + """ await message.reply(f"Добрый день, у вас нет прав для конфигурирования!") diff --git a/tgbot/handlers/groups/catch_update.py b/tgbot/handlers/groups/catch_update.py index b57ab9e..ce40edc 100644 --- a/tgbot/handlers/groups/catch_update.py +++ b/tgbot/handlers/groups/catch_update.py @@ -8,7 +8,14 @@ from tgbot.Utils.DBWorker import set_data_queue -async def new_chat(update: types.ChatMemberUpdated, ids: List[tuple[int]], count: int): +async def new_chat(update: types.ChatMemberUpdated, ids: List[tuple[int]], count: int) -> None: + """ + Функция для отлова события присоеднинения новго пользователя к модерируемой группе + :param update: types.ChatMemberUpdated + :param ids: List[tuple[int]] + :param count: int + :return: None + """ link = await get_link(update.new_chat_member.user) uid = str(uuid.uuid4()) if update.new_chat_member.user.username: diff --git a/tgbot/handlers/groups/check.py b/tgbot/handlers/groups/check.py index 280fcd5..b625b63 100644 --- a/tgbot/handlers/groups/check.py +++ b/tgbot/handlers/groups/check.py @@ -4,7 +4,13 @@ from tgbot.Utils.DBWorker import get_queue -async def check_queue(message: types.Message, ids: List[tuple[str]]): +async def check_queue(message: types.Message, ids: List[tuple]) -> None: + """ + Функция для проверки очереди на поздравление, комманда /проверка, доступна только в модераторских группах + :param message: types.Message + :param ids: List[tuple] + :return: None + """ users_groups_ids = ids[0][0].split(',') for group_id in users_groups_ids: diff --git a/tgbot/handlers/groups/echo.py b/tgbot/handlers/groups/echo.py deleted file mode 100644 index aa26706..0000000 --- a/tgbot/handlers/groups/echo.py +++ /dev/null @@ -1,28 +0,0 @@ -from aiogram import types, Dispatcher -from aiogram.dispatcher import FSMContext -from aiogram.utils.markdown import hcode - - -async def bot_echo(message: types.Message): - text = [ - "Эхо без состояния.", - "Сообщение:", - message.text, - ] - - await message.answer('\n'.join(text)) - - -async def bot_echo_all(message: types.Message, state: FSMContext): - state_name = await state.get_state() - text = [ - f'Эхо в состоянии {hcode(state_name)}', - 'Содержание сообщения:', - hcode(message.text) - ] - await message.answer('\n'.join(text)) - - -def register_echo(dp: Dispatcher): - dp.register_message_handler(bot_echo) - dp.register_message_handler(bot_echo_all, state="*", content_types=types.ContentTypes.ANY) diff --git a/tgbot/handlers/groups/get_granted.py b/tgbot/handlers/groups/get_granted.py index 39d93dd..b26f514 100644 --- a/tgbot/handlers/groups/get_granted.py +++ b/tgbot/handlers/groups/get_granted.py @@ -8,7 +8,14 @@ from tgbot.Utils.DBWorker import get_data_granted, get_users_groups -async def get_granted(message: types.Message, ids: List[tuple[str]], state: FSMContext): +async def get_granted(message: types.Message, ids: List[tuple], state: FSMContext) -> None: + """ + Функция для показа поздравленных пользователей, комманда /списокЮбилейный, доступна только в модераторских группах + :param message: types.Message + :param ids: List[tuple] + :param state: FSMContext + :return: None + """ granted_list = await get_data_granted(message.chat.id) if granted_list: user_groups_ids = {id_user_gr[1]: id_user_gr[2] for id_user_gr in granted_list} diff --git a/tgbot/handlers/groups/grant_callback.py b/tgbot/handlers/groups/grant_callback.py index 06b1618..ea501ed 100644 --- a/tgbot/handlers/groups/grant_callback.py +++ b/tgbot/handlers/groups/grant_callback.py @@ -11,7 +11,12 @@ count_from_queue -async def grant_user(call: types.CallbackQuery): +async def grant_user(call: types.CallbackQuery) -> None: + """ + Функция коллбека для поздравления пользователя + :param call: types.CallbackQuery + :return: None + """ uid = call.data.split('|')[1] message_btn = await get_message_in_queue(uid) if not message_btn: diff --git a/tgbot/handlers/groups/grant_cancel_callback.py b/tgbot/handlers/groups/grant_cancel_callback.py index 90e3f1f..386367d 100644 --- a/tgbot/handlers/groups/grant_cancel_callback.py +++ b/tgbot/handlers/groups/grant_cancel_callback.py @@ -5,7 +5,12 @@ from tgbot.Utils.DBWorker import get_message_in_queue -async def cancel_grant_user(call: types.CallbackQuery): +async def cancel_grant_user(call: types.CallbackQuery) -> None: + """ + Функция коллбека, убирает кнопку поздравления пользователя + :param call: types.CallbackQuery + :return: None + """ uid = call.data.split('|')[1] message = await get_message_in_queue(uid) await call.answer() diff --git a/tgbot/handlers/groups/restore.py b/tgbot/handlers/groups/restore.py index 7822ad9..d716496 100644 --- a/tgbot/handlers/groups/restore.py +++ b/tgbot/handlers/groups/restore.py @@ -10,11 +10,17 @@ from tgbot.Utils.DBWorker import get_queue, update_data_queue -async def restore(message: types.Message, ids: List[tuple[str]]): +async def restore(message: types.Message, ids: List[tuple]) -> None: + """ + Функция для повторной отправки сообщений с кнопками для поздр. в группу модераторов + :param message: types.Message + :param ids: List[tuple] + :return: None + """ users_groups_ids = ids[0][0].split(',') for group_id in users_groups_ids: - messages_in_queue = await get_queue(group_id) + messages_in_queue = await get_queue(int(group_id)) if messages_in_queue: for message_in_queue in messages_in_queue: with suppress(MessageToDeleteNotFound, MessageCantBeDeleted): diff --git a/tgbot/handlers/groups/show_granted_callback.py b/tgbot/handlers/groups/show_granted_callback.py index ea87dcd..4c9959e 100644 --- a/tgbot/handlers/groups/show_granted_callback.py +++ b/tgbot/handlers/groups/show_granted_callback.py @@ -9,7 +9,13 @@ from tgbot.misc.show_granted import send_granted_message -async def show_granted_cb(call: CallbackQuery, callback_data: dict): +async def show_granted_cb(call: CallbackQuery, callback_data: dict) -> None: + """ + Функция коллбека, для фабрики коллбеков, для показа юбилейных пользователей + :param call: CallbackQuery + :param callback_data: dict + :return: None + """ id_group = callback_data["ids"] granted_list = await get_data_granted_for_kb(id_group) with suppress(MessageCantBeDeleted, MessageToEditNotFound): diff --git a/tgbot/handlers/groups/show_granted_cancel_callback.py b/tgbot/handlers/groups/show_granted_cancel_callback.py index 0b2437e..843b20b 100644 --- a/tgbot/handlers/groups/show_granted_cancel_callback.py +++ b/tgbot/handlers/groups/show_granted_cancel_callback.py @@ -5,7 +5,13 @@ from tgbot.keyboards.inline import cb -async def show_granted_cb(call: CallbackQuery, callback_data: dict): +async def show_granted_cb(call: CallbackQuery, callback_data: dict) -> None: + """ + Функция коллбека для закрытия меню для /списокЮбилейный + :param call: CallbackQuery + :param callback_data: dict + :return: None + """ with suppress(MessageCantBeDeleted, MessageToEditNotFound): await call.message.delete() diff --git a/tgbot/keyboards/inline.py b/tgbot/keyboards/inline.py index f62144b..fc75524 100644 --- a/tgbot/keyboards/inline.py +++ b/tgbot/keyboards/inline.py @@ -3,14 +3,23 @@ from aiogram.utils.callback_data import CallbackData -def get_gran_kb(uid): +def get_gran_kb(uid: str) -> InlineKeyboardMarkup: + """ + Возвращает inline клав. для поздравления + :param uid: + :return: InlineKeyboardMarkup + """ grant_btn = InlineKeyboardButton('Поздравить!', callback_data=f'grant|{uid}') cancel_btn = InlineKeyboardButton('Отмена', callback_data=f'can|{uid}') grant_kb = InlineKeyboardMarkup().add(grant_btn, cancel_btn) return grant_kb -def get_conf_groups_kb(): +def get_conf_groups_kb() -> InlineKeyboardMarkup: + """ + Возвращает inline клав. для настройки таблицы соотв. групп + :return: InlineKeyboardMarkup + """ show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_groups') add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_groups') delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_groups') @@ -19,7 +28,11 @@ def get_conf_groups_kb(): return conf_groups_kb -def get_main_menu_kb(): +def get_main_menu_kb() -> InlineKeyboardMarkup: + """ + Возвращает inline клав. для главного меню + :return: InlineKeyboardMarkup + """ config_groups_btn = InlineKeyboardButton('Настройка таблицы групп', callback_data='configure_groups') config_numbers_btn = InlineKeyboardButton('Настройка таблицы номеров', callback_data='configure_numbers') cancel_btn = InlineKeyboardButton('Отмена', callback_data='cancel') @@ -28,6 +41,10 @@ def get_main_menu_kb(): def get_conf_numbers_kb(): + """ + Возвращает inline клав. для настройки таблицы c поздр. номерами + :return: InlineKeyboardMarkup + """ show_btn = InlineKeyboardButton('Показать таблицу', callback_data='show_numbers') add_btn = InlineKeyboardButton('Добавить строку', callback_data='add_numbers') delete_btn = InlineKeyboardButton('Удалить строку', callback_data='delete_numbers') @@ -40,7 +57,11 @@ def get_conf_numbers_kb(): def get_list_granted_kb(user_groups: dict) -> types.InlineKeyboardMarkup: - + """ + Фабрика коллбеков для вывода групп, если их больше одной, при отправке команды /списокЮбилейный + :param user_groups: dict + :return: types.InlineKeyboardMarkup + """ markup = types.InlineKeyboardMarkup() for ids, user_group in user_groups.items(): markup.add( diff --git a/tgbot/keyboards/reply.py b/tgbot/keyboards/reply.py deleted file mode 100644 index e69de29..0000000 diff --git a/tgbot/misc/grant_text.py b/tgbot/misc/grant_text.py index 7f843f3..9266e0d 100644 --- a/tgbot/misc/grant_text.py +++ b/tgbot/misc/grant_text.py @@ -1,4 +1,10 @@ -def get_great_text(user, count): +def get_great_text(user: str, count: int) -> str: + """ + Функция возврата текста для поздравления + :param user: str + :param count: int + :return: str + """ text = f'🎉 Поздравляю, {user}, как же удачно попали в нужное место и в нужное время!\n' \ f'Вы {count} участник комьюнити.\n' \ f'Вас ждут плюшки и печенюшки!🎉' diff --git a/tgbot/misc/set_commands.py b/tgbot/misc/set_commands.py index 5a793ac..03412dd 100644 --- a/tgbot/misc/set_commands.py +++ b/tgbot/misc/set_commands.py @@ -1,7 +1,12 @@ -from aiogram import types +from aiogram import types, Dispatcher -async def set_default_commands(dp): +async def set_default_commands(dp: Dispatcher) -> None: + """ + Функция для установки комманд меню в приватном канале бота + :param dp: Dispatcher + :return: None + """ await dp.bot.set_my_commands([ types.BotCommand("start", "Запустить бота"), diff --git a/tgbot/misc/show_granted.py b/tgbot/misc/show_granted.py index 3229f77..7054f75 100644 --- a/tgbot/misc/show_granted.py +++ b/tgbot/misc/show_granted.py @@ -1,7 +1,13 @@ from aiogram import types -async def send_granted_message(granted_list: list[tuple], message: types.Message): +async def send_granted_message(granted_list: list[tuple], message: types.Message) -> None: + """ + Функция для отправкий сообщений с юбилейными пользователями + :param granted_list: list[tuple] + :param message: types.Message + :return: None + """ for granted in granted_list: emoji = '🎉' if granted[6]: From b6e2ab5bce7973f019fd61d176989aa5fe09288b Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Wed, 20 Jul 2022 14:51:52 +0300 Subject: [PATCH 15/16] Add readme and delete autocreating groups in grant_numbers --- README.md | 86 +++++++++++++++++++++++- tgbot/Utils/DBWorker.py | 10 --- tgbot/handlers/admin/get_users_groups.py | 5 +- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1164b0e..2544183 100644 --- a/README.md +++ b/README.md @@ -1 +1,85 @@ -# tg-bot-users 🤖 +# Anniversary Users Bot 🤖 + +Бот для автоматического отслеживания и поздравления юбилейных пользователей. При +вступлении в группу юбилейного участника бот присылает в группу +администраторов уведомление с именем, ником, id пользователя, юбилейным номером и датой и временем вступления, +а также кнопкой "Поздравить" и "Отменить" для автоматического поздравления юбилейного участника или отмены, в случае +вступления в группу бота/модератора. В файле .env в переменной GRANT_NUMBER (пример в .env.dist), необходимо установить +число, кратно которому будут определятся пользователи (при 500 - 500, 1000 и т.д.), это глобальная настройка для всех +групп, если необходимо для какой-то группы выставить индивидуальные значения, то необходимо через приватный канал бота, +для этой группы настроить соответствующую таблицу. Для доступа к конфигурированию бота через приватный канал, в файле +.env (пример в .env.dist) необходимо прописать в переменной ADMINS, прописать ID пользователей Телеграмм, которые будут +иметь соответствующие права. + +## Особенности + +* Бот, в автоматическом режиме проверяет вступившего пользователя на "юбилейные" места в группе, и посылает оповещения в + группу администраторов. +* Все новые вступившие пользователи проверяются по базе данных, что бы исключить повторное поздравление. +* Управление ботов осуществляется в группе администраторов. +* Возможность "тонкой" настройки юбилейных мест. К примеру, каждый: 50, 100, 200 ... и так далее. +* Сохранение данных о двух последующих пользователях. +* Возможность настройки групп администраторов. +* База данных на всех поздравленных пользователей +* Автоматический перезапуск бота в случае возникновения ошибки (Docker) + +## Доступные команды + +### В группе модераторов + +* /проверка - команда проверяет, есть ли в очереди на поздравление пользователи из модерируемых групп. +* /восстановить - команда предназначена для восстановления кнопок для поздравления, на случай если уведомление с + кнопками поздравлениями удалили, или нажали кнопку отмены. +* /списокЮбилейный - выводит историю о юбилейных пользователях + +### В приватном чате бота(админка) + +Настройка бота производится в приватном чате, команды доступные в меню: + +*/start - Позволяет проверить запушен ли бот и есть ли у пользователя права на конфигурирование +*/configure - Вызывает главное меню + +#### Главное меню: + +В главном меню есть доступ для перехода к конфигурированию 2 таблиц: + +1. Настройка таблицы групп: + +* Показать таблицу - выводит таблицу с данными из БД +* Добавить строку - позволяет добавить новую в БД, на одну группу модераторов может быть добавлено несколько групп + пользователей, при этом, если ввести id группы модераторов, запись с которой уже существует, то бот просто добавит + к старой записи новые группы пользователей, при этом бот уберет дубликаты id пользовательских групп, если их введут + повторно. +* Удалить строку - удаляет строку из БД по ID записи в БД +* Главное меню - возвращает в главное меню + +2. Настройка таблицы с юбилейными номерами: + +* Показать таблицу - выводит таблицу с данными из БД +* Добавить строку - позволяет добавить новую в БД, на одну группу пользователей может быть добавлено несколько номеров, + при этом, если ввести уже id группы пользователей, запись с которой уже существует, то бот просто добавит + к старой записи, новые номера, при этом бот уберет дубликаты номеров а также отсортиует их по возрастанию. +* Удалить строку - удаляет строку из БД по ID записи в БД +* Главное меню - возвращает в главное меню + +## Requirements + +* aiogram 2.21 +* aioredis 2.0 +* environs 9.0 +* aiosqlite 0.17 +* python-dotenv 0.20 + +## Подготовка и запуск + +1) Создайте своего бота с помощью бота @BotFather и сохраните свой токен. +2) Необходимо в @BotFather отключить privacy mode. +3) Добавьте бота во все чаты, в которых необходимо отслеживать пользователей(боту необходимо выдать права + администратора) +4) Создать файл .env в директории программы и заполнить его согласно .env.dist +5) Вы можете запустить бота локально, установив все зависимости командой: + pip install -r requirements.txt и запустив bot.py +6) Вы так же можете запустить бота из Docker контейнера, для этого перейдите в терминале, в папку с ботом и выполните + команду: docker-compose up +7) После чего можете переходить к настройкам админки, для того чтобы бот начал работать в группах в которые он был + добавлен, необходимо внести соответствие ID этих групп в таблицу, через приватный канал бота. \ No newline at end of file diff --git a/tgbot/Utils/DBWorker.py b/tgbot/Utils/DBWorker.py index 3664e3e..2140bbd 100644 --- a/tgbot/Utils/DBWorker.py +++ b/tgbot/Utils/DBWorker.py @@ -122,16 +122,6 @@ async def set_data_groups(values: tuple) -> int: ' VALUES(?, ?);', values=values) -async def set_group_ids_grant_numbers(values: List[tuple]) -> int: - """ - Функция для вставки новой записи в таблицу grant_numbers, или замены - :param values: tuple - :return: int - """ - return await db_execute(string= - "INSERT OR IGNORE INTO grant_numbers(group_id) VALUES(?);", values=values, multiple=True) - - async def set_data_queue(values: tuple) -> int: """ Функция для вставки новой записи в таблицу queue diff --git a/tgbot/handlers/admin/get_users_groups.py b/tgbot/handlers/admin/get_users_groups.py index 6a15a78..410d20e 100644 --- a/tgbot/handlers/admin/get_users_groups.py +++ b/tgbot/handlers/admin/get_users_groups.py @@ -7,7 +7,7 @@ from tgbot.Utils.get_ids_for_grant_numbers import get_ids_for_multiple_record from tgbot.keyboards.inline import get_conf_groups_kb from tgbot.misc.states import Configure -from tgbot.Utils.DBWorker import set_data_groups, set_group_ids_grant_numbers, get_users_groups +from tgbot.Utils.DBWorker import set_data_groups, get_users_groups async def get_users_group(message: types.Message, state: FSMContext) -> None: @@ -36,9 +36,6 @@ async def get_users_group(message: types.Message, state: FSMContext) -> None: text_message = await delete_doubles_ids(ids_user_groups) await set_data_groups(values=(id_mod_group, text_message,)) - ids_grant_numbers = await get_ids_for_multiple_record(text_message) - await set_group_ids_grant_numbers(values=ids_grant_numbers) - await message.answer('Записал') await state.finish() await message.answer(text='⚙ Настройка таблицы соответствия групп ⚙', From d7bc07ad7bcd41ac47d5e86d4bfcaa0ec40749b8 Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <1cbit3@gmail.com> Date: Fri, 2 Sep 2022 17:46:27 +0300 Subject: [PATCH 16/16] fix bug --- tgbot/handlers/admin/get_numbers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgbot/handlers/admin/get_numbers.py b/tgbot/handlers/admin/get_numbers.py index 5cc4512..bb1bc51 100644 --- a/tgbot/handlers/admin/get_numbers.py +++ b/tgbot/handlers/admin/get_numbers.py @@ -31,7 +31,7 @@ async def get_grant_numbers(message: types.Message, state: FSMContext) -> None: existed = await get_data_from_grant_numbers(group_id=id_group) numbers = message.text - if existed[0][0]: + if existed: numbers += f',{existed[0][0]}' text_message = await delete_doubles_ids(message=numbers, sort=True)