import django from django.contrib.auth.models import Group from django.db import models from access.models.tenant import Tenant as Organization from access.models.team import Team User = django.contrib.auth.get_user_model() class OrganizationMixin: """Organization Tenancy Mixin This class is intended to be included in **ALL** View / Viewset classes as it contains the functions/methods required to conduct the permission checking. """ _obj_organization: int = None """Cached Object Organization""" def get_obj_organization(self, obj = None, request = None) -> Organization: """Fetch the objects Organization Args: obj (Model): Model of object Raises: ValueError: When `obj` and `request` are both missing Returns: Organization: Organization the object is from None: No Organization was found """ if obj is None and request is None: raise ValueError('Missing Parameter. obj or request must be supplied') if self._obj_organization: return self._obj_organization if obj: self._obj_organization = getattr(obj, 'organization', None) if not self._obj_organization: self._obj_organization = getattr(obj, 'get_organization', lambda: None)() elif ( request and not self.kwargs.get('pk', None) ): if getattr(request.stream, 'method', '') != 'DELETE': data = getattr(request, 'data', None) if data: data_organization = self.kwargs.get('organization_id', None) if not data_organization: data_organization = request.data.get('organization_id', None) if not data_organization: data_organization = request.data.get('organization', None) if data_organization: self._obj_organization = Organization.objects.get( pk = int( data_organization ) ) elif self.kwargs.get('pk', None): obj = self.model.objects.get( pk = self.kwargs.get('pk', None) ) if getattr(obj, 'organization', None): self._obj_organization = obj.organization elif str(self.model._meta.verbose_name).lower() == 'tenant': self._obj_organization = obj if self.get_parent_model(): # if defined is to overwrite object organization parent_obj = self.get_parent_obj() self._obj_organization = parent_obj.get_organization() return self._obj_organization def get_parent_model(self): """Get the Parent Model This function exists so that dynamic parent models can be defined. They are defined by overriding this method. Returns: Model: Parent Model """ return self.parent_model def get_parent_obj(self): """ Get the Parent Model Object Use in views where the the model has no organization and the organization should be fetched from the parent model. Requires attribute `parent_model` within the view with the value of the parent's model class Returns: parent_model (Model): with PK from kwargs['pk'] """ return self.get_parent_model().objects.get(pk=self.kwargs[self.parent_model_pk_kwarg]) def get_permission_organizations(self, permission: str ) -> list([ int ]): """Return Organization(s) the permission belongs to Searches the users organizations for the required permission, if found the organization is added to the list to return. Args: permission (str): Permission to search users organizations for Returns: Organizations (list): All Organizations where the permission was found. """ _permission_organizations: list = [] for team in self.request.tenancy._user_teams: for team_permission in team.permissions.all(): permission_value = str( team_permission.content_type.app_label + '.' + team_permission.codename ) if permission_value == permission: _permission_organizations += [ team.organization.id ] return _permission_organizations _permission_required: str = None """Cached Permissions required""" def get_permission_required(self) -> str: """ Get / Generate Permission Required If there is a requirement that there be custom/dynamic permissions, this function can be safely overridden. Raises: ValueError: Unable to determin the view action Returns: str: Permission in format `._` """ if self._permission_required: return self._permission_required if hasattr(self, 'get_dynamic_permissions'): self._permission_required = self.get_dynamic_permissions() if type(self._permission_required) is list: self._permission_required = self._permission_required[0] return self._permission_required view_action: str = None if( self.action == 'create' or getattr(self.request._stream, 'method', '') == 'POST' ): view_action = 'add' elif ( self.action == 'partial_update' or self.action == 'update' or getattr(self.request._stream, 'method', '') == 'PATCH' or getattr(self.request._stream, 'method', '') == 'PUT' ): view_action = 'change' elif( self.action == 'destroy' or getattr(self.request._stream, 'method', '') == 'DELETE' ): view_action = 'delete' elif ( self.action == 'list' ): view_action = 'view' elif self.action == 'retrieve': view_action = 'view' elif self.action == 'metadata': view_action = 'view' elif self.action is None: return False if view_action is None: raise ValueError('view_action could not be defined.') permission = self.model._meta.app_label + '.' + view_action + '_' + self.model._meta.model_name permission_required = permission self._permission_required = permission_required return self._permission_required parent_model: models.Model = None """ Parent Model This attribute defines the parent model for the model in question. The parent model when defined will be used as the object to obtain the permissions from. """ parent_model_pk_kwarg: str = 'pk' """Parent Model kwarg This value is used to define the kwarg that is used as the parent objects primary key (pk). """