sprint4+5: field-level permissions complete + universal ShareDialog frontend

This commit is contained in:
Agent Zero
2026-07-29 02:14:26 +02:00
parent b06aeeb720
commit 71ed592aa2
6 changed files with 748 additions and 3 deletions
+77 -2
View File
@@ -9,6 +9,11 @@ from __future__ import annotations
import logging
from typing import Any
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.custom_field_definition import CustomFieldDefinition
logger = logging.getLogger(__name__)
# ── Core system permissions ──
@@ -60,13 +65,50 @@ CORE_PERMISSIONS: list[dict[str, str]] = [
# ── Core field definitions for field-level permissions ──
CORE_FIELD_DEFINITIONS: list[dict[str, str]] = [
# ── Contact fields ──
{"module": "contacts", "field": "firstname", "label": "First Name", "sensitivity": "normal"},
{"module": "contacts", "field": "surname", "label": "Last Name", "sensitivity": "normal"},
{"module": "contacts", "field": "email_1", "label": "Email", "sensitivity": "normal"},
{"module": "contacts", "field": "phone_1", "label": "Phone", "sensitivity": "normal"},
{"module": "contacts", "field": "displayname", "label": "Display Name", "sensitivity": "normal"},
{"module": "contacts", "field": "name", "label": "Name", "sensitivity": "normal"},
{"module": "contacts", "field": "email_1", "label": "Email 1", "sensitivity": "normal"},
{"module": "contacts", "field": "email_2", "label": "Email 2", "sensitivity": "normal"},
{"module": "contacts", "field": "phone_1", "label": "Phone 1", "sensitivity": "normal"},
{"module": "contacts", "field": "phone_2", "label": "Phone 2", "sensitivity": "normal"},
{"module": "contacts", "field": "mobilephone", "label": "Mobile", "sensitivity": "sensitive"},
{"module": "contacts", "field": "function", "label": "Position", "sensitivity": "normal"},
{"module": "contacts", "field": "website", "label": "Website", "sensitivity": "normal"},
{"module": "contacts", "field": "status", "label": "Status", "sensitivity": "normal"},
{"module": "contacts", "field": "type", "label": "Type", "sensitivity": "normal"},
{"module": "contacts", "field": "gender", "label": "Gender", "sensitivity": "normal"},
{"module": "contacts", "field": "suffix", "label": "Suffix", "sensitivity": "normal"},
{"module": "contacts", "field": "ext_name_line", "label": "Extra Name Line", "sensitivity": "normal"},
{"module": "contacts", "field": "country", "label": "Country", "sensitivity": "normal"},
# ── Financial / sensitive fields ──
{"module": "contacts", "field": "code", "label": "Code", "sensitivity": "sensitive"},
{"module": "contacts", "field": "accounting_code", "label": "Accounting Code", "sensitivity": "sensitive"},
{"module": "contacts", "field": "vendor_accounting_code", "label": "Vendor Accounting Code", "sensitivity": "sensitive"},
{"module": "contacts", "field": "vat_code", "label": "VAT Code", "sensitivity": "sensitive"},
{"module": "contacts", "field": "fiscal_code", "label": "Fiscal Code", "sensitivity": "sensitive"},
{"module": "contacts", "field": "commerce_code", "label": "Commerce Code", "sensitivity": "sensitive"},
{"module": "contacts", "field": "purchase_number", "label": "Purchase Number", "sensitivity": "sensitive"},
{"module": "contacts", "field": "bic", "label": "BIC", "sensitivity": "sensitive"},
# ── Addresses ──
{"module": "contacts", "field": "mailing_street", "label": "Mailing Street", "sensitivity": "normal"},
{"module": "contacts", "field": "mailing_city", "label": "Mailing City", "sensitivity": "normal"},
{"module": "contacts", "field": "mailing_postalcode", "label": "Mailing Postal Code", "sensitivity": "normal"},
{"module": "contacts", "field": "mailing_country", "label": "Mailing Country", "sensitivity": "normal"},
{"module": "contacts", "field": "visit_street", "label": "Visit Street", "sensitivity": "normal"},
{"module": "contacts", "field": "visit_city", "label": "Visit City", "sensitivity": "normal"},
{"module": "contacts", "field": "visit_postalcode", "label": "Visit Postal Code", "sensitivity": "normal"},
{"module": "contacts", "field": "visit_country", "label": "Visit Country", "sensitivity": "normal"},
{"module": "contacts", "field": "invoice_street", "label": "Invoice Street", "sensitivity": "normal"},
{"module": "contacts", "field": "invoice_city", "label": "Invoice City", "sensitivity": "normal"},
{"module": "contacts", "field": "invoice_postalcode", "label": "Invoice Postal Code", "sensitivity": "normal"},
{"module": "contacts", "field": "invoice_country", "label": "Invoice Country", "sensitivity": "normal"},
# ── Notes & Tags ──
{"module": "contacts", "field": "notes", "label": "Notes", "sensitivity": "sensitive"},
{"module": "contacts", "field": "tags", "label": "Tags", "sensitivity": "sensitive"},
# ── User fields ──
{"module": "users", "field": "email", "label": "Email", "sensitivity": "normal"},
{"module": "users", "field": "name", "label": "Name", "sensitivity": "normal"},
{"module": "users", "field": "role", "label": "Role", "sensitivity": "normal"},
@@ -166,6 +208,39 @@ class PermissionRegistry:
result.extend(defs)
return result
async def get_all_field_definitions_with_custom(
self,
db: AsyncSession,
tenant_id: Any,
) -> list[dict[str, str]]:
"""Return all field definitions including custom fields from DB.
Merges core field definitions with plugin-provided definitions
and active custom field definitions from the database.
"""
result = list(self._core_field_definitions)
# Add plugin field definitions
for defs in self._field_definitions.values():
result.extend(defs)
# Load custom field definitions from DB
q = select(CustomFieldDefinition).where(
CustomFieldDefinition.tenant_id == tenant_id,
CustomFieldDefinition.is_active.is_(True),
)
custom_defs = await db.execute(q)
for cfd in custom_defs.scalars().all():
result.append({
"module": cfd.entity,
"field": cfd.name,
"label": cfd.label,
"sensitivity": cfd.sensitivity,
"custom": "true",
})
return result
# Global instance
_registry = PermissionRegistry()