Source code for permission.handlers

# coding=utf-8
from collections.abc import Callable

from permission.utils.permissions import get_app_perms, get_model_perms


[docs]class PermissionHandler(object): """ Abstract permission handler class """ _includes = None _excludes = None @property def includes(self): return self._includes @includes.setter def includes(self, value): # clear cache if hasattr(self, "_perms_cache"): del self._perms_cache self._includes = value @property def excludes(self): return self._excludes @excludes.setter def excludes(self, value): # clear cache if hasattr(self, "_perms_cache"): del self._perms_cache self._excludes = value def __init__(self, model_or_app_label): """ Constructor Parameters ---------- model_or_app_label : django model class or string A django model class or application label string. Use django model class for model level permission and application label for application level permission. """ if isinstance(model_or_app_label, str): self.app_label = model_or_app_label self.model = None if self.includes is None: self.includes = self._get_app_perms else: self.app_label = model_or_app_label._meta.app_label self.model = model_or_app_label self.model._permission_handler = self if self.includes is None: self.includes = self._get_model_perms def _get_app_perms(self, *args): """ Get permissions related to the application specified in constructor Returns ------- set A set instance of `app_label.codename` formatted permission strings """ if not hasattr(self, "_app_perms_cache"): self._app_perms_cache = get_app_perms(self.app_label) return self._app_perms_cache def _get_model_perms(self, *args): """ Get permissions related to the model specified in constructor Returns ------- set A set instance of `app_label.codename` formatted permission strings """ if not hasattr(self, "_model_perms_cache"): if self.model is None: self._model_perms_cache = set() else: self._model_perms_cache = get_model_perms(self.model) return self._model_perms_cache
[docs] def get_supported_permissions(self): """ Get permissions which this handler can treat. Specified with :attr:`includes` and :attr:`excludes` of this instance. Returns ------- set A set instance of `app_label.codename` formatted permission strings """ if not hasattr(self, "_perms_cache"): if self.includes and isinstance(self.includes, Callable): includes = self.includes(self) else: includes = self.includes or [] if self.excludes and isinstance(self.excludes, Callable): excludes = self.excludes(self) else: excludes = self.excludes or [] includes = set(includes) excludes = set(excludes) includes = includes.difference(excludes) self._perms_cache = includes return self._perms_cache
[docs] def get_supported_app_labels(self): """ Get app labels which this handler can treat. Specified with :attr:`includes` and :attr:`excludes` of this instance. Returns ------- set A set instance of app_label """ get_app_label = lambda x: x.split(".", 1)[0] if not hasattr(self, "_app_labels_cache"): perms = self.get_supported_permissions() self._app_labels_cache = set([get_app_label(x) for x in perms]) return self._app_labels_cache
[docs] def has_perm(self, user_obj, perm, obj=None): """ Check if user have permission (of object) Parameters ---------- user_obj : django user model instance A django user model instance which be checked perm : string `app_label.codename` formatted permission string obj : None or django model instance None or django model instance for object permission Returns ------- boolean Whether the specified user have specified permission (of specified object). .. note:: Sub class must override this method. """ raise NotImplementedError( ( "'%s' does not override `has_perm(user_obj, perm, obj=None)` " "method. Sub class must override this method." ) % self.__class__ )
[docs] def has_module_perms(self, user_obj, app_label): """ Check if user have permission of specified app Parameters ---------- user_obj : django user model instance A django user model instance which be checked app_label : string Django application name Returns ------- boolean Whether the specified user have any permissions of specified app """ cache_name = "_has_module_perms_%s_%s_cache" % (app_label, user_obj.pk) if hasattr(self, cache_name): return getattr(self, cache_name) if self.app_label != app_label: setattr(self, cache_name, False) else: for permission in self.get_supported_permissions(): if user_obj.has_perm(permission): setattr(self, cache_name, True) return True setattr(self, cache_name, False) return False
[docs]class LogicalPermissionHandler(PermissionHandler): """ Permission handler class which use permission logics to determine the permission """ def __init__(self, model): """ Constructor Parameters ---------- model : django model class A django model class. .. note:: LogicalPermissionHandler cannot treat application level permission """ # logical permission handler cannot treat application level permission if isinstance(model, str): raise AttributeError( ("'%s' cannot treat application level permission.") % self.__class__ ) super(LogicalPermissionHandler, self).__init__(model)
[docs] def has_perm(self, user_obj, perm, obj=None): """ Check if user have permission (of object) based on specified models's ``_permission_logics`` attribute. The result will be stored in user_obj as a cache to reduce method call. Parameters ---------- user_obj : django user model instance A django user model instance which be checked perm : string `app_label.codename` formatted permission string obj : None or django model instance None or django model instance for object permission Returns ------- boolean Whether the specified user have specified permission (of specified object). """ if perm not in self.get_supported_permissions(): return False # use cache to reduce method call CACHE_NAME = "_logical_perms_cache" if not hasattr(user_obj, CACHE_NAME): setattr(user_obj, CACHE_NAME, {}) cache = getattr(user_obj, CACHE_NAME) cachekey = "%s %s" % (perm, hash(obj)) if cachekey not in cache: cache[cachekey] = self._has_perm(user_obj, perm, obj) return cache[cachekey]
def _has_perm(self, user_obj, perm, obj=None): if perm not in self.get_supported_permissions(): return False for permission_logic in getattr(self.model, "_permission_logics", set()): if permission_logic.has_perm(user_obj, perm, obj): return True return False