feat: add telegram notification channel with outbox service and per-user preferences

Extend the notification system with a third channel (telegram) alongside existing in_app and push channels. Add `telegram_enabled` column to `notification_preferences` table, update `NOTIFICATION_CHANNELS` and `_NOTIFICATION_CHANNEL_COLUMNS` mappings, and set telegram default to off (`_NOTIFICATION_CHANNEL_DEFAULTS`). Create `telegram_outbox` table with columns for uid, user_uid, chat_id, text, status, attempts, created_at, and sent_at, plus an index on status/id for efficient polling. Register `TelegramOutboxService` in the service manager lifecycle. Update API documentation strings to describe the new channel and its pairing requirement. Extend admin notification defaults view to include telegram column. Pass `notif_telegram_paired` flag to profile template based on `telegram_store.is_paired()` check. Update `NotificationPrefForm` and `NotificationDefaultForm` model literals to accept "telegram" as a valid channel value.
This commit is contained in:
2026-06-22 20:52:02 +00:00
parent a9d0814c47
commit e0e64c8d9e
36 changed files with 720 additions and 78 deletions
+9
View File
@@ -173,6 +173,7 @@ class TelegramBridge:
summary=f"Telegram paired for {user.get('username', user['uid'])}",
metadata={"chat_id": chat_id},
)
await self._publish_pairing(user["uid"], True)
return
self._register_attempt(chat_id)
await self._service.send(chat_id, BAD_CODE)
@@ -198,6 +199,14 @@ class TelegramBridge:
def _register_attempt(self, chat_id: int) -> None:
self._attempts.setdefault(chat_id, []).append(time.monotonic())
async def _publish_pairing(self, user_uid: str, paired: bool) -> None:
try:
from devplacepy.services.pubsub import publish
await publish(f"user.{user_uid}.telegram", {"paired": paired})
except Exception: # noqa: BLE001 - live pairing update is best-effort
pass
async def _run_turn(
self, chat_id: int, user: dict[str, Any], text: str, images: list[str]
) -> None: