from __future__ import annotations from typing import List from fastapi import APIRouter, Depends, HTTPException, status from dependencies import get_unit_of_work from models import Project from schemas.project import ProjectCreate, ProjectRead, ProjectUpdate from services.exceptions import EntityConflictError, EntityNotFoundError from services.unit_of_work import UnitOfWork router = APIRouter(prefix="/projects", tags=["Projects"]) def _to_read_model(project: Project) -> ProjectRead: return ProjectRead.model_validate(project) @router.get("", response_model=List[ProjectRead]) def list_projects(uow: UnitOfWork = Depends(get_unit_of_work)) -> List[ProjectRead]: projects = uow.projects.list() return [_to_read_model(project) for project in projects] @router.post("", response_model=ProjectRead, status_code=status.HTTP_201_CREATED) def create_project( payload: ProjectCreate, uow: UnitOfWork = Depends(get_unit_of_work) ) -> ProjectRead: project = Project(**payload.model_dump()) try: created = uow.projects.create(project) except EntityConflictError as exc: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=str(exc) ) from exc return _to_read_model(created) @router.get("/{project_id}", response_model=ProjectRead) def get_project(project_id: int, uow: UnitOfWork = Depends(get_unit_of_work)) -> ProjectRead: try: project = uow.projects.get(project_id) except EntityNotFoundError as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc return _to_read_model(project) @router.put("/{project_id}", response_model=ProjectRead) def update_project( project_id: int, payload: ProjectUpdate, uow: UnitOfWork = Depends(get_unit_of_work), ) -> ProjectRead: try: project = uow.projects.get(project_id) except EntityNotFoundError as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc update_data = payload.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(project, field, value) uow.flush() return _to_read_model(project) @router.delete("/{project_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_project(project_id: int, uow: UnitOfWork = Depends(get_unit_of_work)) -> None: try: uow.projects.delete(project_id) except EntityNotFoundError as exc: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc