"""API routes for CustomFieldDefinition CRUD.""" from __future__ import annotations import uuid from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from app.core.db import get_db from app.deps import get_current_user, require_permission from app.schemas.custom_field_definition import ( CustomFieldDefinitionCreate, CustomFieldDefinitionResponse, CustomFieldDefinitionUpdate, ) from app.services import custom_field_service router = APIRouter(prefix="/api/v1/custom-fields", tags=["custom-fields-definitions"]) @router.get( "/definitions", response_model=list[CustomFieldDefinitionResponse], dependencies=[Depends(require_permission("contacts:read"))], ) async def list_definitions( entity: str | None = Query(None, description="Filter by entity type (e.g. 'contact', 'company')"), db: AsyncSession = Depends(get_db), current_user: dict = Depends(get_current_user), ): """List all active custom field definitions for the current tenant.""" tenant_id = uuid.UUID(current_user["tenant_id"]) definitions = await custom_field_service.list_definitions(db, tenant_id, entity=entity) return definitions @router.post( "/definitions", response_model=CustomFieldDefinitionResponse, status_code=201, dependencies=[Depends(require_permission("contacts:write"))], ) async def create_definition( body: CustomFieldDefinitionCreate, db: AsyncSession = Depends(get_db), current_user: dict = Depends(get_current_user), ): """Create a new custom field definition.""" tenant_id = uuid.UUID(current_user["tenant_id"]) user_id = uuid.UUID(current_user["user_id"]) definition = await custom_field_service.create_definition( db, tenant_id, user_id, body.model_dump() ) return definition @router.patch( "/definitions/{definition_id}", response_model=CustomFieldDefinitionResponse, dependencies=[Depends(require_permission("contacts:write"))], ) async def update_definition( definition_id: str, body: CustomFieldDefinitionUpdate, db: AsyncSession = Depends(get_db), current_user: dict = Depends(get_current_user), ): """Update an existing custom field definition.""" tenant_id = uuid.UUID(current_user["tenant_id"]) user_id = uuid.UUID(current_user["user_id"]) try: def_id = uuid.UUID(definition_id) except (ValueError, TypeError): raise HTTPException(400, detail={"detail": "Invalid definition_id", "code": "invalid_id"}) from None # Filter out None values from the update body update_data = {k: v for k, v in body.model_dump().items() if v is not None} if not update_data: raise HTTPException(400, detail={"detail": "No fields to update", "code": "no_updates"}) definition = await custom_field_service.update_definition( db, tenant_id, def_id, update_data, user_id=user_id ) if definition is None: raise HTTPException(404, detail={"detail": "Definition not found", "code": "not_found"}) return definition @router.delete( "/definitions/{definition_id}", status_code=204, dependencies=[Depends(require_permission("contacts:write"))], ) async def delete_definition( definition_id: str, db: AsyncSession = Depends(get_db), current_user: dict = Depends(get_current_user), ): """Delete a custom field definition.""" tenant_id = uuid.UUID(current_user["tenant_id"]) try: def_id = uuid.UUID(definition_id) except (ValueError, TypeError): raise HTTPException(400, detail={"detail": "Invalid definition_id", "code": "invalid_id"}) from None deleted = await custom_field_service.delete_definition(db, tenant_id, def_id) if not deleted: raise HTTPException(404, detail={"detail": "Definition not found", "code": "not_found"}) return None