| """ |
| Project management routes - create, list, and get projects |
| """ |
| import os |
| import uuid |
| import aiofiles |
| from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form, status |
| from sqlalchemy.orm import Session |
| from typing import List, Optional |
| from app.database import get_db |
| from app.models import User, Project |
| from app.schemas import ProjectCreate, ProjectResponse, ProjectListResponse |
| from app.dependencies import get_current_user |
| from app.config import get_settings |
|
|
| settings = get_settings() |
| router = APIRouter(prefix="/projects", tags=["Projects"]) |
|
|
| |
| ALLOWED_EXTENSIONS = {".mp4", ".mov", ".avi", ".webm", ".mkv"} |
| MAX_FILE_SIZE = 500 * 1024 * 1024 |
|
|
|
|
| @router.post("", response_model=ProjectResponse, status_code=status.HTTP_201_CREATED) |
| async def create_project( |
| title: str = Form(...), |
| demographic_filter: Optional[str] = Form(None), |
| video: UploadFile = File(...), |
| current_user: User = Depends(get_current_user), |
| db: Session = Depends(get_db) |
| ): |
| """ |
| Create a new project with video upload |
| """ |
| |
| file_ext = os.path.splitext(video.filename)[1].lower() |
| if file_ext not in ALLOWED_EXTENSIONS: |
| raise HTTPException( |
| status_code=status.HTTP_400_BAD_REQUEST, |
| detail=f"Invalid file type. Allowed types: {', '.join(ALLOWED_EXTENSIONS)}" |
| ) |
| |
| |
| upload_dir = os.path.join(settings.upload_dir, str(current_user.id)) |
| os.makedirs(upload_dir, exist_ok=True) |
| |
| |
| file_id = str(uuid.uuid4()) |
| filename = f"{file_id}{file_ext}" |
| file_path = os.path.join(upload_dir, filename) |
| |
| |
| try: |
| async with aiofiles.open(file_path, 'wb') as f: |
| |
| total_size = 0 |
| while chunk := await video.read(1024 * 1024): |
| total_size += len(chunk) |
| if total_size > MAX_FILE_SIZE: |
| os.remove(file_path) |
| raise HTTPException( |
| status_code=status.HTTP_400_BAD_REQUEST, |
| detail=f"File too large. Maximum size: {MAX_FILE_SIZE // (1024*1024)}MB" |
| ) |
| await f.write(chunk) |
| except Exception as e: |
| if os.path.exists(file_path): |
| os.remove(file_path) |
| raise HTTPException( |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| detail=f"Failed to save file: {str(e)}" |
| ) |
| |
| |
| demo_filter = None |
| if demographic_filter: |
| import json |
| try: |
| demo_filter = json.loads(demographic_filter) |
| except json.JSONDecodeError: |
| pass |
| |
| |
| project = Project( |
| user_id=current_user.id, |
| title=title, |
| video_path=file_path, |
| demographic_filter=demo_filter, |
| status="PENDING" |
| ) |
| |
| db.add(project) |
| db.commit() |
| db.refresh(project) |
| |
| |
| from app.tasks import process_video_task |
| process_video_task.delay(str(project.id)) |
| |
| return project |
|
|
|
|
| @router.get("", response_model=List[ProjectListResponse]) |
| async def list_projects( |
| current_user: User = Depends(get_current_user), |
| db: Session = Depends(get_db) |
| ): |
| """ |
| List all projects for the current user |
| """ |
| projects = db.query(Project).filter( |
| Project.user_id == current_user.id |
| ).order_by(Project.created_at.desc()).all() |
| |
| return projects |
|
|
|
|
| @router.get("/{project_id}", response_model=ProjectResponse) |
| async def get_project( |
| project_id: str, |
| current_user: User = Depends(get_current_user), |
| db: Session = Depends(get_db) |
| ): |
| """ |
| Get a specific project by ID |
| """ |
| project = db.query(Project).filter( |
| Project.id == project_id, |
| Project.user_id == current_user.id |
| ).first() |
| |
| if not project: |
| raise HTTPException( |
| status_code=status.HTTP_404_NOT_FOUND, |
| detail="Project not found" |
| ) |
| |
| return project |
|
|
|
|
| @router.delete("/{project_id}", status_code=status.HTTP_204_NO_CONTENT) |
| async def delete_project( |
| project_id: str, |
| current_user: User = Depends(get_current_user), |
| db: Session = Depends(get_db) |
| ): |
| """ |
| Delete a project and its video file |
| """ |
| project = db.query(Project).filter( |
| Project.id == project_id, |
| Project.user_id == current_user.id |
| ).first() |
| |
| if not project: |
| raise HTTPException( |
| status_code=status.HTTP_404_NOT_FOUND, |
| detail="Project not found" |
| ) |
| |
| |
| if os.path.exists(project.video_path): |
| os.remove(project.video_path) |
| |
| |
| db.delete(project) |
| db.commit() |
|
|