"""Dispatch ingest notifications per global policy (severity → channels).""" import logging from sqlalchemy.orm import Session from app.models import Event, Problem from app.services import email_notify, telegram_notify, webhook_notify from app.services.notification_cooldown import should_notify_event, should_notify_problem from app.services.notification_policy import get_effective_notification_policy from app.services.notification_severity import severity_meets_minimum logger = logging.getLogger(__name__) LIFECYCLE_EVENT_TYPE = "agent.lifecycle" def _event_telegram_via_agent(event: Event) -> bool: details = event.details if isinstance(event.details, dict) else {} via = str(details.get("telegram_via") or "").strip().lower() return via == "agent" def _dispatch_event_channels(event: Event, *, db: Session | None, policy) -> None: if policy.use_telegram: telegram_notify.notify_event(event, db=db, apply_policy_gate=False) if policy.use_webhook: webhook_notify.notify_event(event, db=db, apply_policy_gate=False) if policy.use_email: email_notify.notify_event(event, db=db, apply_policy_gate=False) def _dispatch_problem_channels(problem: Problem, event: Event | None, *, db: Session | None, policy) -> None: if policy.use_telegram: telegram_notify.notify_problem(problem, event, db=db, apply_policy_gate=False) if policy.use_webhook: webhook_notify.notify_problem(problem, event, db=db, apply_policy_gate=False) if policy.use_email: email_notify.notify_problem(problem, event, db=db, apply_policy_gate=False) def notify_event(event: Event, *, db: Session | None = None) -> None: policy = get_effective_notification_policy(db) if not severity_meets_minimum(event.severity, policy.min_severity): return if not should_notify_event(event, db): return _dispatch_event_channels(event, db=db, policy=policy) def notify_problem(problem: Problem, event: Event | None = None, *, db: Session | None = None) -> None: policy = get_effective_notification_policy(db) if not severity_meets_minimum(problem.severity, policy.min_severity): return if not should_notify_problem(problem, db): return _dispatch_problem_channels(problem, event, db=db, policy=policy) def _dispatch_lifecycle_channels(event: Event, *, db: Session | None, policy) -> None: skip_telegram = _event_telegram_via_agent(event) if policy.use_telegram and not skip_telegram: telegram_notify.notify_event(event, db=db, apply_policy_gate=False) if policy.use_webhook: webhook_notify.notify_event(event, db=db, apply_policy_gate=False) if policy.use_email: email_notify.notify_event(event, db=db, apply_policy_gate=False) def notify_daily_report(event: Event, *, db: Session | None = None) -> None: """Оповещение по суточному отчёту (severity=info, вне порога policy).""" policy = get_effective_notification_policy(db) if not should_notify_event(event, db): return _dispatch_event_channels(event, db=db, policy=policy) def notify_lifecycle(event: Event, *, db: Session | None = None) -> None: """Старт/стоп/reload агента — всегда в каналы SAC (кроме TG, если telegram_via=agent).""" policy = get_effective_notification_policy(db) if not should_notify_event(event, db): return _dispatch_lifecycle_channels(event, db=db, policy=policy)