diff --git a/.gitignore b/.gitignore index 2eea525..dc12cb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.env \ No newline at end of file +.env +__pycache__ \ No newline at end of file diff --git a/__pycache__/data_manager.cpython-313.pyc b/__pycache__/data_manager.cpython-313.pyc deleted file mode 100644 index b717da0..0000000 Binary files a/__pycache__/data_manager.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/database.cpython-313.pyc b/__pycache__/database.cpython-313.pyc deleted file mode 100644 index ec16ae7..0000000 Binary files a/__pycache__/database.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/keyboards.cpython-313.pyc b/__pycache__/keyboards.cpython-313.pyc deleted file mode 100644 index 17cc644..0000000 Binary files a/__pycache__/keyboards.cpython-313.pyc and /dev/null differ diff --git a/data_manager.py b/data_manager.py index f1c814a..d5943d2 100644 --- a/data_manager.py +++ b/data_manager.py @@ -4,11 +4,13 @@ import logging logger = logging.getLogger(__name__) class DataManager: - def __init__(self, facultets_url, groups_url): + def __init__(self, facultets_url, groups_url, parser_url): self.facultets_url = facultets_url self.groups_url = groups_url + self.parser_url = parser_url self.facs = {} # {id: {name: ...}} self.groups = {} # {id: {real_name: ..., facultet_tech: ..., ...}} + self.parser = {} async def refresh_cache(self, connector): async with aiohttp.ClientSession(connector=connector) as session: @@ -17,6 +19,8 @@ class DataManager: try: self.facs = await fetch(self.facultets_url) self.groups = (await fetch(self.groups_url))['groups'] + self.parser = (await fetch(self.parser_url)) + logger.info(f"Loaded {len(self.facs)} facs and {len(self.groups)} groups") except Exception as e: logger.error(f"Cache refresh failed: {e}") @@ -29,11 +33,12 @@ class DataManager: def get_files_by_fac(self, fac_id): files = {} # {uniqpath*: display_name} - for g in self.groups.values(): - if g.get('facultet_tech') == fac_id or g.get('facultet_recognized') == fac_id: - for ex in g.get('excels', []): - fn = ex['uniqpath'].replace("vstu.ru/rasp?dep=", "") - files[fn] = ex['display_filename'] + i = -1 + for ex in self.parser['all_files']: + i += 1 + if ex.get('facultet') == fac_id: + files[i] = ex['display_filename'] + return list(files.items()) def get_excel_by_uniqpath(self, uniqid): diff --git a/main.py b/main.py index e4f763a..19395cc 100644 --- a/main.py +++ b/main.py @@ -22,12 +22,22 @@ import keyboards as kb import re import fnmatch +from middleware import LoggingMiddleware + load_dotenv() +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler() + ] +) + # --- Настройки --- engine = create_async_engine(os.getenv("DATABASE_URL")) async_session = async_sessionmaker(engine, expire_on_commit=False) -data_mgr = DataManager(os.getenv("FACULTETS_JSON_URL"), os.getenv("GROUPS_JSON_URL")) +data_mgr = DataManager(os.getenv("FACULTETS_JSON_URL"), os.getenv("GROUPS_JSON_URL"), os.getenv("PARSER_JSON_URL")) bot = None dp = Dispatcher() @@ -203,16 +213,17 @@ async def view_group(callback: types.CallbackQuery): # Просмотр файла @dp.callback_query(F.data.startswith("view_excel:")) async def view_excel(callback: types.CallbackQuery): - pre_uniq_path = callback.data.split(":")[1] - uniqpath = "vstu.ru/rasp?dep=" + pre_uniq_path + pre_index = callback.data.split(":")[1] # Находим имя файла для красоты h_name = "Excel файл" - for g in data_mgr.groups.values(): - for ex in g.get('excels', []): - if ex.get('uniqpath', "") == uniqpath: h_name = ex['display_filename']; break + try: + ex = data_mgr.parser['all_files'][int(pre_index)] + h_name = ex['display_filename'] + except Exception as e: + print(f"safe?: {e}") builder = InlineKeyboardBuilder() - builder.row(types.InlineKeyboardButton(text="🔔 Подписаться на файл", callback_data=f"suco:excel:{pre_uniq_path}")) + builder.row(types.InlineKeyboardButton(text="🔔 Подписаться на файл", callback_data=f"suco:excel:{pre_index}")) builder.row(types.InlineKeyboardButton(text="⬅️ Назад", callback_data="menu_start")) await callback.message.edit_text(f"📄 Файл: *{h_name}*", reply_markup=builder.as_markup(), parse_mode="Markdown") @@ -224,11 +235,13 @@ async def sub_confirm(callback: types.CallbackQuery): sub_value = val if mode == "excel": - pre_uniq_path = h_name - uniqpath = "vstu.ru/rasp?dep=" + pre_uniq_path - excel = data_mgr.get_excel_by_uniqpath(uniqpath) - sub_value = excel['url'].split("/")[-1] - h_name = sub_value + pre_index = h_name + try: + excel = data_mgr.parser['all_files'][int(pre_index)] + sub_value = excel['url'].split("/")[-1] + h_name = sub_value + except Exception as e: + print(f"safe? e={e}") async with async_session() as session: # Регистрация пользователя если нет @@ -337,6 +350,8 @@ async def main(): await conn.run_sync(Base.metadata.create_all) await data_mgr.refresh_cache(connector) + + dp.update.middleware(LoggingMiddleware()) # <-- добавьте эту строку asyncio.create_task(start_rabbitmq_consumer()) # Периодическое обновление индексов diff --git a/middleware.py b/middleware.py new file mode 100644 index 0000000..637ced3 --- /dev/null +++ b/middleware.py @@ -0,0 +1,51 @@ +from aiogram.types import Update +from aiogram import BaseMiddleware +from typing import Callable, Dict, Any, Awaitable +import logging +import time +import json + +class LoggingMiddleware(BaseMiddleware): + async def __call__( + self, + handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]], + event: Update, + data: Dict[str, Any] + ) -> Any: + # Логируем входящий апдейт + update_id = event.update_id + update_type = "unknown" + + if event.message: + update_type = "message" + chat_id = event.message.chat.id + text = event.message.text or "[non-text]" + log_msg = f"📥 [UPDATE {update_id}] type={update_type} chat={chat_id} text={text}" + elif event.callback_query: + update_type = "callback_query" + chat_id = event.callback_query.message.chat.id + data_str = event.callback_query.data or "[no data]" + log_msg = f"📥 [UPDATE {update_id}] type={update_type} chat={chat_id} data={data_str}" + elif event.my_chat_member: + update_type = "my_chat_member" + log_msg = f"📥 [UPDATE {update_id}] type={update_type}" + elif event.chat_member: + update_type = "chat_member" + log_msg = f"📥 [UPDATE {update_id}] type={update_type}" + else: + log_msg = f"📥 [UPDATE {update_id}] type={update_type} raw={event.json()}" + + # Печатаем или используем logging + logging.info(log_msg) + # Если настроен logging: logging.info(log_msg) + + # Передаём управление дальше (в хендлеры) + try: + result = await handler(event, data) + except Exception as e: + # Логируем ошибку, но не подавляем + logging.error(f"❌ [UPDATE {update_id}] handler error: {e}") + raise + else: + logging.info(f"✅ [UPDATE {update_id}] handled successfully") + return result