From 70becfc32ec98084067686bd456971a4cb76082c Mon Sep 17 00:00:00 2001 From: Igor Tolmachov Date: Sat, 3 Dec 2022 02:03:05 +0900 Subject: Beta 2.0 --- handlers/__init__.py | 7 ++-- handlers/config.py | 77 +++++++++++++++++++++++++++++++++++++ handlers/gen.py | 102 +++++++++++++++++++++++++------------------------ handlers/member.py | 25 ++++++------ handlers/middleware.py | 21 ++++++++++ handlers/msg.py | 18 --------- handlers/pin.py | 32 +++++++--------- handlers/system.py | 17 +++++---- 8 files changed, 188 insertions(+), 111 deletions(-) create mode 100644 handlers/config.py create mode 100644 handlers/middleware.py delete mode 100644 handlers/msg.py (limited to 'handlers') 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 @@ # isort: skip_file -from . import msg - -from . import pin +from . import middleware from . import member +from . import pin +from . import config from . import gen - 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 @@ +from ast import literal_eval +from copy import deepcopy +from logging import info +from typing import Any, get_args + +from aiogram import types as t +from pydantic import BaseModel, ValidationError + +from shared.database import Message +from shared.instances import config, dp, session +from shared.settings import Config +from utils import filters as f + + +@dp.message_handler(f.user.is_admin, commands=["void"]) +async def void_command(msg: t.Message) -> None: + if msg.get_args() == "Я знаю что делаю": + with session.begin() as s: + s.query(Message).filter(Message.chat_id == msg.chat.id).delete() + await msg.answer("Лоботомия проведена успешно") + else: + await msg.answer( + "Напишите /void Я знаю что делаю", + parse_mode=t.ParseMode.HTML, + ) + + +@dp.message_handler(f.message.is_chat, f.user.is_admin, commands=["config"]) +async def settings_command(msg: t.Message) -> None: + def get_fields(config: BaseModel, level: int = 1) -> str: + text = "" + for name in config.__fields__: + value = getattr(config, name) + if isinstance(value, BaseModel): + text += f"\n{' '*level*4}{name}." + text += get_fields(value, level + 1) + else: + text += f"\n{' '*level*4}{name} = {value!r}" + return text + + args = msg.get_args().split() + chat_config = deepcopy(config.get_config(msg.chat.id)) + try: + if len(args) == 0: + text = f"/config{get_fields(chat_config)}\n\n" + await msg.reply(text, parse_mode=t.ParseMode.HTML) + else: + conf = chat_config + *path, field = args[0].split(".") + for f in path: + conf = getattr(conf, f) + if not isinstance(conf, BaseModel): + raise KeyError() + + if len(args) == 2: + if isinstance(getattr(conf, field), BaseModel): + raise KeyError() + value = args[1] + setattr(conf, field, literal_eval(value)) + + config.set_config(msg.chat.id, Config.parse_obj(chat_config.dict())) + config.save("data/config.json") + + await msg.reply( + f"/config {args[0]} = {getattr(conf, field)!r}", + parse_mode=t.ParseMode.HTML, + ) + else: + field_info = conf.__fields__[field].field_info + await msg.reply( + f"/config {args[0]} = {getattr(conf, field)!r}\n{field_info.description}", + parse_mode=t.ParseMode.HTML, + ) + except (ValidationError, ValueError, SyntaxError): + await msg.reply("Неверное значение") + except (KeyError, AttributeError): + 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 @@ -import os +import random import mc from aiogram import types as t -from shared import config -from shared.instances import bot, dp +from shared.database import Message +from shared.instances import bot, config, dp, session from utils import filters as f -@dp.message_handler(commands=["gen"]) -async def сгенерировать_хуету(msg: t.Message): - await msg.answer(получить_говно(msg.chat.id)) +def get_text(chat_id: int) -> str: + with session() as s: + samples = [ + m.tuple()[0] + for m in s.query(Message.message).filter(Message.chat_id == chat_id).all() + ] + assert ( + len(samples) != 0 + ), "Нету сообщений на основе которых можно сгенерировать сообщение" -@dp.message_handler(commands=["del"]) -async def удалить_хуету(msg: t.Message): - await msg.delete() + generator = mc.PhraseGenerator(samples) + gen_config = config.get_config(chat_id).gen + validators = [] - if msg.reply_to_message: - if msg.reply_to_message.from_user.id in [bot.id, msg.from_user.id]: - await msg.reply_to_message.delete() - else: - await msg.answer("Ты умник, можно только свои или мои удалять") - else: - await msg.answer("Ты умник, ответь на сообщение") - - -@dp.message_handler(commands=["void"]) -async def лоботомия(msg: t.Message): - if msg.get_args() == "Я знаю что делаю": - os.remove(f"data/{msg.chat.id}") - await msg.answer("Лоботомия проведена успешно") - else: - await msg.answer( - "Напишите /void Я знаю что делаю", parse_mode=t.ParseMode.HTML + if gen_config.max_word_count is not None or gen_config.min_word_count is not None: + validators.append( + mc.builtin.validators.words_count( + minimal=gen_config.min_word_count, + maximal=gen_config.max_word_count, + ) ) + while True: + message = generator.generate_phrase_or_none(1, validators=validators) + if message is not None: + return message -@dp.message_handler(commands=["chance"]) -async def изменить_шанс_срания(msg: t.Message): - if msg.get_args(): - try: - chance = int(msg.get_args().split()[0]) - if 0 <= chance <= 100: - config.chances[str(msg.chat.id)] = chance - config.save() - else: - raise RuntimeError() - - await msg.answer(f"Теперь я сру с шансом в: {chance}%") - except Exception: - await msg.answer( - "Я хз что не так, но я знаю что ты дебил \n /chance <ЧИСЛО ОТ 0 ДО 100>" - ) - else: - await msg.answer(f"Я сру с шансом в: {config.chances.get(str(msg.chat.id), 10)}%") +@dp.message_handler(commands=["gen"]) +async def gen_command(msg: t.Message) -> None: + await msg.delete() + message = get_text(msg.chat.id) + if message is not None: + await msg.answer(message) -@dp.message_handler(f.message.chance, content_types=[t.ContentType.ANY]) -async def срать_сообщение_с_шансом(msg: t.Message): - await msg.answer(получить_говно(msg.chat.id)) +@dp.message_handler(commands=["del"]) +async def del_command(msg: t.Message) -> None: + await msg.delete() -def получить_говно(id: int) -> str: - samples = mc.util.load_txt_samples(f"data/{id}", separator="§") - return mc.StringGenerator(samples=samples).generate_string() + if msg.reply_to_message: + if msg.reply_to_message.from_user.id == bot.id: + await msg.reply_to_message.delete() + else: + await msg.reply("Можно удалять только сообщения бота") + else: + await msg.reply("Вы не ответили на сообщение") + + +@dp.message_handler( + f.message.is_chat, + f.message.chance, + content_types=[t.ContentType.ANY], +) +async def chance_message(msg: t.Message) -> None: + message = get_text(msg.chat.id) + if message is not None: + 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 @@ from aiogram import types as t -from shared.instances import bot, dp +from shared.instances import bot, config, dp from utils import filters as f @dp.chat_join_request_handler() -async def приём_запроса(cjr: t.ChatJoinRequest): - r = await bot.send_message( +async def new_member(cjr: t.ChatJoinRequest) -> None: + reply = await bot.send_message( cjr.chat.id, f'{cjr.from_user.mention} хочет в чат', parse_mode=t.ParseMode.HTML, ) - await r.reply_poll( + await reply.reply_poll( "Пускаем ?", [ "Да", @@ -33,28 +33,27 @@ async def приём_запроса(cjr: t.ChatJoinRequest): @dp.callback_query_handler( f.message.is_chat, lambda clb: clb.data.split(":")[0] == "check_request_poll" ) -async def проверить_запрос(clb: t.CallbackQuery): +async def check_poll(clb: t.CallbackQuery) -> None: poll = clb.message.poll msg = clb.message data = clb.data.split(":") user_id = int(data[1]) + min_answers = config.get_config(msg.chat.id).commands.accept_member_answers_count - if poll.total_voter_count < 4: - await clb.answer(f"Нужно хотябы 4 голоса, сейчас {poll.total_voter_count}") + if poll.total_voter_count < min_answers: + await clb.answer( + f"Нужно хотябы {min_answers} голоса, сейчас {poll.total_voter_count}" + ) else: if not poll.is_closed: await bot.stop_poll(msg.chat.id, msg.message_id) - yes = poll.options[0].voter_count - no = poll.options[1].voter_count - win = max(yes, no) - - if win == yes: + if poll.options[0].voter_count > poll.options[1].voter_count: await bot.approve_chat_join_request(msg.chat.id, user_id) await bot.send_message( user_id, "Ваша заявка на вступление принята, добро пожаловать в группу" ) - elif win == no: + else: await bot.decline_chat_join_request(msg.chat.id, user_id) await bot.send_message(user_id, "Ваша заявка на вступление НЕ принята") 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 @@ +from logging import info + +from aiogram import types as t +from aiogram.dispatcher.middlewares import BaseMiddleware + +from shared.database import Message +from shared.instances import session + + +class MessageMiddleware(BaseMiddleware): + async def on_pre_process_message(self, msg: t.Message, data: dict) -> None: + text = msg.text or msg.caption + if text is not None and not text.startswith("/"): + with session.begin() as s: + s.add( + Message( + chat_id=msg.chat.id, + message_id=msg.message_id, + message=text, + ) + ) 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 @@ -from aiogram import types as t - -from shared.instances import dp -from utils import filters as f - - -async def сосалка(msg: t.Message): - text = msg.text or msg.caption - if text.startswith("/"): - return False - with open(f"data/{msg.chat.id}", "a+") as file: - file.write(text.lower().replace("§", "") + "§") - return False - - -@dp.message_handler(f.message.has_text, сосалка, content_types=[t.ContentType.ANY]) -async def ХУЙ(): - 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 @@ from aiogram import types as t -from shared.instances import bot, dp +from shared.instances import bot, config, dp from utils import filters as f @dp.message_handler(f.message.is_chat, commands=["pin"]) -async def закрепить_хуету(msg: t.Message): +async def pin_command(msg: t.Message) -> None: await msg.delete() if msg.reply_to_message: - r = await msg.reply_to_message.reply( + reply = await msg.reply_to_message.reply( f'{msg.from_user.mention} хочет закрепить сообщение', parse_mode=t.ParseMode.HTML, ) - await r.reply_poll( - "Закрепить ?", + await reply.reply_poll( + "Закрепить сообщение ?", [ "Да", - "УДАЛИ НАХУЙ", "Нет", ], reply_markup=t.InlineKeyboardMarkup().add( @@ -33,23 +32,18 @@ async def закрепить_хуету(msg: t.Message): @dp.callback_query_handler( f.message.is_chat, lambda clb: clb.data.split(":")[0] == "check_pin_poll" ) -async def проверить_закреп(clb: t.CallbackQuery): +async def check_poll(clb: t.CallbackQuery) -> None: poll = clb.message.poll msg = clb.message pin = int(clb.data.split(":")[1]) + min_answers = config.get_config(msg.chat.id).commands.pin_answers_count - if poll.total_voter_count < 2: - await clb.answer(f"Нужно хотябы 2 голоса, сейчас {poll.total_voter_count}") + if poll.total_voter_count < min_answers: + await clb.answer( + f"Нужно хотябы {min_answers} голоса, сейчас {poll.total_voter_count}" + ) else: + if poll.options[0].voter_count > poll.options[1].voter_count: + await msg.chat.pin_message(pin) if not poll.is_closed: await bot.stop_poll(msg.chat.id, msg.message_id) - - yes = poll.options[0].voter_count - delete = poll.options[1].voter_count - win = max(yes, delete) - - if win == yes: - await msg.chat.pin_message(pin) - elif win == delete: - await msg.chat.delete_message(pin) - 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 @dp.errors_handler() -async def уборщик_какашек(upd: t.Update, err: Exception): - txt = "Я хз что произошло, но да \n" - txt += f" {err.__class__.__name__}: {' '.join(map(str, err.args))}" +async def error_handler(upd: t.Update, err: Exception) -> bool: + if isinstance(err, AssertionError): + text = " ".join(map(str, err.args)) + else: + text = f"{err.__class__.__name__}: {' '.join(map(str, err.args))}" if upd.message: - await upd.message.answer(txt) + await upd.message.answer(text) elif upd.callback_query: - await upd.callback_query.answer(txt) + await upd.callback_query.answer(text) else: - return + return False - logging.error(traceback.format_exc()) + if not isinstance(err, AssertionError): + logging.error(traceback.format_exc()) return True -- cgit v1.3