diff options
Diffstat (limited to 'handlers')
| -rw-r--r-- | handlers/__init__.py | 7 | ||||
| -rw-r--r-- | handlers/config.py | 77 | ||||
| -rw-r--r-- | handlers/gen.py | 102 | ||||
| -rw-r--r-- | handlers/member.py | 25 | ||||
| -rw-r--r-- | handlers/middleware.py | 21 | ||||
| -rw-r--r-- | handlers/msg.py | 18 | ||||
| -rw-r--r-- | handlers/pin.py | 32 | ||||
| -rw-r--r-- | handlers/system.py | 17 |
8 files changed, 188 insertions, 111 deletions
diff --git a/handlers/__init__.py b/handlers/__init__.py index d689d15..d451cea 100644 --- a/handlers/__init__.py +++ b/handlers/__init__.py | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | # isort: skip_file | 1 | # isort: skip_file |
| 2 | from . import msg | 2 | from . import middleware |
| 3 | |||
| 4 | from . import pin | ||
| 5 | from . import member | 3 | from . import member |
| 4 | from . import pin | ||
| 5 | from . import config | ||
| 6 | from . import gen | 6 | from . import gen |
| 7 | |||
| 8 | from . import system | 7 | from . import system |
diff --git a/handlers/config.py b/handlers/config.py new file mode 100644 index 0000000..7eaf9eb --- /dev/null +++ b/handlers/config.py | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | from ast import literal_eval | ||
| 2 | from copy import deepcopy | ||
| 3 | from logging import info | ||
| 4 | from typing import Any, get_args | ||
| 5 | |||
| 6 | from aiogram import types as t | ||
| 7 | from pydantic import BaseModel, ValidationError | ||
| 8 | |||
| 9 | from shared.database import Message | ||
| 10 | from shared.instances import config, dp, session | ||
| 11 | from shared.settings import Config | ||
| 12 | from utils import filters as f | ||
| 13 | |||
| 14 | |||
| 15 | @dp.message_handler(f.user.is_admin, commands=["void"]) | ||
| 16 | async def void_command(msg: t.Message) -> None: | ||
| 17 | if msg.get_args() == "Я знаю что делаю": | ||
| 18 | with session.begin() as s: | ||
| 19 | s.query(Message).filter(Message.chat_id == msg.chat.id).delete() | ||
| 20 | await msg.answer("Лоботомия проведена успешно") | ||
| 21 | else: | ||
| 22 | await msg.answer( | ||
| 23 | "Напишите <code>/void Я знаю что делаю</code>", | ||
| 24 | parse_mode=t.ParseMode.HTML, | ||
| 25 | ) | ||
| 26 | |||
| 27 | |||
| 28 | @dp.message_handler(f.message.is_chat, f.user.is_admin, commands=["config"]) | ||
| 29 | async def settings_command(msg: t.Message) -> None: | ||
| 30 | def get_fields(config: BaseModel, level: int = 1) -> str: | ||
| 31 | text = "" | ||
| 32 | for name in config.__fields__: | ||
| 33 | value = getattr(config, name) | ||
| 34 | if isinstance(value, BaseModel): | ||
| 35 | text += f"\n{' '*level*4}<code>{name}.</code>" | ||
| 36 | text += get_fields(value, level + 1) | ||
| 37 | else: | ||
| 38 | text += f"\n{' '*level*4}<code>{name}</code> = {value!r}" | ||
| 39 | return text | ||
| 40 | |||
| 41 | args = msg.get_args().split() | ||
| 42 | chat_config = deepcopy(config.get_config(msg.chat.id)) | ||
| 43 | try: | ||
| 44 | if len(args) == 0: | ||
| 45 | text = f"<code>/config</code>{get_fields(chat_config)}\n\n" | ||
| 46 | await msg.reply(text, parse_mode=t.ParseMode.HTML) | ||
| 47 | else: | ||
| 48 | conf = chat_config | ||
| 49 | *path, field = args[0].split(".") | ||
| 50 | for f in path: | ||
| 51 | conf = getattr(conf, f) | ||
| 52 | if not isinstance(conf, BaseModel): | ||
| 53 | raise KeyError() | ||
| 54 | |||
| 55 | if len(args) == 2: | ||
| 56 | if isinstance(getattr(conf, field), BaseModel): | ||
| 57 | raise KeyError() | ||
| 58 | value = args[1] | ||
| 59 | setattr(conf, field, literal_eval(value)) | ||
| 60 | |||
| 61 | config.set_config(msg.chat.id, Config.parse_obj(chat_config.dict())) | ||
| 62 | config.save("data/config.json") | ||
| 63 | |||
| 64 | await msg.reply( | ||
| 65 | f"<code>/config {args[0]}</code> = {getattr(conf, field)!r}", | ||
| 66 | parse_mode=t.ParseMode.HTML, | ||
| 67 | ) | ||
| 68 | else: | ||
| 69 | field_info = conf.__fields__[field].field_info | ||
| 70 | await msg.reply( | ||
| 71 | f"<code>/config {args[0]}</code> = {getattr(conf, field)!r}\n{field_info.description}", | ||
| 72 | parse_mode=t.ParseMode.HTML, | ||
| 73 | ) | ||
| 74 | except (ValidationError, ValueError, SyntaxError): | ||
| 75 | await msg.reply("Неверное значение") | ||
| 76 | except (KeyError, AttributeError): | ||
| 77 | await msg.reply("Параметр не найден") | ||
diff --git a/handlers/gen.py b/handlers/gen.py index b618fec..8f19e96 100644 --- a/handlers/gen.py +++ b/handlers/gen.py | |||
| @@ -1,67 +1,69 @@ | |||
| 1 | import os | 1 | import random |
| 2 | 2 | ||
| 3 | import mc | 3 | import mc |
| 4 | from aiogram import types as t | 4 | from aiogram import types as t |
| 5 | 5 | ||
| 6 | from shared import config | 6 | from shared.database import Message |
| 7 | from shared.instances import bot, dp | 7 | from shared.instances import bot, config, dp, session |
| 8 | from utils import filters as f | 8 | from utils import filters as f |
| 9 | 9 | ||
| 10 | 10 | ||
| 11 | @dp.message_handler(commands=["gen"]) | 11 | def get_text(chat_id: int) -> str: |
| 12 | async def сгенерировать_хуету(msg: t.Message): | 12 | with session() as s: |
| 13 | await msg.answer(получить_говно(msg.chat.id)) | 13 | samples = [ |
| 14 | m.tuple()[0] | ||
| 15 | for m in s.query(Message.message).filter(Message.chat_id == chat_id).all() | ||
| 16 | ] | ||
| 14 | 17 | ||
| 18 | assert ( | ||
| 19 | len(samples) != 0 | ||
| 20 | ), "Нету сообщений на основе которых можно сгенерировать сообщение" | ||
| 15 | 21 | ||
| 16 | @dp.message_handler(commands=["del"]) | 22 | generator = mc.PhraseGenerator(samples) |
| 17 | async def удалить_хуету(msg: t.Message): | 23 | gen_config = config.get_config(chat_id).gen |
| 18 | await msg.delete() | 24 | validators = [] |
| 19 | 25 | ||
| 20 | if msg.reply_to_message: | 26 | if gen_config.max_word_count is not None or gen_config.min_word_count is not None: |
| 21 | if msg.reply_to_message.from_user.id in [bot.id, msg.from_user.id]: | 27 | validators.append( |
| 22 | await msg.reply_to_message.delete() | 28 | mc.builtin.validators.words_count( |
| 23 | else: | 29 | minimal=gen_config.min_word_count, |
| 24 | await msg.answer("Ты умник, можно только свои или мои удалять") | 30 | maximal=gen_config.max_word_count, |
| 25 | else: | 31 | ) |
| 26 | await msg.answer("Ты умник, ответь на сообщение") | ||
| 27 | |||
| 28 | |||
| 29 | @dp.message_handler(commands=["void"]) | ||
| 30 | async def лоботомия(msg: t.Message): | ||
| 31 | if msg.get_args() == "Я знаю что делаю": | ||
| 32 | os.remove(f"data/{msg.chat.id}") | ||
| 33 | await msg.answer("Лоботомия проведена успешно") | ||
| 34 | else: | ||
| 35 | await msg.answer( | ||
| 36 | "Напишите <code>/void Я знаю что делаю</code>", parse_mode=t.ParseMode.HTML | ||
| 37 | ) | 32 | ) |
| 38 | 33 | ||
| 34 | while True: | ||
| 35 | message = generator.generate_phrase_or_none(1, validators=validators) | ||
| 36 | if message is not None: | ||
| 37 | return message | ||
| 39 | 38 | ||
| 40 | @dp.message_handler(commands=["chance"]) | ||
| 41 | async def изменить_шанс_срания(msg: t.Message): | ||
| 42 | if msg.get_args(): | ||
| 43 | try: | ||
| 44 | chance = int(msg.get_args().split()[0]) | ||
| 45 | if 0 <= chance <= 100: | ||
| 46 | config.chances[str(msg.chat.id)] = chance | ||
| 47 | config.save() | ||
| 48 | else: | ||
| 49 | raise RuntimeError() | ||
| 50 | |||
| 51 | await msg.answer(f"Теперь я сру с шансом в: {chance}%") | ||
| 52 | except Exception: | ||
| 53 | await msg.answer( | ||
| 54 | "Я хз что не так, но я знаю что ты дебил \n /chance <ЧИСЛО ОТ 0 ДО 100>" | ||
| 55 | ) | ||
| 56 | else: | ||
| 57 | await msg.answer(f"Я сру с шансом в: {config.chances.get(str(msg.chat.id), 10)}%") | ||
| 58 | 39 | ||
| 40 | @dp.message_handler(commands=["gen"]) | ||
| 41 | async def gen_command(msg: t.Message) -> None: | ||
| 42 | await msg.delete() | ||
| 43 | message = get_text(msg.chat.id) | ||
| 44 | if message is not None: | ||
| 45 | await msg.answer(message) | ||
| 59 | 46 | ||
| 60 | @dp.message_handler(f.message.chance, content_types=[t.ContentType.ANY]) | ||
| 61 | async def срать_сообщение_с_шансом(msg: t.Message): | ||
| 62 | await msg.answer(получить_говно(msg.chat.id)) | ||
| 63 | 47 | ||
| 48 | @dp.message_handler(commands=["del"]) | ||
| 49 | async def del_command(msg: t.Message) -> None: | ||
| 50 | await msg.delete() | ||
| 64 | 51 | ||
| 65 | def получить_говно(id: int) -> str: | 52 | if msg.reply_to_message: |
| 66 | samples = mc.util.load_txt_samples(f"data/{id}", separator="§") | 53 | if msg.reply_to_message.from_user.id == bot.id: |
| 67 | return mc.StringGenerator(samples=samples).generate_string() | 54 | await msg.reply_to_message.delete() |
| 55 | else: | ||
| 56 | await msg.reply("Можно удалять только сообщения бота") | ||
| 57 | else: | ||
| 58 | await msg.reply("Вы не ответили на сообщение") | ||
| 59 | |||
| 60 | |||
| 61 | @dp.message_handler( | ||
| 62 | f.message.is_chat, | ||
| 63 | f.message.chance, | ||
| 64 | content_types=[t.ContentType.ANY], | ||
| 65 | ) | ||
| 66 | async def chance_message(msg: t.Message) -> None: | ||
| 67 | message = get_text(msg.chat.id) | ||
| 68 | if message is not None: | ||
| 69 | await msg.reply(message) | ||
diff --git a/handlers/member.py b/handlers/member.py index c4b1495..a4fc4cc 100644 --- a/handlers/member.py +++ b/handlers/member.py | |||
| @@ -1,17 +1,17 @@ | |||
| 1 | from aiogram import types as t | 1 | from aiogram import types as t |
| 2 | 2 | ||
| 3 | from shared.instances import bot, dp | 3 | from shared.instances import bot, config, dp |
| 4 | from utils import filters as f | 4 | from utils import filters as f |
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | @dp.chat_join_request_handler() | 7 | @dp.chat_join_request_handler() |
| 8 | async def приём_запроса(cjr: t.ChatJoinRequest): | 8 | async def new_member(cjr: t.ChatJoinRequest) -> None: |
| 9 | r = await bot.send_message( | 9 | reply = await bot.send_message( |
| 10 | cjr.chat.id, | 10 | cjr.chat.id, |
| 11 | f'<a href="tg://user?id={cjr.from_user.id}">{cjr.from_user.mention}</a> хочет в чат', | 11 | f'<a href="tg://user?id={cjr.from_user.id}">{cjr.from_user.mention}</a> хочет в чат', |
| 12 | parse_mode=t.ParseMode.HTML, | 12 | parse_mode=t.ParseMode.HTML, |
| 13 | ) | 13 | ) |
| 14 | await r.reply_poll( | 14 | await reply.reply_poll( |
| 15 | "Пускаем ?", | 15 | "Пускаем ?", |
| 16 | [ | 16 | [ |
| 17 | "Да", | 17 | "Да", |
| @@ -33,28 +33,27 @@ async def приём_запроса(cjr: t.ChatJoinRequest): | |||
| 33 | @dp.callback_query_handler( | 33 | @dp.callback_query_handler( |
| 34 | f.message.is_chat, lambda clb: clb.data.split(":")[0] == "check_request_poll" | 34 | f.message.is_chat, lambda clb: clb.data.split(":")[0] == "check_request_poll" |
| 35 | ) | 35 | ) |
| 36 | async def проверить_запрос(clb: t.CallbackQuery): | 36 | async def check_poll(clb: t.CallbackQuery) -> None: |
| 37 | poll = clb.message.poll | 37 | poll = clb.message.poll |
| 38 | msg = clb.message | 38 | msg = clb.message |
| 39 | data = clb.data.split(":") | 39 | data = clb.data.split(":") |
| 40 | user_id = int(data[1]) | 40 | user_id = int(data[1]) |
| 41 | min_answers = config.get_config(msg.chat.id).commands.accept_member_answers_count | ||
| 41 | 42 | ||
| 42 | if poll.total_voter_count < 4: | 43 | if poll.total_voter_count < min_answers: |
| 43 | await clb.answer(f"Нужно хотябы 4 голоса, сейчас {poll.total_voter_count}") | 44 | await clb.answer( |
| 45 | f"Нужно хотябы {min_answers} голоса, сейчас {poll.total_voter_count}" | ||
| 46 | ) | ||
| 44 | else: | 47 | else: |
| 45 | if not poll.is_closed: | 48 | if not poll.is_closed: |
| 46 | await bot.stop_poll(msg.chat.id, msg.message_id) | 49 | await bot.stop_poll(msg.chat.id, msg.message_id) |
| 47 | 50 | ||
| 48 | yes = poll.options[0].voter_count | 51 | if poll.options[0].voter_count > poll.options[1].voter_count: |
| 49 | no = poll.options[1].voter_count | ||
| 50 | win = max(yes, no) | ||
| 51 | |||
| 52 | if win == yes: | ||
| 53 | await bot.approve_chat_join_request(msg.chat.id, user_id) | 52 | await bot.approve_chat_join_request(msg.chat.id, user_id) |
| 54 | await bot.send_message( | 53 | await bot.send_message( |
| 55 | user_id, "Ваша заявка на вступление принята, добро пожаловать в группу" | 54 | user_id, "Ваша заявка на вступление принята, добро пожаловать в группу" |
| 56 | ) | 55 | ) |
| 57 | elif win == no: | 56 | else: |
| 58 | await bot.decline_chat_join_request(msg.chat.id, user_id) | 57 | await bot.decline_chat_join_request(msg.chat.id, user_id) |
| 59 | await bot.send_message(user_id, "Ваша заявка на вступление НЕ принята") | 58 | await bot.send_message(user_id, "Ваша заявка на вступление НЕ принята") |
| 60 | if not msg.chat.has_protected_content: | 59 | if not msg.chat.has_protected_content: |
diff --git a/handlers/middleware.py b/handlers/middleware.py new file mode 100644 index 0000000..6cf39b6 --- /dev/null +++ b/handlers/middleware.py | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | from logging import info | ||
| 2 | |||
| 3 | from aiogram import types as t | ||
| 4 | from aiogram.dispatcher.middlewares import BaseMiddleware | ||
| 5 | |||
| 6 | from shared.database import Message | ||
| 7 | from shared.instances import session | ||
| 8 | |||
| 9 | |||
| 10 | class MessageMiddleware(BaseMiddleware): | ||
| 11 | async def on_pre_process_message(self, msg: t.Message, data: dict) -> None: | ||
| 12 | text = msg.text or msg.caption | ||
| 13 | if text is not None and not text.startswith("/"): | ||
| 14 | with session.begin() as s: | ||
| 15 | s.add( | ||
| 16 | Message( | ||
| 17 | chat_id=msg.chat.id, | ||
| 18 | message_id=msg.message_id, | ||
| 19 | message=text, | ||
| 20 | ) | ||
| 21 | ) | ||
diff --git a/handlers/msg.py b/handlers/msg.py deleted file mode 100644 index dca295f..0000000 --- a/handlers/msg.py +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | from aiogram import types as t | ||
| 2 | |||
| 3 | from shared.instances import dp | ||
| 4 | from utils import filters as f | ||
| 5 | |||
| 6 | |||
| 7 | async def сосалка(msg: t.Message): | ||
| 8 | text = msg.text or msg.caption | ||
| 9 | if text.startswith("/"): | ||
| 10 | return False | ||
| 11 | with open(f"data/{msg.chat.id}", "a+") as file: | ||
| 12 | file.write(text.lower().replace("§", "") + "§") | ||
| 13 | return False | ||
| 14 | |||
| 15 | |||
| 16 | @dp.message_handler(f.message.has_text, сосалка, content_types=[t.ContentType.ANY]) | ||
| 17 | async def ХУЙ(): | ||
| 18 | pass | ||
diff --git a/handlers/pin.py b/handlers/pin.py index fc81ed1..9eb91a4 100644 --- a/handlers/pin.py +++ b/handlers/pin.py | |||
| @@ -1,22 +1,21 @@ | |||
| 1 | from aiogram import types as t | 1 | from aiogram import types as t |
| 2 | 2 | ||
| 3 | from shared.instances import bot, dp | 3 | from shared.instances import bot, config, dp |
| 4 | from utils import filters as f | 4 | from utils import filters as f |
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | @dp.message_handler(f.message.is_chat, commands=["pin"]) | 7 | @dp.message_handler(f.message.is_chat, commands=["pin"]) |
| 8 | async def закрепить_хуету(msg: t.Message): | 8 | async def pin_command(msg: t.Message) -> None: |
| 9 | await msg.delete() | 9 | await msg.delete() |
| 10 | if msg.reply_to_message: | 10 | if msg.reply_to_message: |
| 11 | r = await msg.reply_to_message.reply( | 11 | reply = await msg.reply_to_message.reply( |
| 12 | f'<a href="tg://user?id={msg.from_user.id}">{msg.from_user.mention}</a> хочет закрепить сообщение', | 12 | f'<a href="tg://user?id={msg.from_user.id}">{msg.from_user.mention}</a> хочет закрепить сообщение', |
| 13 | parse_mode=t.ParseMode.HTML, | 13 | parse_mode=t.ParseMode.HTML, |
| 14 | ) | 14 | ) |
| 15 | await r.reply_poll( | 15 | await reply.reply_poll( |
| 16 | "Закрепить ?", | 16 | "Закрепить сообщение ?", |
| 17 | [ | 17 | [ |
| 18 | "Да", | 18 | "Да", |
| 19 | "УДАЛИ НАХУЙ", | ||
| 20 | "Нет", | 19 | "Нет", |
| 21 | ], | 20 | ], |
| 22 | reply_markup=t.InlineKeyboardMarkup().add( | 21 | reply_markup=t.InlineKeyboardMarkup().add( |
| @@ -33,23 +32,18 @@ async def закрепить_хуету(msg: t.Message): | |||
| 33 | @dp.callback_query_handler( | 32 | @dp.callback_query_handler( |
| 34 | f.message.is_chat, lambda clb: clb.data.split(":")[0] == "check_pin_poll" | 33 | f.message.is_chat, lambda clb: clb.data.split(":")[0] == "check_pin_poll" |
| 35 | ) | 34 | ) |
| 36 | async def проверить_закреп(clb: t.CallbackQuery): | 35 | async def check_poll(clb: t.CallbackQuery) -> None: |
| 37 | poll = clb.message.poll | 36 | poll = clb.message.poll |
| 38 | msg = clb.message | 37 | msg = clb.message |
| 39 | pin = int(clb.data.split(":")[1]) | 38 | pin = int(clb.data.split(":")[1]) |
| 39 | min_answers = config.get_config(msg.chat.id).commands.pin_answers_count | ||
| 40 | 40 | ||
| 41 | if poll.total_voter_count < 2: | 41 | if poll.total_voter_count < min_answers: |
| 42 | await clb.answer(f"Нужно хотябы 2 голоса, сейчас {poll.total_voter_count}") | 42 | await clb.answer( |
| 43 | f"Нужно хотябы {min_answers} голоса, сейчас {poll.total_voter_count}" | ||
| 44 | ) | ||
| 43 | else: | 45 | else: |
| 46 | if poll.options[0].voter_count > poll.options[1].voter_count: | ||
| 47 | await msg.chat.pin_message(pin) | ||
| 44 | if not poll.is_closed: | 48 | if not poll.is_closed: |
| 45 | await bot.stop_poll(msg.chat.id, msg.message_id) | 49 | await bot.stop_poll(msg.chat.id, msg.message_id) |
| 46 | |||
| 47 | yes = poll.options[0].voter_count | ||
| 48 | delete = poll.options[1].voter_count | ||
| 49 | win = max(yes, delete) | ||
| 50 | |||
| 51 | if win == yes: | ||
| 52 | await msg.chat.pin_message(pin) | ||
| 53 | elif win == delete: | ||
| 54 | await msg.chat.delete_message(pin) | ||
| 55 | await msg.delete() | ||
diff --git a/handlers/system.py b/handlers/system.py index 5346c54..f97ff86 100644 --- a/handlers/system.py +++ b/handlers/system.py | |||
| @@ -7,17 +7,20 @@ from shared.instances import dp | |||
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | @dp.errors_handler() | 9 | @dp.errors_handler() |
| 10 | async def уборщик_какашек(upd: t.Update, err: Exception): | 10 | async def error_handler(upd: t.Update, err: Exception) -> bool: |
| 11 | txt = "Я хз что произошло, но да \n" | 11 | if isinstance(err, AssertionError): |
| 12 | txt += f" {err.__class__.__name__}: {' '.join(map(str, err.args))}" | 12 | text = " ".join(map(str, err.args)) |
| 13 | else: | ||
| 14 | text = f"{err.__class__.__name__}: {' '.join(map(str, err.args))}" | ||
| 13 | 15 | ||
| 14 | if upd.message: | 16 | if upd.message: |
| 15 | await upd.message.answer(txt) | 17 | await upd.message.answer(text) |
| 16 | elif upd.callback_query: | 18 | elif upd.callback_query: |
| 17 | await upd.callback_query.answer(txt) | 19 | await upd.callback_query.answer(text) |
| 18 | else: | 20 | else: |
| 19 | return | 21 | return False |
| 20 | 22 | ||
| 21 | logging.error(traceback.format_exc()) | 23 | if not isinstance(err, AssertionError): |
| 24 | logging.error(traceback.format_exc()) | ||
| 22 | 25 | ||
| 23 | return True | 26 | return True |
