563b836acc
Adds mobile device registration by admin codes, refresh tokens, push channel in notification policy, and Settings section for managing Seaca clients. Co-authored-by: Cursor <cursoragent@cursor.com>
141 lines
4.2 KiB
Python
141 lines
4.2 KiB
Python
"""Global notification policy: severity ≥ min → selected channels."""
|
|
|
|
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
|
|
from app.models.notification_policy import POLICY_ROW_ID, NotificationPolicy
|
|
from app.services.notification_settings import (
|
|
CHANNEL_EMAIL,
|
|
CHANNEL_TELEGRAM,
|
|
CHANNEL_WEBHOOK,
|
|
VALID_SEVERITIES,
|
|
)
|
|
|
|
CHANNEL_MOBILE = "mobile"
|
|
DEFAULT_CHANNELS = frozenset({CHANNEL_TELEGRAM, CHANNEL_WEBHOOK, CHANNEL_EMAIL, CHANNEL_MOBILE})
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class NotificationPolicyConfig:
|
|
min_severity: str
|
|
use_telegram: bool
|
|
use_webhook: bool
|
|
use_email: bool
|
|
use_mobile: bool
|
|
source: str # env | db
|
|
|
|
def allows_channel(self, channel: str) -> bool:
|
|
if channel == CHANNEL_TELEGRAM:
|
|
return self.use_telegram
|
|
if channel == CHANNEL_WEBHOOK:
|
|
return self.use_webhook
|
|
if channel == CHANNEL_EMAIL:
|
|
return self.use_email
|
|
if channel == CHANNEL_MOBILE:
|
|
return self.use_mobile
|
|
return False
|
|
|
|
|
|
def _parse_channels_csv(value: str) -> tuple[bool, bool, bool, bool]:
|
|
parts = {p.strip().lower() for p in value.split(",") if p.strip()}
|
|
return (
|
|
CHANNEL_TELEGRAM in parts or "tg" in parts,
|
|
CHANNEL_WEBHOOK in parts,
|
|
CHANNEL_EMAIL in parts or "mail" in parts or "smtp" in parts,
|
|
CHANNEL_MOBILE in parts or "push" in parts or "fcm" in parts,
|
|
)
|
|
|
|
|
|
def _policy_from_env() -> NotificationPolicyConfig:
|
|
settings = get_settings()
|
|
use_tg, use_wh, use_em, use_mob = _parse_channels_csv(settings.notify_channels)
|
|
min_sev = settings.notify_min_severity.strip() or "warning"
|
|
if min_sev not in VALID_SEVERITIES:
|
|
min_sev = "warning"
|
|
return NotificationPolicyConfig(
|
|
min_severity=min_sev,
|
|
use_telegram=use_tg,
|
|
use_webhook=use_wh,
|
|
use_email=use_em,
|
|
use_mobile=use_mob,
|
|
source="env",
|
|
)
|
|
|
|
|
|
def get_effective_notification_policy(db: Session | None = None) -> NotificationPolicyConfig:
|
|
if db is None:
|
|
from app.database import SessionLocal
|
|
|
|
session = SessionLocal()
|
|
try:
|
|
return get_effective_notification_policy(session)
|
|
finally:
|
|
session.close()
|
|
|
|
row = db.get(NotificationPolicy, POLICY_ROW_ID)
|
|
env_cfg = _policy_from_env()
|
|
if row is None:
|
|
return env_cfg
|
|
|
|
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 NotificationPolicyConfig(
|
|
min_severity=min_sev,
|
|
use_telegram=bool(row.use_telegram),
|
|
use_webhook=bool(row.use_webhook),
|
|
use_email=bool(row.use_email),
|
|
use_mobile=bool(getattr(row, "use_mobile", False)),
|
|
source="db",
|
|
)
|
|
|
|
|
|
def _sync_channel_min_severity(db: Session, min_severity: str) -> None:
|
|
for channel in (CHANNEL_TELEGRAM, CHANNEL_WEBHOOK, CHANNEL_EMAIL):
|
|
row = db.get(NotificationChannel, channel)
|
|
if row is not None:
|
|
row.min_severity = min_severity
|
|
|
|
|
|
def upsert_notification_policy(
|
|
db: Session,
|
|
*,
|
|
min_severity: str,
|
|
use_telegram: bool,
|
|
use_webhook: bool,
|
|
use_email: bool,
|
|
use_mobile: bool = False,
|
|
) -> NotificationPolicyConfig:
|
|
if min_severity not in VALID_SEVERITIES:
|
|
raise ValueError(f"invalid min_severity: {min_severity}")
|
|
|
|
row = db.get(NotificationPolicy, POLICY_ROW_ID)
|
|
if row is None:
|
|
row = NotificationPolicy(
|
|
id=POLICY_ROW_ID,
|
|
min_severity=min_severity,
|
|
use_telegram=use_telegram,
|
|
use_webhook=use_webhook,
|
|
use_email=use_email,
|
|
use_mobile=use_mobile,
|
|
)
|
|
db.add(row)
|
|
else:
|
|
row.min_severity = min_severity
|
|
row.use_telegram = use_telegram
|
|
row.use_webhook = use_webhook
|
|
row.use_email = use_email
|
|
row.use_mobile = use_mobile
|
|
|
|
_sync_channel_min_severity(db, min_severity)
|
|
db.commit()
|
|
db.refresh(row)
|
|
return get_effective_notification_policy(db)
|