"""CRUD APIs for Projects (inside a tenant).""" from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from asf_domain import Project, ProjectCreate, ProjectUpdate from ...repositories import NotFoundError, DuplicateError, TenantMismatchError from .deps import project_service from ...services import ProjectService router = APIRouter() @router.get("", response_model=list[Project], summary="List projects (tenant scoped)") async def list_projects( limit: int = Query(100, ge=1, le=500), offset: int = Query(0, ge=0), only_active: bool = True, svc: ProjectService = Depends(project_service), ) -> list[Project]: return await svc.list(limit=limit, offset=offset, only_active=only_active) @router.post( "", response_model=Project, status_code=status.HTTP_201_CREATED, summary="Create project", ) async def create_project( body: ProjectCreate, svc: ProjectService = Depends(project_service), ) -> Project: try: return await svc.create(body) except DuplicateError as exc: raise HTTPException(status_code=409, detail=str(exc)) from exc except NotFoundError as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc @router.get("/{project_id}", response_model=Project, summary="Get project by id") async def get_project( project_id: UUID, svc: ProjectService = Depends(project_service), ) -> Project: p = await svc.get(project_id) if p is None: raise HTTPException(status_code=404, detail=f"Project {project_id} not found") return p @router.patch("/{project_id}", response_model=Project, summary="Update project") async def update_project( project_id: UUID, body: ProjectUpdate, svc: ProjectService = Depends(project_service), ) -> Project: try: return await svc.update(project_id, body) except (NotFoundError, TenantMismatchError) as exc: raise HTTPException(status_code=404, detail=str(exc)) from exc