from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.auth.dependencies import get_current_active_user from app.db import get_db_session from app.models.project import Project from app.models.user import User from app.models.workspace import Workspace from app.schemas.workspace import WorkspaceCreate, WorkspaceRead, WorkspaceUpdate router = APIRouter(tags=["workspaces"]) async def _get_project_for_user( project_id: UUID, user: User, session: AsyncSession ) -> Project: project = await session.get(Project, project_id) if not project or project.owner_id != user.id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found") return project @router.post("/projects/{project_id}/workspaces", response_model=WorkspaceRead, status_code=status.HTTP_201_CREATED) # noqa: E501 async def create_workspace( project_id: UUID, ws_in: WorkspaceCreate, current_user: User = Depends(get_current_active_user), session: AsyncSession = Depends(get_db_session), ) -> Workspace: await _get_project_for_user(project_id, current_user, session) ws = Workspace(**ws_in.model_dump(), project_id=project_id) session.add(ws) await session.commit() await session.refresh(ws) return ws @router.get("/projects/{project_id}/workspaces", response_model=list[WorkspaceRead]) async def list_workspaces( project_id: UUID, current_user: User = Depends(get_current_active_user), session: AsyncSession = Depends(get_db_session), ) -> list[Workspace]: await _get_project_for_user(project_id, current_user, session) result = await session.execute( select(Workspace).where(Workspace.project_id == project_id) ) return list(result.scalars().all()) @router.get("/projects/{project_id}/workspaces/{ws_id}", response_model=WorkspaceRead) async def get_workspace( project_id: UUID, ws_id: UUID, current_user: User = Depends(get_current_active_user), session: AsyncSession = Depends(get_db_session), ) -> Workspace: await _get_project_for_user(project_id, current_user, session) ws = await session.get(Workspace, ws_id) if not ws or ws.project_id != project_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Workspace not found") return ws @router.put("/projects/{project_id}/workspaces/{ws_id}", response_model=WorkspaceRead) async def update_workspace( project_id: UUID, ws_id: UUID, ws_in: WorkspaceUpdate, current_user: User = Depends(get_current_active_user), session: AsyncSession = Depends(get_db_session), ) -> Workspace: await _get_project_for_user(project_id, current_user, session) ws = await session.get(Workspace, ws_id) if not ws or ws.project_id != project_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Workspace not found") update_data = ws_in.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(ws, field, value) await session.commit() await session.refresh(ws) return ws @router.delete("/projects/{project_id}/workspaces/{ws_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_workspace( project_id: UUID, ws_id: UUID, current_user: User = Depends(get_current_active_user), session: AsyncSession = Depends(get_db_session), ) -> None: await _get_project_for_user(project_id, current_user, session) ws = await session.get(Workspace, ws_id) if not ws or ws.project_id != project_id: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Workspace not found") await session.delete(ws) await session.commit()