from typing import Optional from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session from app.core.database import get_db from app.models import User, Notification from app.schemas.notification import ( NotificationResponse, NotificationListResponse, UnreadCountResponse ) from app.middleware.auth import get_current_user router = APIRouter(tags=["notifications"]) def notification_to_response(notification: Notification) -> NotificationResponse: """Convert Notification model to NotificationResponse.""" return NotificationResponse( id=notification.id, type=notification.type, reference_type=notification.reference_type, reference_id=notification.reference_id, title=notification.title, message=notification.message, is_read=notification.is_read, created_at=notification.created_at, read_at=notification.read_at, ) @router.get("/api/notifications", response_model=NotificationListResponse) async def list_notifications( is_read: Optional[bool] = Query(None, description="Filter by read status"), limit: int = Query(50, ge=1, le=100, description="Number of notifications to return"), offset: int = Query(0, ge=0, description="Offset for pagination"), db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """List notifications for the current user.""" query = db.query(Notification).filter(Notification.user_id == current_user.id) if is_read is not None: query = query.filter(Notification.is_read == is_read) total = query.count() unread_count = db.query(Notification).filter( Notification.user_id == current_user.id, Notification.is_read == False, ).count() notifications = query.order_by(Notification.created_at.desc()).offset(offset).limit(limit).all() return NotificationListResponse( notifications=[notification_to_response(n) for n in notifications], total=total, unread_count=unread_count, ) @router.get("/api/notifications/unread-count", response_model=UnreadCountResponse) async def get_unread_count( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Get count of unread notifications.""" count = db.query(Notification).filter( Notification.user_id == current_user.id, Notification.is_read == False, ).count() return UnreadCountResponse(unread_count=count) @router.put("/api/notifications/{notification_id}/read", response_model=NotificationResponse) async def mark_as_read( notification_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Mark a notification as read.""" notification = db.query(Notification).filter( Notification.id == notification_id, Notification.user_id == current_user.id, ).first() if not notification: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Notification not found", ) if not notification.is_read: notification.is_read = True notification.read_at = datetime.utcnow() db.commit() db.refresh(notification) return notification_to_response(notification) @router.put("/api/notifications/read-all", response_model=dict) async def mark_all_as_read( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """Mark all notifications as read.""" now = datetime.utcnow() updated_count = db.query(Notification).filter( Notification.user_id == current_user.id, Notification.is_read == False, ).update({ Notification.is_read: True, Notification.read_at: now, }) db.commit() return {"updated_count": updated_count}