feat(M2): Persönliche Dashboards — Tabelle, CRUD, Lazy-Seed, RLS (#360)
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
- dashboards-Tabelle (Layout JSONB, Tabs, is_default, partial unique name index) - 6 CRUD-Endpoints /api/v1/dashboards, Owner-only (saved_views-Präzedenz), Audit - Lazy Default-Seed aus MiniApp-Registry (permission-gefiltert, 12-Spalten-Flow) - CORE_PERMISSIONS dashboard:read/write (fixt Phantom-Permission in dashboard.py) - Migration 0144: RLS crm_api+crm_worker + konvergenter Fix der 3 Phase-L-Policies - Tests: test_dashboards_backend.py 23/23 (TDD rot->grün); Regression 162/163
This commit is contained in:
@@ -63,7 +63,7 @@ BEGIN
|
||||
EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY', t);
|
||||
EXECUTE format('DROP POLICY IF EXISTS %I ON %I', t || '_tenant_isolation', t);
|
||||
EXECUTE format(
|
||||
'CREATE POLICY %I ON %I AS PERMISSIVE FOR ALL TO crm_api USING (tenant_id = NULLIF(current_setting(''app.current_tenant_id'', true), '''')::uuid) WITH CHECK (tenant_id = NULLIF(current_setting(''app.current_tenant_id'', true), '''')::uuid)',
|
||||
'CREATE POLICY %I ON %I AS PERMISSIVE FOR ALL TO crm_api, crm_worker USING (tenant_id = NULLIF(current_setting(''app.current_tenant_id'', true), '''')::uuid) WITH CHECK (tenant_id = NULLIF(current_setting(''app.current_tenant_id'', true), '''')::uuid)',
|
||||
t || '_tenant_isolation', t
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
|
||||
@@ -152,3 +152,20 @@ def reset_miniapp_registry() -> None:
|
||||
"""Reset the singleton instance (useful for tests)."""
|
||||
global _registry
|
||||
_registry = None
|
||||
|
||||
|
||||
def user_permits(current_user: dict[str, Any], app: dict[str, Any]) -> bool:
|
||||
"""Check whether *current_user* may see/use the MiniApp *app*.
|
||||
|
||||
Empty permission = visible to everyone; otherwise fail-closed check
|
||||
(system admins always pass). Shared by /api/v1/miniapps and the
|
||||
personal dashboard seed (Phase M2) so both apply identical rules.
|
||||
"""
|
||||
from app.core.permissions import check_permission
|
||||
|
||||
required = app.get("permission") or ""
|
||||
if not required:
|
||||
return True
|
||||
if current_user.get("is_system_admin"):
|
||||
return True
|
||||
return check_permission(current_user, required)
|
||||
|
||||
Reference in New Issue
Block a user