feat: Receiver OOP hierarchy with per-receiver locale resolution
- Introduce Receiver base class + typed subclasses (TelegramReceiver, WebhookReceiver, EmailReceiver, etc.) in core/notifications/receiver.py - Dispatcher uses typed Receiver objects instead of raw dicts, with per-receiver locale-aware template rendering - load_link_data resolves locale from TelegramChat.language_override at load time: TargetReceiver.locale || chat.language_override || chat.language_code - Add language_override field to TelegramChat (separate from auto-detected language_code), with per-chat commands toggle and command dispatch using override language - Add locale field to TargetReceiver for explicit per-receiver overrides
This commit is contained in:
@@ -10,6 +10,7 @@ from sqlmodel import select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from notify_bridge_core.models.events import ServiceEvent
|
||||
from notify_bridge_core.notifications.receiver import Receiver, build_receiver
|
||||
|
||||
from ..database.models import (
|
||||
EmailBot,
|
||||
@@ -17,6 +18,8 @@ from ..database.models import (
|
||||
NotificationTarget,
|
||||
NotificationTrackerTarget,
|
||||
TargetReceiver,
|
||||
TelegramBot,
|
||||
TelegramChat,
|
||||
TemplateConfig,
|
||||
TemplateSlot,
|
||||
TrackingConfig,
|
||||
@@ -115,14 +118,44 @@ async def load_link_data(
|
||||
if not target:
|
||||
continue
|
||||
|
||||
# Load receivers
|
||||
# Load receivers as typed Receiver objects
|
||||
recv_result = await session.exec(
|
||||
select(TargetReceiver).where(
|
||||
TargetReceiver.target_id == target.id,
|
||||
TargetReceiver.enabled == True,
|
||||
)
|
||||
)
|
||||
receivers = [dict(r.config) for r in recv_result.all()]
|
||||
recv_rows = recv_result.all()
|
||||
|
||||
# For Telegram targets, resolve locale from TelegramChat
|
||||
chat_locale_map: dict[str, str] = {}
|
||||
if target.type == "telegram":
|
||||
bot_id = target.config.get("bot_id")
|
||||
if bot_id:
|
||||
chat_ids = [str(r.config.get("chat_id", "")) for r in recv_rows if r.config.get("chat_id")]
|
||||
if chat_ids:
|
||||
chat_result = await session.exec(
|
||||
select(TelegramChat).where(
|
||||
TelegramChat.bot_id == bot_id,
|
||||
TelegramChat.chat_id.in_(chat_ids),
|
||||
)
|
||||
)
|
||||
for chat in chat_result.all():
|
||||
resolved = (
|
||||
getattr(chat, 'language_override', '') or
|
||||
getattr(chat, 'language_code', '') or ''
|
||||
)
|
||||
if resolved:
|
||||
chat_locale_map[chat.chat_id] = resolved[:2].lower()
|
||||
|
||||
receivers: list[Receiver] = []
|
||||
for r in recv_rows:
|
||||
explicit_locale = getattr(r, 'locale', '') or ''
|
||||
locale = explicit_locale
|
||||
if not locale and target.type == "telegram":
|
||||
chat_id = str(r.config.get("chat_id", ""))
|
||||
locale = chat_locale_map.get(chat_id, "")
|
||||
receivers.append(build_receiver(target.type, dict(r.config), locale))
|
||||
|
||||
tracking_config = None
|
||||
if tt.tracking_config_id:
|
||||
|
||||
@@ -207,8 +207,9 @@ async def _poll_bot(bot_id: int) -> None:
|
||||
)).first()
|
||||
if not chat_row or not chat_row.commands_enabled:
|
||||
continue
|
||||
effective_lang = chat_row.language_override or msg_language
|
||||
message_id = message.get("message_id")
|
||||
cmd_response = await handle_command(bot_obj, chat_id, text, language_code=msg_language)
|
||||
cmd_response = await handle_command(bot_obj, chat_id, text, language_code=effective_lang)
|
||||
if cmd_response is not None:
|
||||
if isinstance(cmd_response, list):
|
||||
await send_media_group(bot_token, chat_id, cmd_response, reply_to_message_id=message_id)
|
||||
|
||||
Reference in New Issue
Block a user