# bot/bot.py import logging from typing import Optional, Tuple from telegram.constants import ParseMode from telegram.ext import ( Application, ApplicationBuilder, CommandHandler, MessageHandler, ChatMemberHandler, filters, Defaults ) from .models import TelegramBot, BotConfig from .handlers import start, ping, echo, my_chat_member_update, error_handler logger = logging.getLogger(__name__) def _resolve_parse_mode(pm: Optional[str]): """ Преобразуем строковое значение из BotConfig.parse_mode в объект ParseMode. 'None' -> None (без парсинга), иначе HTML/MarkdownV2. """ if not pm or pm == "None": return None # Безопасно берём атрибут из ParseMode, по умолчанию HTML return getattr(ParseMode, pm, ParseMode.HTML) def _get_active_bot_and_config() -> Tuple[TelegramBot, BotConfig]: """ Возвращает (активный TelegramBot, его BotConfig). Бросает понятные ошибки, если данных нет. """ bot = TelegramBot.objects.filter(is_active=True).first() if not bot: raise RuntimeError( "Нет активного TelegramBot (is_active=True). Создайте запись TelegramBot и включите её." ) cfg = BotConfig.objects.filter(bot=bot).first() if not cfg: raise RuntimeError( f"Для бота '{bot}' не найден BotConfig. Создайте связанную запись BotConfig." ) return bot, cfg def build_application() -> Application: tb, cfg = _get_active_bot_and_config() parse_mode = _resolve_parse_mode(cfg.parse_mode) allowed_updates = cfg.allowed_updates or None defaults = Defaults(parse_mode=parse_mode) if parse_mode else None builder: ApplicationBuilder = Application.builder().token(tb.token) if defaults: builder = builder.defaults(defaults) app = builder.build() app.add_handler(CommandHandler("start", start)) app.add_handler(CommandHandler("ping", ping)) app.add_handler(ChatMemberHandler(my_chat_member_update, ChatMemberHandler.MY_CHAT_MEMBER)) app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo)) app.add_error_handler(error_handler) app.bot_data["allowed_updates"] = allowed_updates return app