evolution-todo-api / routes /notifications.py
Asma-yaseen's picture
feat: Deploy all advanced endpoints - Phase 2 complete
80df84c
Raw
History Blame Contribute Delete
3.59 kB
"""
Notifications API (US8).
Task: US8 - Scheduled reminder retrieval
Spec: specs/database/schema.md
"""
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlmodel import Session, select
from typing import List, Optional
from datetime import datetime
from models import Notification
from db import get_session
from middleware.auth import verify_token
router = APIRouter(prefix="/api", tags=["notifications"])
@router.get("/{user_id}/notifications")
async def get_notifications(
user_id: str,
unread_only: bool = Query(True, alias="unread"),
limit: int = Query(20, le=50),
session: Session = Depends(get_session),
authenticated_user_id: str = Depends(verify_token)
):
"""
Retrieve user notifications (US8).
Args:
user_id: User ID from URL path
unread_only: Filter by unsent/unread status
limit: Number of records to return
session: Database session
authenticated_user_id: User ID from JWT token
Returns:
List of notifications
"""
# Verify user_id matches authenticated user
if user_id != authenticated_user_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Cannot access other users' notifications"
)
# Build query
query = select(Notification).where(Notification.user_id == user_id)
if unread_only:
query = query.where(Notification.sent == False)
query = query.order_by(Notification.scheduled_time.desc()).limit(limit)
notifications = session.exec(query).all()
return {
"notifications": notifications,
"count": len(notifications)
}
@router.patch("/{user_id}/notifications/{notification_id}/read")
async def mark_notification_as_read(
user_id: str,
notification_id: int,
session: Session = Depends(get_session),
authenticated_user_id: str = Depends(verify_token)
):
"""Mark a notification as read/sent."""
if user_id != authenticated_user_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Forbidden"
)
notification = session.get(Notification, notification_id)
if not notification or notification.user_id != user_id:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Notification not found"
)
notification.sent = True
notification.sent_at = datetime.utcnow()
session.add(notification)
session.commit()
session.refresh(notification)
return notification
@router.patch("/{user_id}/notifications/mark-all-read")
async def mark_all_notifications_as_read(
user_id: str,
session: Session = Depends(get_session),
authenticated_user_id: str = Depends(verify_token)
):
"""Mark all notifications as read/sent for a user."""
if user_id != authenticated_user_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Forbidden"
)
query = select(Notification).where(
Notification.user_id == user_id,
Notification.sent == False
)
notifications = session.exec(query).all()
for notification in notifications:
notification.sent = True
notification.sent_at = datetime.utcnow()
session.add(notification)
session.commit()
return {"message": f"Marked {len(notifications)} notifications as read", "count": len(notifications)}