"""API endpoints for scheduled task management.""" from fastapi import APIRouter, Depends, HTTPException, Query from sqlmodel.ext.asyncio.session import AsyncSession from app.core.database import get_db from app.core.dependencies import ( get_admin_user, get_current_active_user, ) from app.models.scheduled_task import ScheduledTask, TaskStatus, TaskType from app.models.user import User from app.schemas.scheduler import ( ScheduledTaskCreate, ScheduledTaskResponse, ScheduledTaskUpdate, ) from app.services.scheduler import SchedulerService router = APIRouter(prefix="/scheduler") def get_scheduler_service() -> SchedulerService: """Get the global scheduler service instance.""" from app.main import get_global_scheduler_service return get_global_scheduler_service() @router.post("/tasks", response_model=ScheduledTaskResponse) async def create_task( task_data: ScheduledTaskCreate, current_user: User = Depends(get_current_active_user), scheduler_service: SchedulerService = Depends(get_scheduler_service), ) -> ScheduledTask: """Create a new scheduled task.""" try: task = await scheduler_service.create_task( name=task_data.name, task_type=task_data.task_type, scheduled_at=task_data.scheduled_at, parameters=task_data.parameters, user_id=current_user.id, timezone=task_data.timezone, recurrence_type=task_data.recurrence_type, cron_expression=task_data.cron_expression, recurrence_count=task_data.recurrence_count, expires_at=task_data.expires_at, ) return task except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @router.get("/tasks", response_model=list[ScheduledTaskResponse]) async def get_user_tasks( status: TaskStatus | None = Query(None, description="Filter by task status"), task_type: TaskType | None = Query(None, description="Filter by task type"), limit: int | None = Query(50, description="Maximum number of tasks to return"), offset: int | None = Query(0, description="Number of tasks to skip"), current_user: User = Depends(get_current_active_user), scheduler_service: SchedulerService = Depends(get_scheduler_service), ) -> list[ScheduledTask]: """Get user's scheduled tasks.""" return await scheduler_service.get_user_tasks( user_id=current_user.id, status=status, task_type=task_type, limit=limit, offset=offset, ) @router.get("/tasks/{task_id}", response_model=ScheduledTaskResponse) async def get_task( task_id: int, current_user: User = Depends(get_current_active_user), db_session: AsyncSession = Depends(get_db), ) -> ScheduledTask: """Get a specific scheduled task.""" from app.repositories.scheduled_task import ScheduledTaskRepository repo = ScheduledTaskRepository(db_session) task = await repo.get_by_id(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") # Check if user owns the task or is admin if task.user_id != current_user.id and not current_user.is_admin: raise HTTPException(status_code=403, detail="Access denied") return task @router.patch("/tasks/{task_id}", response_model=ScheduledTaskResponse) async def update_task( task_id: int, task_update: ScheduledTaskUpdate, current_user: User = Depends(get_current_active_user), db_session: AsyncSession = Depends(get_db), ) -> ScheduledTask: """Update a scheduled task.""" from app.repositories.scheduled_task import ScheduledTaskRepository repo = ScheduledTaskRepository(db_session) task = await repo.get_by_id(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") # Check if user owns the task or is admin if task.user_id != current_user.id and not current_user.is_admin: raise HTTPException(status_code=403, detail="Access denied") # Update task fields update_data = task_update.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(task, field, value) updated_task = await repo.update(task) return updated_task @router.delete("/tasks/{task_id}") async def cancel_task( task_id: int, current_user: User = Depends(get_current_active_user), scheduler_service: SchedulerService = Depends(get_scheduler_service), db_session: AsyncSession = Depends(get_db), ) -> dict: """Cancel a scheduled task.""" from app.repositories.scheduled_task import ScheduledTaskRepository repo = ScheduledTaskRepository(db_session) task = await repo.get_by_id(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") # Check if user owns the task or is admin if task.user_id != current_user.id and not current_user.is_admin: raise HTTPException(status_code=403, detail="Access denied") success = await scheduler_service.cancel_task(task_id) if not success: raise HTTPException(status_code=400, detail="Failed to cancel task") return {"message": "Task cancelled successfully"} # Admin-only endpoints @router.get("/admin/tasks", response_model=list[ScheduledTaskResponse]) async def get_all_tasks( status: TaskStatus | None = Query(None, description="Filter by task status"), task_type: TaskType | None = Query(None, description="Filter by task type"), limit: int | None = Query(100, description="Maximum number of tasks to return"), offset: int | None = Query(0, description="Number of tasks to skip"), current_user: User = Depends(get_admin_user), db_session: AsyncSession = Depends(get_db), ) -> list[ScheduledTask]: """Get all scheduled tasks (admin only).""" from app.repositories.scheduled_task import ScheduledTaskRepository repo = ScheduledTaskRepository(db_session) # Get all tasks with pagination and filtering from sqlmodel import select statement = select(ScheduledTask) if status: statement = statement.where(ScheduledTask.status == status) if task_type: statement = statement.where(ScheduledTask.task_type == task_type) statement = statement.order_by(ScheduledTask.scheduled_at.desc()) if offset: statement = statement.offset(offset) if limit: statement = statement.limit(limit) result = await db_session.exec(statement) return list(result.all()) @router.get("/admin/system-tasks", response_model=list[ScheduledTaskResponse]) async def get_system_tasks( status: TaskStatus | None = Query(None, description="Filter by task status"), task_type: TaskType | None = Query(None, description="Filter by task type"), current_user: User = Depends(get_admin_user), db_session: AsyncSession = Depends(get_db), ) -> list[ScheduledTask]: """Get system tasks (admin only).""" from app.repositories.scheduled_task import ScheduledTaskRepository repo = ScheduledTaskRepository(db_session) return await repo.get_system_tasks(status=status, task_type=task_type) @router.post("/admin/system-tasks", response_model=ScheduledTaskResponse) async def create_system_task( task_data: ScheduledTaskCreate, current_user: User = Depends(get_admin_user), scheduler_service: SchedulerService = Depends(get_scheduler_service), ) -> ScheduledTask: """Create a system task (admin only).""" try: task = await scheduler_service.create_task( name=task_data.name, task_type=task_data.task_type, scheduled_at=task_data.scheduled_at, parameters=task_data.parameters, user_id=None, # System task timezone=task_data.timezone, recurrence_type=task_data.recurrence_type, cron_expression=task_data.cron_expression, recurrence_count=task_data.recurrence_count, expires_at=task_data.expires_at, ) return task except Exception as e: raise HTTPException(status_code=400, detail=str(e))