feat: add apprise notification delivery

This commit is contained in:
Christian Krakau-Louis
2026-05-22 22:42:29 +02:00
parent 701a3603b5
commit dd4b90c9de
9 changed files with 320 additions and 162 deletions
+65
View File
@@ -49,6 +49,8 @@ class TestSettingsAPI:
assert "general.app_name" in keys
assert "dmarc.default_policy" in keys
assert "cloudflare.api_token" in keys
assert "notifications.apprise_enabled" in keys
assert "notifications.apprise_urls" in keys
def test_list_settings_filter_by_category(self, authed_client: TestClient):
"""GET /api/v1/settings?category=dmarc returns only dmarc settings."""
@@ -125,6 +127,17 @@ class TestSettingsAPI:
assert res.status_code == 200
assert res.json()["value"] == "**redacted**"
def test_apprise_urls_are_redacted_in_response(self, authed_client: TestClient):
"""Apprise target URLs are treated as notification secrets."""
authed_client.get("/api/v1/settings")
authed_client.put(
"/api/v1/settings/notifications.apprise_urls",
json={"value": "mailto://user:password@example.com"},
)
res = authed_client.get("/api/v1/settings/notifications.apprise_urls")
assert res.status_code == 200
assert res.json()["value"] == "**redacted**"
def test_redacted_placeholder_does_not_overwrite(self, authed_client: TestClient):
"""Sending **redacted** back to PUT should not overwrite the stored value."""
authed_client.get("/api/v1/settings")
@@ -148,3 +161,55 @@ class TestSettingsAPI:
"""Unauthenticated requests to settings endpoints return 403."""
res = client.get("/api/v1/settings")
assert res.status_code in (401, 403)
def test_test_notification_sends_via_apprise(self, authed_client: TestClient, monkeypatch):
"""POST /settings/notifications/test sends a sanitized Apprise test notification."""
class FakeApprise:
instances = []
def __init__(self):
self.urls = []
self.messages = []
FakeApprise.instances.append(self)
def add(self, url):
self.urls.append(url)
return True
def notify(self, *, title, body):
self.messages.append({"title": title, "body": body})
return True
monkeypatch.setattr("app.services.notifications.apprise.Apprise", FakeApprise)
authed_client.get("/api/v1/settings")
authed_client.post(
"/api/v1/settings/bulk",
json={
"settings": {
"notifications.apprise_enabled": "true",
"notifications.apprise_urls": "mailto://user:password@example.com",
}
},
)
res = authed_client.post("/api/v1/settings/notifications/test")
assert res.status_code == 200
data = res.json()
assert data["success"] is True
assert data["configured_targets"] == 1
assert "password" not in str(data)
assert FakeApprise.instances[0].messages[0]["title"] == "DMARQ test notification"
def test_test_notification_without_targets_returns_400(self, authed_client: TestClient):
"""Test notification returns a useful error when no target is configured."""
authed_client.get("/api/v1/settings")
res = authed_client.post("/api/v1/settings/notifications/test")
assert res.status_code == 400
detail = res.json()["detail"]
assert detail["success"] is False
assert detail["message"] == "No notification targets are configured."