""" Projects API Routes - Workspace management """ from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from typing import Optional, List from datetime import datetime from sqlalchemy.orm import Session from app.api.deps import get_scoped_db from app.models import Project, Entity, Relationship router = APIRouter(prefix="/projects", tags=["Projects"]) class ProjectCreate(BaseModel): name: str description: Optional[str] = None color: str = "#00d4ff" icon: str = "folder" class ProjectResponse(BaseModel): id: str name: str description: Optional[str] color: str icon: str entity_count: int = 0 created_at: datetime class Config: from_attributes = True @router.get("", response_model=List[ProjectResponse]) def list_projects(db: Session = Depends(get_scoped_db)): """List all projects""" projects = db.query(Project).order_by(Project.created_at.desc()).all() result = [] for p in projects: entity_count = db.query(Entity).filter(Entity.project_id == p.id).count() result.append(ProjectResponse( id=p.id, name=p.name, description=p.description, color=p.color, icon=p.icon, entity_count=entity_count, created_at=p.created_at )) return result @router.post("", response_model=ProjectResponse) def create_project(project: ProjectCreate, db: Session = Depends(get_scoped_db)): """Create a new project""" new_project = Project( name=project.name, description=project.description, color=project.color, icon=project.icon ) db.add(new_project) db.commit() db.refresh(new_project) return ProjectResponse( id=new_project.id, name=new_project.name, description=new_project.description, color=new_project.color, icon=new_project.icon, entity_count=0, created_at=new_project.created_at ) @router.get("/{project_id}", response_model=ProjectResponse) def get_project(project_id: str, db: Session = Depends(get_scoped_db)): """Get project by ID""" project = db.query(Project).filter(Project.id == project_id).first() if not project: raise HTTPException(status_code=404, detail="Project not found") entity_count = db.query(Entity).filter(Entity.project_id == project_id).count() return ProjectResponse( id=project.id, name=project.name, description=project.description, color=project.color, icon=project.icon, entity_count=entity_count, created_at=project.created_at ) @router.delete("/{project_id}") def delete_project(project_id: str, db: Session = Depends(get_scoped_db)): """Delete project and optionally its entities""" project = db.query(Project).filter(Project.id == project_id).first() if not project: raise HTTPException(status_code=404, detail="Project not found") # Set entities and relationships to no project (null) db.query(Entity).filter(Entity.project_id == project_id).update({"project_id": None}) db.query(Relationship).filter(Relationship.project_id == project_id).update({"project_id": None}) db.delete(project) db.commit() return {"message": f"Project '{project.name}' deleted"} @router.put("/{project_id}") def update_project(project_id: str, project: ProjectCreate, db: Session = Depends(get_scoped_db)): """Update project""" existing = db.query(Project).filter(Project.id == project_id).first() if not existing: raise HTTPException(status_code=404, detail="Project not found") existing.name = project.name existing.description = project.description existing.color = project.color existing.icon = project.icon db.commit() return {"message": "Project updated"}