feat: phase 3 - field-level permissions with plugin field definitions, service-layer filtering, 20 core field definitions
This commit is contained in:
@@ -35,6 +35,12 @@ def _company_to_dict(c: Company, include_contacts: bool = False) -> dict[str, An
|
||||
return data
|
||||
|
||||
|
||||
def _filter_company_fields(data: dict, resolved_perms: dict) -> dict:
|
||||
"""Filter company fields based on field-level permissions."""
|
||||
from app.core.permissions import filter_fields_by_permission
|
||||
return filter_fields_by_permission(data, resolved_perms, "companies")
|
||||
|
||||
|
||||
async def list_companies(
|
||||
db: AsyncSession,
|
||||
tenant_id: uuid.UUID,
|
||||
@@ -44,6 +50,7 @@ async def list_companies(
|
||||
industry: str | None = None,
|
||||
sort_by: str = "name",
|
||||
sort_order: str = "asc",
|
||||
resolved_perms: dict | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""List companies with pagination, FTS search, industry filter, and sorting."""
|
||||
page = max(1, page)
|
||||
@@ -83,8 +90,12 @@ async def list_companies(
|
||||
result = await db.execute(paginated)
|
||||
companies = result.scalars().all()
|
||||
|
||||
items = [_company_to_dict(c) for c in companies]
|
||||
if resolved_perms is not None:
|
||||
items = [_filter_company_fields(item, resolved_perms) for item in items]
|
||||
|
||||
return {
|
||||
"items": [_company_to_dict(c) for c in companies],
|
||||
"items": items,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
@@ -95,6 +106,7 @@ async def get_company_detail(
|
||||
db: AsyncSession,
|
||||
tenant_id: uuid.UUID,
|
||||
company_id: uuid.UUID,
|
||||
resolved_perms: dict | None = None,
|
||||
) -> dict[str, Any] | None:
|
||||
"""Get a single company with its contacts array."""
|
||||
q = select(Company).where(
|
||||
@@ -133,6 +145,8 @@ async def get_company_detail(
|
||||
}
|
||||
)
|
||||
data["contacts"] = contacts_list
|
||||
if resolved_perms is not None:
|
||||
data = _filter_company_fields(data, resolved_perms)
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user