""" Projects API Router """ import logging import shutil from pathlib import Path from typing import List, Optional from uuid import UUID from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from app.api.response import ApiResponse, PaginatedResponse from app.core.database import get_db from app.core.exceptions import NotFoundException from app.core.crud import CRUDBase from app.models.models import Project from app.schemas.project import ( ProjectCreate, ProjectUpdate, ProjectResponse, ProjectCreateSchema, ProjectUpdateSchema ) router = APIRouter() logger = logging.getLogger("yg_dataset.projects") # Initialize CRUD project_crud = CRUDBase(Project) @router.get("", response_model=PaginatedResponse) async def list_projects( page: int = Query(1, ge=1, description="Page number"), page_size: int = Query(20, ge=1, le=100, description="Page size"), db: AsyncSession = Depends(get_db) ): """List all projects with pagination""" logger.info(f"Listing projects - page: {page}, page_size: {page_size}") skip = (page - 1) * page_size projects, total = await project_crud.get_multi( db, skip=skip, limit=page_size, order_by="created_at", descending=True ) logger.info(f"Found {total} projects, returning {len(projects)} items") project_responses = [ProjectResponse.model_validate(p) for p in projects] return PaginatedResponse.ok( items=project_responses, page=page, page_size=page_size, total=total ) @router.post("", response_model=ApiResponse) async def create_project( project: ProjectCreateSchema, db: AsyncSession = Depends(get_db) ): """Create a new project""" logger.info(f"Creating project: name={project.name}, description={project.description}") db_project = await project_crud.create(db, project) logger.info(f"Project created successfully: id={db_project.id}") return ApiResponse.ok( data={"id": str(db_project.id)}, message="Project created successfully" ) @router.get("/{project_id}", response_model=ApiResponse) async def get_project( project_id: UUID, db: AsyncSession = Depends(get_db) ): """Get project by ID""" logger.info(f"Getting project: id={project_id}") project = await project_crud.get_or_raise(db, project_id, "Project") logger.info(f"Found project: name={project.name}") return ApiResponse.ok(data=ProjectResponse.model_validate(project)) @router.put("/{project_id}", response_model=ApiResponse) async def update_project( project_id: UUID, project: ProjectUpdateSchema, db: AsyncSession = Depends(get_db) ): """Update project""" logger.info(f"Updating project: id={project_id}") db_project = await project_crud.get_or_raise(db, project_id, "Project") updated_project = await project_crud.update(db, db_project, project) logger.info(f"Project updated: name={updated_project.name}") return ApiResponse.ok( data=ProjectResponse.model_validate(updated_project), message="Project updated successfully" ) @router.delete("/{project_id}", response_model=ApiResponse) async def delete_project( project_id: UUID, db: AsyncSession = Depends(get_db) ): """Delete project""" logger.info(f"Deleting project: id={project_id}") await project_crud.get_or_raise(db, project_id, "Project") await project_crud.delete(db, project_id) # 删除项目对应的本地数据目录 project_data_dir = Path("/data/code/YG-Datasets/data") / str(project_id) if project_data_dir.exists(): shutil.rmtree(project_data_dir) logger.info(f"Project data directory deleted: {project_data_dir}") logger.info(f"Project deleted: id={project_id}") return ApiResponse.ok(message="Project deleted successfully")