feat: replace Web Push with ntfy for medication reminders
Single notification path via ntfy HTTP publish for reliable Android delivery; remove VAPID, push subscriptions, and SW push handlers. PWA settings show topic subscribe link; humor texts and deep-link actions unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
import httpx
|
||||
|
||||
from server.settings import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _publish_url() -> str | None:
|
||||
if not settings.ntfy_url or not settings.ntfy_topic:
|
||||
return None
|
||||
return f"{settings.ntfy_url.rstrip('/')}/{settings.ntfy_topic}"
|
||||
|
||||
|
||||
def _click_base() -> str:
|
||||
return settings.ntfy_click_url.rstrip("/")
|
||||
|
||||
|
||||
async def send_slot_reminder(
|
||||
slot_id: str,
|
||||
title: str,
|
||||
body: str,
|
||||
*,
|
||||
silent: bool = True,
|
||||
) -> int:
|
||||
url = _publish_url()
|
||||
if not url:
|
||||
logger.warning(
|
||||
"Notify skipped slot=%s reason=ntfy_not_configured (NTFY_URL + NTFY_TOPIC)",
|
||||
slot_id,
|
||||
)
|
||||
return 0
|
||||
|
||||
click_base = _click_base()
|
||||
headers: dict[str, str] = {
|
||||
"Title": title,
|
||||
"Click": f"{click_base}/?slot={slot_id}",
|
||||
"Priority": "2" if silent else "3",
|
||||
"Tags": "pill",
|
||||
"Actions": json.dumps(
|
||||
[
|
||||
{
|
||||
"action": "view",
|
||||
"label": "Genommen ✓",
|
||||
"url": f"{click_base}/?action=take&slot={slot_id}",
|
||||
},
|
||||
{
|
||||
"action": "view",
|
||||
"label": "+15 Min",
|
||||
"url": f"{click_base}/?action=snooze&slot={slot_id}&minutes=15",
|
||||
},
|
||||
{
|
||||
"action": "view",
|
||||
"label": "+30 Min",
|
||||
"url": f"{click_base}/?action=snooze&slot={slot_id}&minutes=30",
|
||||
},
|
||||
]
|
||||
),
|
||||
}
|
||||
if settings.ntfy_token:
|
||||
headers["Authorization"] = f"Bearer {settings.ntfy_token}"
|
||||
|
||||
logger.info("Notify start slot=%s title=%r topic=%s", slot_id, title, settings.ntfy_topic)
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
resp = await client.post(url, content=body.encode("utf-8"), headers=headers)
|
||||
resp.raise_for_status()
|
||||
except httpx.HTTPError as exc:
|
||||
logger.warning("Notify failed slot=%s error=%s", slot_id, exc)
|
||||
return 0
|
||||
|
||||
logger.info("Notify ok slot=%s", slot_id)
|
||||
return 1
|
||||
Reference in New Issue
Block a user