from collections.abc import Awaitable, Callable from typing import Any from aiogram import BaseMiddleware from aiogram.enums import ChatType from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError from aiogram.fsm.context import FSMContext from aiogram.types import InlineKeyboardButton, Message, Update from aiogram.utils.keyboard import InlineKeyboardBuilder from bot import bot from config import CHANNEL_EXISTS, CHANNEL_ID, CHANNEL_REQUIRED, CHANNEL_URL from core.bootstrap import MODES_CONFIG from handlers.buttons import SUB_CHANELL, SUB_CHANELL_DONE from handlers.texts import SUBSCRIPTION_REQUIRED_MSG from handlers.utils import edit_or_send_message from logger import logger class SubscriptionMiddleware(BaseMiddleware): async def __call__( self, handler: Callable[[Update, dict[str, Any]], Awaitable[Any]], event: Update, data: dict[str, Any], ) -> Any: channel_check_enabled = bool(MODES_CONFIG.get("CHANNEL_CHECK_ENABLED", CHANNEL_REQUIRED)) if not CHANNEL_EXISTS or not channel_check_enabled: return await handler(event, data) tg_id = None message = None from_user = None if event.message: if event.message.chat.type != ChatType.PRIVATE: return await handler(event, data) if not event.message.from_user: return await handler(event, data) if event.message.from_user.is_bot: return await handler(event, data) tg_id = event.message.from_user.id message = event.message from_user = event.message.from_user elif event.callback_query: if event.callback_query.message and event.callback_query.message.chat.type != ChatType.PRIVATE: return await handler(event, data) if not event.callback_query.from_user: return await handler(event, data) if event.callback_query.from_user.is_bot: return await handler(event, data) tg_id = event.callback_query.from_user.id message = event.callback_query.message from_user = event.callback_query.from_user else: return await handler(event, data) try: member = await bot.get_chat_member(CHANNEL_ID, tg_id) if member.status not in ("member", "administrator", "creator"): logger.info(f"[SubMiddleware] Пользователь {tg_id} не подписан") await self._store_user_state(data, message, from_user) return await self._ask_to_subscribe(message) except (TelegramBadRequest, TelegramForbiddenError) as e: logger.warning(f"[SubMiddleware] Ошибка при проверке подписки {tg_id}: {e}") await self._store_user_state(data, message, from_user) return await self._ask_to_subscribe(message) return await handler(event, data) async def _store_user_state(self, data: dict, message: Message, from_user): state: FSMContext = data.get("state") if not state or not from_user or from_user.is_bot: return state_data = await state.get_data() if "original_text" in state_data and "user_data" in state_data: return original_text = message.text or message.caption user_data = { "tg_id": from_user.id, "username": from_user.username, "first_name": from_user.first_name, "last_name": from_user.last_name, "language_code": from_user.language_code, "is_bot": from_user.is_bot, } await state.update_data( original_text=original_text, user_data=user_data, ) async def _ask_to_subscribe(self, message: Message): builder = InlineKeyboardBuilder() builder.row(InlineKeyboardButton(text=SUB_CHANELL, url=CHANNEL_URL)) builder.row(InlineKeyboardButton(text=SUB_CHANELL_DONE, callback_data="check_subscription")) await edit_or_send_message( target_message=message, text=SUBSCRIPTION_REQUIRED_MSG, reply_markup=builder.as_markup(), )