feat: phase 3 - field-level permissions with plugin field definitions, service-layer filtering, 20 core field definitions

This commit is contained in:
Agent Zero
2026-07-15 23:02:30 +02:00
parent 08fd3ab72c
commit beaca24480
9 changed files with 106 additions and 4 deletions
+15 -1
View File
@@ -35,6 +35,12 @@ def _contact_to_dict(c: Contact, include_companies: bool = False) -> dict[str, A
return data
def _filter_contact_fields(data: dict, resolved_perms: dict) -> dict:
"""Filter contact fields based on field-level permissions."""
from app.core.permissions import filter_fields_by_permission
return filter_fields_by_permission(data, resolved_perms, "contacts")
async def list_contacts(
db: AsyncSession,
tenant_id: uuid.UUID,
@@ -43,6 +49,7 @@ async def list_contacts(
search: str | None = None,
sort_by: str = "last_name",
sort_order: str = "asc",
resolved_perms: dict | None = None,
) -> dict[str, Any]:
"""List contacts with pagination and optional search."""
page = max(1, page)
@@ -76,8 +83,12 @@ async def list_contacts(
result = await db.execute(paginated)
contacts = result.scalars().all()
items = [_contact_to_dict(c) for c in contacts]
if resolved_perms is not None:
items = [_filter_contact_fields(item, resolved_perms) for item in items]
return {
"items": [_contact_to_dict(c) for c in contacts],
"items": items,
"total": total,
"page": page,
"page_size": page_size,
@@ -88,6 +99,7 @@ async def get_contact_detail(
db: AsyncSession,
tenant_id: uuid.UUID,
contact_id: uuid.UUID,
resolved_perms: dict | None = None,
) -> dict[str, Any] | None:
"""Get a single contact with its linked companies array."""
q = select(Contact).where(
@@ -123,6 +135,8 @@ async def get_contact_detail(
}
)
data["companies"] = companies_list
if resolved_perms is not None:
data = _filter_contact_fields(data, resolved_perms)
return data