multi-bot finished

This commit is contained in:
2025-08-08 12:09:20 +09:00
parent 423ebf625b
commit 927da228c8
3 changed files with 93 additions and 17 deletions

View File

@@ -1,6 +1,7 @@
# bot/bot_factory.py
import logging
from typing import Optional, Tuple
from typing import Optional, Sequence, Tuple
from telegram.constants import ParseMode
from telegram.ext import (
Application,
@@ -11,22 +12,25 @@ from telegram.ext import (
Defaults,
filters,
)
from .models import TelegramBot, BotConfig
from .handlers import start, ping, echo, my_chat_member_update, error_handler
from .services import build_services
logger = logging.getLogger(__name__)
def _resolve_parse_mode(pm: Optional[str]):
if not pm or pm == "None":
return None
return getattr(ParseMode, pm, ParseMode.HTML)
def build_application_for_bot(tb: TelegramBot) -> Tuple[Application, Optional[list]]:
cfg = BotConfig.objects.filter(bot=tb).first()
if not cfg:
raise RuntimeError(f"BotConfig не найден для бота '{tb}'")
def build_application_for_bot(tb: TelegramBot, cfg: BotConfig) -> Tuple[Application, Optional[list]]:
"""
Фабрика PTB Application для КОНКРЕТНОГО бота.
ВАЖНО: никакого ORM внутри — cfg передаётся извне.
"""
parse_mode = _resolve_parse_mode(cfg.parse_mode)
defaults = Defaults(parse_mode=parse_mode) if parse_mode else None
allowed_updates = cfg.allowed_updates or None
@@ -37,14 +41,16 @@ def build_application_for_bot(tb: TelegramBot) -> Tuple[Application, Optional[li
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)
# инжект зависимостей для КОНКРЕТНОГО бота
# DI: сервисы для этого бота
services = build_services(tb)
app.bot_data["services"] = services
app.bot_data["allowed_updates"] = allowed_updates
@@ -54,3 +60,42 @@ def build_application_for_bot(tb: TelegramBot) -> Tuple[Application, Optional[li
tb.name, tb.username or "", parse_mode, allowed_updates
)
return app, allowed_updates
def get_first_active_bot_with_config() -> Tuple[TelegramBot, BotConfig]:
"""
СИНХРОННО! Забирает первого активного бота и его конфиг.
"""
tb = TelegramBot.objects.filter(is_active=True).first()
if not tb:
raise RuntimeError("Нет активного TelegramBot (is_active=True). Создайте запись и включите её.")
cfg = BotConfig.objects.filter(bot=tb).first()
if not cfg:
raise RuntimeError(f"Для бота '{tb}' не найден BotConfig. Создайте связанную запись BotConfig.")
return tb, cfg
def get_all_active_bots_with_configs() -> Sequence[Tuple[TelegramBot, BotConfig]]:
"""
СИНХРОННО! Возвращает все (bot, cfg) для активных ботов.
Бросает, если хотя бы у одного нет BotConfig.
"""
bots = list(TelegramBot.objects.filter(is_active=True))
if not bots:
return []
cfg_map = {c.bot_id: c for c in BotConfig.objects.filter(bot__in=bots)}
result: list[Tuple[TelegramBot, BotConfig]] = []
missing = []
for b in bots:
cfg = cfg_map.get(b.id)
if not cfg:
missing.append(b)
else:
result.append((b, cfg))
if missing:
names = ", ".join(f"{b.name}(@{b.username or ''})" for b in missing)
raise RuntimeError(f"Нет BotConfig для ботов: {names}")
return result