Added context processor, management command, and supporting models/views to enable Web Push notifications and VAPID key generation.
56 lines
1.7 KiB
Python
56 lines
1.7 KiB
Python
import logging
|
|
|
|
from django.conf import settings
|
|
from pywebpush import WebPushException, webpush
|
|
|
|
from src.notifications.models import PushSubscription
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _get_vapid_private_key():
|
|
raw = settings.VAPID_PRIVATE_KEY
|
|
if not raw:
|
|
return None
|
|
return raw.replace("\\n", "\n")
|
|
|
|
|
|
def send_push_notification(user, title, body, url=None, icon=None):
|
|
private_key = _get_vapid_private_key()
|
|
if not settings.VAPID_PUBLIC_KEY or not private_key:
|
|
logger.warning("VAPID keys not configured; skipping push notification")
|
|
return
|
|
|
|
payload = {
|
|
"title": title,
|
|
"body": body,
|
|
"icon": icon or "/static/img/favicon.png",
|
|
"badge": "/static/img/favicon.png",
|
|
}
|
|
if url:
|
|
payload["data"] = {"url": url}
|
|
|
|
subscriptions = PushSubscription.objects.filter(user=user)
|
|
if not subscriptions.exists():
|
|
return
|
|
|
|
for sub in subscriptions:
|
|
try:
|
|
webpush(
|
|
subscription_info={
|
|
"endpoint": sub.endpoint,
|
|
"keys": {"auth": sub.auth_key, "p256dh": sub.p256dh_key},
|
|
},
|
|
data=payload,
|
|
vapid_private_key=private_key,
|
|
vapid_claims=settings.VAPID_CLAIMS,
|
|
)
|
|
except WebPushException as e:
|
|
if e.response and e.response.status_code in (410, 404):
|
|
logger.info("Removing expired push subscription for %s", user)
|
|
sub.delete()
|
|
else:
|
|
logger.error("Web push failed for %s: %s", user, e)
|
|
except Exception as e:
|
|
logger.error("Unexpected error sending push to %s: %s", user, e)
|