dograh/api/routes/folder.py

100 lines
2.9 KiB
Python
Raw Permalink Normal View History

from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field, field_validator
from api.db import db_client
from api.db.folder_client import FolderNameConflictError
from api.db.models import UserModel
from api.services.auth.depends import get_user
router = APIRouter(prefix="/folder")
class FolderResponse(BaseModel):
id: int
name: str
created_at: datetime
class CreateFolderRequest(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
@field_validator("name")
@classmethod
def strip_name(cls, v: str) -> str:
v = v.strip()
if not v:
raise ValueError("Folder name cannot be empty")
return v
class UpdateFolderRequest(CreateFolderRequest):
pass
@router.get("/")
async def list_folders(
user: UserModel = Depends(get_user),
) -> list[FolderResponse]:
"""List all folders in the authenticated user's organization."""
folders = await db_client.list_folders(
organization_id=user.selected_organization_id
)
return [
FolderResponse(id=f.id, name=f.name, created_at=f.created_at) for f in folders
]
@router.post("/")
async def create_folder(
request: CreateFolderRequest,
user: UserModel = Depends(get_user),
) -> FolderResponse:
"""Create a new folder in the authenticated user's organization."""
try:
folder = await db_client.create_folder(
name=request.name,
organization_id=user.selected_organization_id,
)
except FolderNameConflictError as e:
raise HTTPException(status_code=409, detail=str(e))
return FolderResponse(id=folder.id, name=folder.name, created_at=folder.created_at)
@router.put("/{folder_id}")
async def rename_folder(
folder_id: int,
request: UpdateFolderRequest,
user: UserModel = Depends(get_user),
) -> FolderResponse:
"""Rename a folder owned by the authenticated user's organization."""
try:
folder = await db_client.rename_folder(
folder_id=folder_id,
name=request.name,
organization_id=user.selected_organization_id,
)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except FolderNameConflictError as e:
raise HTTPException(status_code=409, detail=str(e))
return FolderResponse(id=folder.id, name=folder.name, created_at=folder.created_at)
@router.delete("/{folder_id}")
async def delete_folder(
folder_id: int,
user: UserModel = Depends(get_user),
) -> dict[str, bool]:
"""Delete a folder. Member agents are moved to "Uncategorized", not deleted."""
deleted = await db_client.delete_folder(
folder_id=folder_id,
organization_id=user.selected_organization_id,
)
if not deleted:
raise HTTPException(
status_code=404, detail=f"Folder with id {folder_id} not found"
)
return {"success": True}