"""Notification API endpoints.""" import json from typing import Any, Optional from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session from app.dependencies import get_db, get_current_user, get_current_superuser from app.models.user import User from app import crud from app.schemas.notification import ( Notification, NotificationCreate, NotificationCreateForUser, NotificationList, NotificationStats, NotificationBulkAction ) router = APIRouter() def serialize_notification(db_obj) -> dict: """Serialize notification for response.""" metadata = None if db_obj.metadata: try: metadata = json.loads(db_obj.metadata) except json.JSONDecodeError: metadata = None return { "id": db_obj.id, "user_id": db_obj.user_id, "title": db_obj.title, "message": db_obj.message, "type": db_obj.type, "link": db_obj.link, "metadata": metadata, "is_read": db_obj.is_read, "created_at": db_obj.created_at, "read_at": db_obj.read_at } @router.get("", response_model=NotificationList) def get_notifications( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), unread_only: bool = False ) -> Any: """ Get notifications for the current user. """ notifications = crud.notification.get_multi_by_user( db, user_id=current_user.id, skip=skip, limit=limit, unread_only=unread_only ) total = crud.notification.count_by_user(db, current_user.id) unread_count = crud.notification.count_unread_by_user(db, current_user.id) return { "items": [serialize_notification(n) for n in notifications], "total": total, "unread_count": unread_count } @router.get("/unread-count") def get_unread_count( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Get unread notification count for the current user. """ count = crud.notification.count_unread_by_user(db, current_user.id) return {"unread_count": count} @router.get("/stats", response_model=NotificationStats) def get_notification_stats( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Get notification statistics for the current user. """ return crud.notification.get_stats_by_user(db, current_user.id) @router.get("/{notification_id}", response_model=Notification) def get_notification( notification_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Get a specific notification. """ db_obj = crud.notification.get(db, id=notification_id) if not db_obj or db_obj.user_id != current_user.id: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Notification not found" ) return serialize_notification(db_obj) @router.post("/{notification_id}/read", response_model=Notification) def mark_as_read( notification_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Mark a notification as read. """ db_obj = crud.notification.mark_as_read( db, id=notification_id, user_id=current_user.id ) if not db_obj: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Notification not found" ) return serialize_notification(db_obj) @router.post("/read-all") def mark_all_as_read( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Mark all notifications as read. """ count = crud.notification.mark_all_as_read(db, user_id=current_user.id) return {"marked_as_read": count} @router.post("/read-multiple") def mark_multiple_as_read( action: NotificationBulkAction, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Mark multiple notifications as read. """ count = crud.notification.mark_multiple_as_read( db, user_id=current_user.id, notification_ids=action.notification_ids ) return {"marked_as_read": count} @router.delete("/{notification_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_notification( notification_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> None: """ Delete a notification. """ if not crud.notification.delete(db, id=notification_id, user_id=current_user.id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Notification not found" ) @router.delete("/read/all") def delete_all_read( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Delete all read notifications. """ count = crud.notification.delete_all_read(db, user_id=current_user.id) return {"deleted": count} @router.post("/delete-multiple") def delete_multiple( action: NotificationBulkAction, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ) -> Any: """ Delete multiple notifications. """ count = crud.notification.delete_multiple( db, user_id=current_user.id, notification_ids=action.notification_ids ) return {"deleted": count} # Admin endpoints @router.post("/admin/send", status_code=status.HTTP_201_CREATED) def send_notification_to_user( notification_in: NotificationCreate, db: Session = Depends(get_db), current_user: User = Depends(get_current_superuser), ) -> Any: """ Send a notification to a specific user (admin only). """ db_obj = crud.notification.create(db, obj_in=notification_in) return serialize_notification(db_obj) @router.post("/admin/broadcast") def broadcast_notification( notification_in: NotificationCreateForUser, db: Session = Depends(get_db), current_user: User = Depends(get_current_superuser), ) -> Any: """ Send a notification to all users (admin only). """ count = crud.notification.create_for_all_users( db, title=notification_in.title, message=notification_in.message, type=notification_in.type, link=notification_in.link, metadata=notification_in.metadata ) return {"sent_to": count}