from fastapi import APIRouter, Depends, HTTPException, status, Query, Request import uuid from sqlalchemy.orm import Session from typing import Optional from app.core.database import get_db from app.core.rate_limiter import limiter from app.core.config import settings from app.models import User, ReportHistory, ScheduledReport from app.schemas.report import ( WeeklyReportContent, ReportHistoryListResponse, ReportHistoryItem, GenerateReportResponse, ReportSummary, WeeklyReportSubscription, WeeklyReportSubscriptionUpdate ) from app.middleware.auth import get_current_user from app.services.report_service import ReportService router = APIRouter(tags=["reports"]) @router.get("/api/reports/weekly/subscription", response_model=WeeklyReportSubscription) async def get_weekly_report_subscription( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Get weekly report subscription status for the current user. """ scheduled_report = db.query(ScheduledReport).filter( ScheduledReport.recipient_id == current_user.id, ScheduledReport.report_type == "weekly", ).first() if not scheduled_report: return WeeklyReportSubscription(is_active=False, last_sent_at=None) return WeeklyReportSubscription( is_active=scheduled_report.is_active, last_sent_at=scheduled_report.last_sent_at, ) @router.put("/api/reports/weekly/subscription", response_model=WeeklyReportSubscription) async def update_weekly_report_subscription( subscription: WeeklyReportSubscriptionUpdate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Update weekly report subscription status for the current user. """ scheduled_report = db.query(ScheduledReport).filter( ScheduledReport.recipient_id == current_user.id, ScheduledReport.report_type == "weekly", ).first() if not scheduled_report: scheduled_report = ScheduledReport( id=str(uuid.uuid4()), report_type="weekly", recipient_id=current_user.id, is_active=subscription.is_active, ) db.add(scheduled_report) else: scheduled_report.is_active = subscription.is_active db.commit() db.refresh(scheduled_report) return WeeklyReportSubscription( is_active=scheduled_report.is_active, last_sent_at=scheduled_report.last_sent_at, ) @router.get("/api/reports/weekly/preview", response_model=WeeklyReportContent) async def preview_weekly_report( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Preview the weekly report for the current user. Shows what would be included in the next weekly report. """ content = ReportService.get_weekly_stats(db, current_user.id) return WeeklyReportContent( week_start=content["week_start"], week_end=content["week_end"], generated_at=content["generated_at"], projects=content["projects"], summary=ReportSummary(**content["summary"]), ) @router.post("/api/reports/weekly/generate", response_model=GenerateReportResponse) @limiter.limit(settings.RATE_LIMIT_HEAVY) async def generate_weekly_report( request: Request, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Manually trigger weekly report generation for the current user. Rate limited: 5 requests per minute (heavy tier). """ # Generate report report_history = ReportService.generate_weekly_report(db, current_user.id) if not report_history: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to generate report", ) # Send notification ReportService.send_report_notification(db, current_user.id, report_history.content) db.commit() summary = report_history.content.get("summary", {}) return GenerateReportResponse( message="Weekly report generated successfully", report_id=report_history.id, summary=ReportSummary( completed_count=summary.get("completed_count", 0), in_progress_count=summary.get("in_progress_count", 0), overdue_count=summary.get("overdue_count", 0), total_tasks=summary.get("total_tasks", 0), ), ) @router.get("/api/reports/history", response_model=ReportHistoryListResponse) async def list_report_history( limit: int = Query(10, ge=1, le=100, description="Number of reports to return"), offset: int = Query(0, ge=0, description="Number of reports to skip"), db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ List report history for the current user. """ # Get scheduled report for this user scheduled_report = db.query(ScheduledReport).filter( ScheduledReport.recipient_id == current_user.id, ).first() if not scheduled_report: return ReportHistoryListResponse(reports=[], total=0) # Get history total = db.query(ReportHistory).filter( ReportHistory.report_id == scheduled_report.id, ).count() history = db.query(ReportHistory).filter( ReportHistory.report_id == scheduled_report.id, ).order_by(ReportHistory.generated_at.desc()).offset(offset).limit(limit).all() return ReportHistoryListResponse( reports=[ ReportHistoryItem( id=h.id, report_id=h.report_id, generated_at=h.generated_at, content=h.content, status=h.status, error_message=h.error_message, ) for h in history ], total=total, ) @router.get("/api/reports/history/{report_id}") @limiter.limit(settings.RATE_LIMIT_SENSITIVE) async def get_report_detail( request: Request, report_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): """ Get detailed content of a specific report. Rate limited: 20 requests per minute (sensitive tier). """ report = db.query(ReportHistory).filter(ReportHistory.id == report_id).first() if not report: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Report not found", ) # Check ownership scheduled_report = report.report if scheduled_report.recipient_id != current_user.id and not current_user.is_system_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied", ) return ReportHistoryItem( id=report.id, report_id=report.report_id, generated_at=report.generated_at, content=report.content, status=report.status, error_message=report.error_message, )