from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from sqlalchemy import desc from typing import List, Optional from datetime import datetime, timedelta from database import get_db from models.user import User from models.activity import Activity, ActivityType from models.project import ProjectMember from schemas.activity import ActivityResponse from utils.auth import get_current_user from utils.activity import ActivityService router = APIRouter(prefix="/activities", tags=["activities"]) @router.get("/project/{project_id}", response_model=List[ActivityResponse]) def get_project_activities( project_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), type_filter: Optional[ActivityType] = None, days: Optional[int] = Query(None, ge=1, le=90), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get activity feed for a specific project (excludes activities for deleted records).""" # Verify user has access to the project member = db.query(ProjectMember).filter( ProjectMember.project_id == project_id, ProjectMember.user_id == current_user.id ).first() if not member and not current_user.is_admin: from fastapi import HTTPException raise HTTPException(status_code=403, detail="Access denied to this project") # Use ActivityService to get activities excluding deleted records activities = ActivityService.get_activities_excluding_deleted( db=db, project_id=project_id, skip=skip, limit=limit, type_filter=type_filter, days=days ) return activities @router.get("/task/{task_id}", response_model=List[ActivityResponse]) def get_task_activities( task_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get activity timeline for a specific task (excludes activities for deleted records).""" from models.task import Task # Verify user has access to the task and it's not deleted task = db.query(Task).filter(Task.id == task_id, Task.deleted_at.is_(None)).first() if not task: from fastapi import HTTPException raise HTTPException(status_code=404, detail="Task not found") # Check if user is a member of the project member = db.query(ProjectMember).filter( ProjectMember.project_id == task.project_id, ProjectMember.user_id == current_user.id ).first() if not member and not current_user.is_admin: from fastapi import HTTPException raise HTTPException(status_code=403, detail="Access denied to this task") # Use ActivityService to get activities excluding deleted records activities = ActivityService.get_activities_excluding_deleted( db=db, task_id=task_id, skip=skip, limit=limit ) return activities @router.get("/user/{user_id}", response_model=List[ActivityResponse]) def get_user_activities( user_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), days: Optional[int] = Query(None, ge=1, le=90), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get activity history for a specific user (excludes activities for deleted records).""" # Users can only view their own activity unless they're admin if user_id != current_user.id and not current_user.is_admin: from fastapi import HTTPException raise HTTPException(status_code=403, detail="Access denied") # Use ActivityService to get activities excluding deleted records activities = ActivityService.get_activities_excluding_deleted( db=db, user_id=user_id, skip=skip, limit=limit, days=days ) return activities @router.get("/recent", response_model=List[ActivityResponse]) def get_recent_activities( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=50), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get recent activities from all projects the user has access to (excludes activities for deleted records).""" # Get all projects the user is a member of project_ids = db.query(ProjectMember.project_id).filter( ProjectMember.user_id == current_user.id ).all() project_ids = [pid[0] for pid in project_ids] if not project_ids and not current_user.is_admin: return [] # For non-admin users, filter by their project access if not current_user.is_admin: # Get activities from user's projects, excluding deleted records all_activities = [] for project_id in project_ids: activities = ActivityService.get_activities_excluding_deleted( db=db, project_id=project_id, skip=0, limit=limit * 2 # Get more to account for filtering ) all_activities.extend(activities) # Sort by created_at and apply pagination all_activities.sort(key=lambda x: x.created_at, reverse=True) return all_activities[skip:skip + limit] else: # Admin gets all activities excluding deleted records activities = ActivityService.get_activities_excluding_deleted( db=db, skip=skip, limit=limit ) return activities # Admin-only endpoints that include activities for deleted records @router.get("/admin/project/{project_id}/all", response_model=List[ActivityResponse]) def get_project_activities_including_deleted( project_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), type_filter: Optional[ActivityType] = None, days: Optional[int] = Query(None, ge=1, le=90), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get all activity feed for a specific project including deleted records (admin only).""" if not current_user.is_admin: from fastapi import HTTPException raise HTTPException(status_code=403, detail="Admin access required") # Use ActivityService to get all activities including deleted records activities = ActivityService.get_activities_including_deleted( db=db, project_id=project_id, skip=skip, limit=limit, type_filter=type_filter, days=days ) return activities @router.get("/admin/user/{user_id}/all", response_model=List[ActivityResponse]) def get_user_activities_including_deleted( user_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), days: Optional[int] = Query(None, ge=1, le=90), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get all activity history for a specific user including deleted records (admin only).""" if not current_user.is_admin: from fastapi import HTTPException raise HTTPException(status_code=403, detail="Admin access required") # Use ActivityService to get all activities including deleted records activities = ActivityService.get_activities_including_deleted( db=db, user_id=user_id, skip=skip, limit=limit, days=days ) return activities @router.get("/admin/all", response_model=List[ActivityResponse]) def get_all_activities_including_deleted( skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), type_filter: Optional[ActivityType] = None, days: Optional[int] = Query(None, ge=1, le=90), db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get all activities including deleted records (admin only).""" if not current_user.is_admin: from fastapi import HTTPException raise HTTPException(status_code=403, detail="Admin access required") # Use ActivityService to get all activities including deleted records activities = ActivityService.get_activities_including_deleted( db=db, skip=skip, limit=limit, type_filter=type_filter, days=days ) return activities