"""Effective notification channel config (DB overrides env).""" from __future__ import annotations from dataclasses import dataclass from sqlalchemy import select from sqlalchemy.orm import Session from app.config import get_settings from app.models.notification_channel import NotificationChannel VALID_SEVERITIES = frozenset({"info", "warning", "high", "critical"}) CHANNEL_TELEGRAM = "telegram" @dataclass(frozen=True) class TelegramConfig: enabled: bool bot_token: str chat_id: str min_severity: str source: str # env | db @property def configured(self) -> bool: return bool(self.bot_token.strip() and self.chat_id.strip()) @property def active(self) -> bool: return self.enabled and self.configured def _telegram_from_env() -> TelegramConfig: settings = get_settings() return TelegramConfig( enabled=bool(settings.telegram_enabled), bot_token=settings.telegram_bot_token.strip(), chat_id=settings.telegram_chat_id.strip(), min_severity=settings.telegram_min_severity.strip() or "high", source="env", ) def get_effective_telegram_config(db: Session | None = None) -> TelegramConfig: if db is None: from app.database import SessionLocal session = SessionLocal() try: return get_effective_telegram_config(session) finally: session.close() row = db.scalar(select(NotificationChannel).where(NotificationChannel.channel == CHANNEL_TELEGRAM)) env_cfg = _telegram_from_env() if row is None: return env_cfg token = (row.bot_token or "").strip() or env_cfg.bot_token chat_id = (row.chat_id or "").strip() or env_cfg.chat_id min_sev = (row.min_severity or "").strip() or env_cfg.min_severity if min_sev not in VALID_SEVERITIES: min_sev = env_cfg.min_severity return TelegramConfig( enabled=bool(row.enabled), bot_token=token, chat_id=chat_id, min_severity=min_sev, source="db", ) def upsert_telegram_channel( db: Session, *, enabled: bool | None = None, bot_token: str | None = None, chat_id: str | None = None, min_severity: str | None = None, ) -> TelegramConfig: row = db.scalar(select(NotificationChannel).where(NotificationChannel.channel == CHANNEL_TELEGRAM)) env_cfg = _telegram_from_env() if row is None: row = NotificationChannel( channel=CHANNEL_TELEGRAM, enabled=env_cfg.enabled, bot_token=env_cfg.bot_token or None, chat_id=env_cfg.chat_id or None, min_severity=env_cfg.min_severity, ) db.add(row) if enabled is not None: row.enabled = enabled if min_severity is not None: if min_severity not in VALID_SEVERITIES: raise ValueError(f"invalid min_severity: {min_severity}") row.min_severity = min_severity if bot_token is not None and bot_token.strip(): row.bot_token = bot_token.strip() if chat_id is not None and chat_id.strip(): row.chat_id = chat_id.strip() db.commit() db.refresh(row) return get_effective_telegram_config(db)