131 lines
4 KiB
Python
131 lines
4 KiB
Python
"""Routes de notifications Web Push."""
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from pydantic import BaseModel
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.config import settings
|
|
from app.core.database import get_db
|
|
from app.core.security import get_current_membre
|
|
from app.models.push_subscription import PushSubscription
|
|
from app.services.notifications import (
|
|
NOTIFICATION_TYPES,
|
|
normalized_preferences,
|
|
notifications_configured,
|
|
send_to_subscriptions,
|
|
)
|
|
|
|
router = APIRouter(prefix="/notifications", tags=["Notifications"])
|
|
|
|
|
|
class PushSubscriptionIn(BaseModel):
|
|
endpoint: str
|
|
expirationTime: int | None = None
|
|
keys: dict
|
|
|
|
|
|
class NotificationPreferencesIn(BaseModel):
|
|
preferences: dict[str, bool]
|
|
|
|
|
|
@router.get("/configuration")
|
|
async def configuration_notifications():
|
|
return {
|
|
"enabled": notifications_configured(),
|
|
"public_key": settings.VAPID_PUBLIC_KEY,
|
|
}
|
|
|
|
|
|
@router.get("/preferences")
|
|
async def lire_preferences_notifications(membre=Depends(get_current_membre)):
|
|
return {
|
|
"types": NOTIFICATION_TYPES,
|
|
"preferences": normalized_preferences(membre.notification_preferences),
|
|
}
|
|
|
|
|
|
@router.patch("/preferences")
|
|
async def modifier_preferences_notifications(
|
|
req: NotificationPreferencesIn,
|
|
membre=Depends(get_current_membre),
|
|
):
|
|
current = normalized_preferences(membre.notification_preferences)
|
|
for item in NOTIFICATION_TYPES:
|
|
code = item["code"]
|
|
if code in req.preferences:
|
|
current[code] = bool(req.preferences[code])
|
|
membre.notification_preferences = current
|
|
return {
|
|
"types": NOTIFICATION_TYPES,
|
|
"preferences": current,
|
|
}
|
|
|
|
|
|
@router.post("/abonnement")
|
|
async def enregistrer_abonnement(
|
|
abonnement: PushSubscriptionIn,
|
|
request: Request,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
if not notifications_configured():
|
|
raise HTTPException(status_code=400, detail="Les notifications ne sont pas configurées sur ce serveur")
|
|
result = await db.execute(select(PushSubscription).where(PushSubscription.endpoint == abonnement.endpoint))
|
|
sub = result.scalar_one_or_none()
|
|
if sub:
|
|
sub.groupe_id = membre.groupe_id
|
|
sub.membre_id = membre.id
|
|
sub.abonnement = abonnement.model_dump()
|
|
sub.user_agent = (request.headers.get("user-agent") or "")[:255] or None
|
|
else:
|
|
db.add(PushSubscription(
|
|
groupe_id=membre.groupe_id,
|
|
membre_id=membre.id,
|
|
endpoint=abonnement.endpoint,
|
|
abonnement=abonnement.model_dump(),
|
|
user_agent=(request.headers.get("user-agent") or "")[:255] or None,
|
|
))
|
|
membre.push_sub = abonnement.model_dump()
|
|
await db.flush()
|
|
return {"message": "Notifications activées"}
|
|
|
|
|
|
@router.delete("/abonnement")
|
|
async def retirer_abonnement(
|
|
endpoint: str,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(
|
|
select(PushSubscription).where(
|
|
PushSubscription.endpoint == endpoint,
|
|
PushSubscription.membre_id == membre.id,
|
|
PushSubscription.groupe_id == membre.groupe_id,
|
|
)
|
|
)
|
|
sub = result.scalar_one_or_none()
|
|
if sub:
|
|
await db.delete(sub)
|
|
membre.push_sub = None
|
|
await db.flush()
|
|
return {"message": "Notifications désactivées"}
|
|
|
|
|
|
@router.post("/test")
|
|
async def envoyer_test(
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(
|
|
select(PushSubscription).where(
|
|
PushSubscription.membre_id == membre.id,
|
|
PushSubscription.groupe_id == membre.groupe_id,
|
|
)
|
|
)
|
|
sent = await send_to_subscriptions(db, result.scalars().all(), {
|
|
"title": "Notifications activées",
|
|
"body": "Cet appareil recevra les avis du groupe.",
|
|
"url": "/",
|
|
})
|
|
await db.flush()
|
|
return {"message": "Notification de test envoyée", "sent": sent}
|