111 lines
3.8 KiB
Python
111 lines
3.8 KiB
Python
|
|
"""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
|