from django.contrib.auth.models import Permission, User from django.core.exceptions import PermissionDenied from access.models.tenant import Tenant class CenturionUser( User, ): """Centurion User A Multi-Tenant User wirh permission Checking. ToDo: - Add to Roles user field `related_name = roles` - Add to Roles group field `related_name = roles` # - have group lookup prefetch related roles__permissions - have user lookup prefetch related roles__permissions and groups__roles__permissions Args: User (Model): Django Base User """ _tenancies: list[Tenant] = None _tenancies_int: list[int] = None _permissions: list[Permission] = None _permissions_by_tenancy: dict[ str, list[ Permission ] ] = None """Permissions by Tenancy `{ 'tenancy_{id}': [ Permission ] }` """ # EMAIL_FIELD = 'email' # Update contact email field name so it's different to the user model. # REQUIRED_FIELDS = [ # EMAIL_FIELD, # 'f_name', # 'l_name', # ] class Meta: abstract = False proxy = True # User will be linked to Employee/Customer entity via related_name from the entity. # ToDo: refactory Employee/Customer to inherit from a new model. entity_user verbose_name = 'Centurion User' verbose_name_plural = 'Centurion Users' def get_full_name(self) -> str: return f'{self.entity_user.f_name} {self.entity_user.l_name}' def get_group_permissions(self, tenancy: bool = True) -> dict[ str, list[ Permission ] ] | list[ Permission ]: """ Get the Users Permissions Args: tenancy (bool, optional): Return permission in list. Defaults to True. Returns: dict[ str, list[ Permission ] ]: Permissions listed by tenancy list[ Permission ]: All Permissions """ for group in self.groups: for role in group.roles: pass # role.get_permissions() def get_permissions(self, tenancy: bool = True) -> dict[ str, list[ Permission ] ] | list[ Permission ]: """ Get the Users Permissions Args: tenancy (bool, optional): Return permission in list. Defaults to True. Returns: dict[ str, list[ Permission ] ]: Permissions listed by tenancy list[ Permission ]: All Permissions """ # also get group permissions. self.get_group_permissions() for role in self.roles: pass # role.get_permissions() # also populate `self._tenancies` and `self._tenancies_int` def get_short_name() -> str: return self.entity_user.f_name def get_tenancies(self, int_list = False) -> list[ Tenant ] | list[ int ]: """Get the Tenancies the user is in. Args: int_list (bool, optional): Return Tenancy list as int values. Defaults to False. Returns: list[ Tenant ] | list[ int ]: All Tenancies the user is in. """ if self._tenancies is None: if self._permissions is None: self.get_permissions tenancies: list = [] tenancies_int: list = [] for role in self.roles: if role.organization in tenancies: continue tenancies += [ role.organization ] tenancies_int += [ role.organization.id ] self._tenancies = tenancies self._tenancies_int = tenancies_int if as_int_list: return self._tenancies_int return self._tenancies def has_module_perms(self, app_label): # is this needed? # if has app_label in perms raise PermissionDenied def has_perm(self, permission: Permission, obj = None, tenancy: Tenant = None) -> bool: if( obj is None and tenancy is None ): raise ValueError('Both obj and tenancy cant be None') if tenancy is None: tenancy = obj.organization # if self.has_tenancy_permission(perm, tenancy): # for tenancy, permissions in self.get_permissions().items() if tenancy is None: raise ValueError('tenancy cant be None') permissions = self.get_permissions() if f'tenancy_{tenancy.id}' not in permissions: raise PermissionDenied for tenancy, permissions in self.get_permissions().items(): if( tenancy == f'tenancy_{tenancy.id}' and perm in permissions ): return True raise PermissionDenied def has_perms(self, permission_list: list[ Permission ], obj = None, tenancy: Tenant = None): for perm in perm_list: self.has_perm( perm, obj ) return True