feat: Telegram settings in DB with UI edit and test send

Store notification_channels (migration 004), effective config DB over env,
PUT/test API endpoints, Settings form, and pass db session into ingest notify.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
PTah
2026-05-29 16:05:32 +10:00
parent e0ba384705
commit 79a78dc7c9
12 changed files with 564 additions and 116 deletions
+73 -3
View File
@@ -1,6 +1,10 @@
"""GET /api/v1/settings/notifications"""
"""GET/PUT/POST /api/v1/settings/notifications"""
from app.services.telegram_notify import get_settings
from unittest.mock import patch
from app.config import get_settings
from app.models.notification_channel import NotificationChannel
from app.services.notification_settings import get_effective_telegram_config
def test_get_notification_settings_masks_secrets(jwt_headers, client, monkeypatch):
@@ -18,4 +22,70 @@ def test_get_notification_settings_masks_secrets(jwt_headers, client, monkeypatc
assert body["telegram"]["min_severity"] == "warning"
assert body["telegram"]["source"] == "env"
assert body["telegram"]["bot_token_hint"].endswith("ghij")
assert "1234567890" not in body["telegram"]["bot_token_hint"]
def test_put_telegram_settings_persists_db(jwt_headers, client, db_session, monkeypatch):
monkeypatch.setenv("TELEGRAM_ENABLED", "false")
monkeypatch.setenv("TELEGRAM_BOT_TOKEN", "")
monkeypatch.setenv("TELEGRAM_CHAT_ID", "")
monkeypatch.setenv("TELEGRAM_MIN_SEVERITY", "high")
get_settings.cache_clear()
response = client.put(
"/api/v1/settings/notifications/telegram",
headers=jwt_headers,
json={
"enabled": True,
"min_severity": "warning",
"bot_token": "1234567890:TESTTOKEN",
"chat_id": "999001",
},
)
assert response.status_code == 200
body = response.json()
assert body["source"] == "db"
assert body["enabled"] is True
assert body["min_severity"] == "warning"
row = db_session.get(NotificationChannel, "telegram")
assert row is not None
assert row.bot_token == "1234567890:TESTTOKEN"
assert row.chat_id == "999001"
cfg = get_effective_telegram_config(db_session)
assert cfg.source == "db"
assert cfg.min_severity == "warning"
def test_post_telegram_test_success(jwt_headers, client, db_session, monkeypatch):
monkeypatch.setenv("TELEGRAM_ENABLED", "true")
monkeypatch.setenv("TELEGRAM_BOT_TOKEN", "tok")
monkeypatch.setenv("TELEGRAM_CHAT_ID", "1")
get_settings.cache_clear()
db_session.add(
NotificationChannel(
channel="telegram",
enabled=True,
min_severity="warning",
bot_token="1234567890:ABCDEF",
chat_id="2843230",
)
)
db_session.commit()
with patch("app.api.v1.settings.send_telegram_test_message") as mock_test:
response = client.post("/api/v1/settings/notifications/telegram/test", headers=jwt_headers)
assert response.status_code == 200
assert response.json()["ok"] is True
mock_test.assert_called_once()
def test_post_telegram_test_not_configured(jwt_headers, client, monkeypatch):
monkeypatch.setenv("TELEGRAM_ENABLED", "false")
monkeypatch.setenv("TELEGRAM_BOT_TOKEN", "")
monkeypatch.setenv("TELEGRAM_CHAT_ID", "")
get_settings.cache_clear()
response = client.post("/api/v1/settings/notifications/telegram/test", headers=jwt_headers)
assert response.status_code == 400
+30 -27
View File
@@ -3,24 +3,27 @@
from datetime import datetime, timezone
from unittest.mock import patch
import pytest
from app.models import Event, Host, Problem
from app.models import Event, Problem
from app.services import telegram_notify
from app.services.notification_settings import TelegramConfig
def test_notify_event_respects_min_severity(monkeypatch):
def _telegram_cfg(*, min_severity: str) -> TelegramConfig:
return TelegramConfig(
enabled=True,
bot_token="test-token",
chat_id="123",
min_severity=min_severity,
source="env",
)
def test_notify_event_respects_min_severity():
sent: list[str] = []
def fake_send(message: str) -> None:
def fake_send(message: str, **kwargs) -> None:
sent.append(message)
monkeypatch.setenv("TELEGRAM_ENABLED", "true")
monkeypatch.setenv("TELEGRAM_BOT_TOKEN", "test-token")
monkeypatch.setenv("TELEGRAM_CHAT_ID", "123")
monkeypatch.setenv("TELEGRAM_MIN_SEVERITY", "warning")
telegram_notify.get_settings.cache_clear()
event = Event(
event_id="00000000-0000-4000-8000-000000000001",
host_id=1,
@@ -33,28 +36,25 @@ def test_notify_event_respects_min_severity(monkeypatch):
payload={},
)
with patch.object(telegram_notify, "_send_text", side_effect=fake_send):
telegram_notify.notify_event(event)
cfg = _telegram_cfg(min_severity="warning")
with patch.object(telegram_notify, "get_effective_telegram_config", return_value=cfg):
with patch.object(telegram_notify, "send_telegram_text", side_effect=fake_send):
telegram_notify.notify_event(event)
assert sent == []
event.severity = "warning"
with patch.object(telegram_notify, "_send_text", side_effect=fake_send):
telegram_notify.notify_event(event)
with patch.object(telegram_notify, "get_effective_telegram_config", return_value=cfg):
with patch.object(telegram_notify, "send_telegram_text", side_effect=fake_send):
telegram_notify.notify_event(event)
assert len(sent) == 1
def test_notify_problem_respects_min_severity(monkeypatch):
def test_notify_problem_respects_min_severity():
sent: list[str] = []
def fake_send(message: str) -> None:
def fake_send(message: str, **kwargs) -> None:
sent.append(message)
monkeypatch.setenv("TELEGRAM_ENABLED", "true")
monkeypatch.setenv("TELEGRAM_BOT_TOKEN", "test-token")
monkeypatch.setenv("TELEGRAM_CHAT_ID", "123")
monkeypatch.setenv("TELEGRAM_MIN_SEVERITY", "high")
telegram_notify.get_settings.cache_clear()
problem = Problem(
title="brute",
summary="burst",
@@ -63,11 +63,14 @@ def test_notify_problem_respects_min_severity(monkeypatch):
fingerprint="fp1",
)
with patch.object(telegram_notify, "_send_text", side_effect=fake_send):
telegram_notify.notify_problem(problem)
cfg = _telegram_cfg(min_severity="high")
with patch.object(telegram_notify, "get_effective_telegram_config", return_value=cfg):
with patch.object(telegram_notify, "send_telegram_text", side_effect=fake_send):
telegram_notify.notify_problem(problem)
assert sent == []
problem.severity = "high"
with patch.object(telegram_notify, "_send_text", side_effect=fake_send):
telegram_notify.notify_problem(problem)
with patch.object(telegram_notify, "get_effective_telegram_config", return_value=cfg):
with patch.object(telegram_notify, "send_telegram_text", side_effect=fake_send):
telegram_notify.notify_problem(problem)
assert len(sent) == 1