# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Membership models: UserMandate, FeatureAccess, and Junction Tables. Diese Models definieren die m:n Beziehungen zwischen User, Mandate und FeatureInstance. Rollen werden über Junction Tables verknüpft für saubere CASCADE DELETE. """ import uuid from pydantic import BaseModel, Field from modules.datamodels.datamodelBase import PowerOnModel from modules.shared.attributeUtils import registerModelLabels class UserMandate(PowerOnModel): """ User-Mitgliedschaft in einem Mandanten. Kein User gehört direkt zu einem Mandanten - Zugehörigkeit wird über dieses Model gesteuert. """ id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the user-mandate membership", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_visible": False, "frontend_required": False} ) userId: str = Field( description="FK → User.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/users/", "frontend_fk_display_field": "username"} ) mandateId: str = Field( description="FK → Mandate.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/mandates/", "frontend_fk_display_field": "label"} ) enabled: bool = Field( default=True, description="Whether this membership is enabled", json_schema_extra={"frontend_type": "checkbox", "frontend_readonly": False, "frontend_required": False} ) # Rollen werden via Junction Table UserMandateRole verknüpft registerModelLabels( "UserMandate", {"en": "User Mandate", "de": "Benutzer-Mandant", "fr": "Mandat utilisateur"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "userId": {"en": "User", "de": "Benutzer", "fr": "Utilisateur"}, "mandateId": {"en": "Mandate", "de": "Mandant", "fr": "Mandat"}, "enabled": {"en": "Enabled", "de": "Aktiviert", "fr": "Activé"}, }, ) class FeatureAccess(PowerOnModel): """ User-Zugriff auf eine Feature-Instanz. Definiert welche User auf welche Feature-Instanzen zugreifen können. """ id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the feature access", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_visible": False, "frontend_required": False} ) userId: str = Field( description="FK → User.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/users/", "frontend_fk_display_field": "username"} ) featureInstanceId: str = Field( description="FK → FeatureInstance.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/feature-instances/", "frontend_fk_display_field": "name"} ) enabled: bool = Field( default=True, description="Whether this feature access is enabled", json_schema_extra={"frontend_type": "checkbox", "frontend_readonly": False, "frontend_required": False} ) # Rollen werden via Junction Table FeatureAccessRole verknüpft registerModelLabels( "FeatureAccess", {"en": "Feature Access", "de": "Feature-Zugang", "fr": "Accès fonctionnalité"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "userId": {"en": "User", "de": "Benutzer", "fr": "Utilisateur"}, "featureInstanceId": {"en": "Feature Instance", "de": "Feature-Instanz", "fr": "Instance"}, "enabled": {"en": "Enabled", "de": "Aktiviert", "fr": "Activé"}, }, ) class UserMandateRole(PowerOnModel): """ Junction Table: UserMandate zu Role. Ermöglicht CASCADE DELETE auf Datenbankebene. """ id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the junction record", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_visible": False, "frontend_required": False} ) userMandateId: str = Field( description="FK → UserMandate.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/user-mandates/", "frontend_fk_display_field": "userId"} ) roleId: str = Field( description="FK → Role.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/rbac/roles", "frontend_fk_display_field": "roleLabel"} ) registerModelLabels( "UserMandateRole", {"en": "User Mandate Role", "de": "Benutzer-Mandant-Rolle", "fr": "Rôle mandat utilisateur"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "userMandateId": {"en": "User Mandate", "de": "Benutzer-Mandant", "fr": "Mandat utilisateur"}, "roleId": {"en": "Role", "de": "Rolle", "fr": "Rôle"}, }, ) class FeatureAccessRole(PowerOnModel): """ Junction Table: FeatureAccess zu Role. Ermöglicht CASCADE DELETE auf Datenbankebene. """ id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the junction record", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_visible": False, "frontend_required": False} ) featureAccessId: str = Field( description="FK → FeatureAccess.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/feature-access/", "frontend_fk_display_field": "userId"} ) roleId: str = Field( description="FK → Role.id (CASCADE DELETE)", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/rbac/roles", "frontend_fk_display_field": "roleLabel"} ) registerModelLabels( "FeatureAccessRole", {"en": "Feature Access Role", "de": "Feature-Zugang-Rolle", "fr": "Rôle accès fonctionnalité"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "featureAccessId": {"en": "Feature Access", "de": "Feature-Zugang", "fr": "Accès fonctionnalité"}, "roleId": {"en": "Role", "de": "Rolle", "fr": "Rôle"}, }, )