def save(self, *args, **kwargs): content_type = get_ctype_from_polymorphic(self.content_object) if content_type != self.permission.content_type: raise ValidationError("Cannot persist permission not designed for " "this class (permission's type is %r and object's type is %r)" % (self.permission.content_type, content_type)) return super(BaseObjectPermission, self).save(*args, **kwargs)
def get_perms_for_model(cls): """ Returns queryset of all Permission objects for the given class. It is possible to pass Model as class or instance. """ if isinstance(cls, basestring): app_label, model_name = cls.split('.') model = models.get_model(app_label, model_name) else: model = cls ctype = get_ctype_from_polymorphic(model) return Permission.objects.filter(content_type=ctype)
def get_groups_with_perms(obj, attach_perms=False): """ Returns queryset of all ``Group`` objects with *any* object permissions for the given ``obj``. :param obj: persisted Django's ``Model`` instance :param attach_perms: Default: ``False``. If set to ``True`` result would be dictionary of ``Group`` instances with permissions' codenames list as values. This would fetch groups eagerly! Example:: >>> from django.contrib.flatpages.models import FlatPage >>> from guardian.shortcuts import assign_perm, get_groups_with_perms >>> from guardian.models import Group >>> >>> page = FlatPage.objects.create(title='Some page', path='/some/page/') >>> admins = Group.objects.create(name='Admins') >>> assign_perm('change_flatpage', admins, page) >>> >>> get_groups_with_perms(page) [<Group: admins>] >>> >>> get_groups_with_perms(page, attach_perms=True) {<Group: admins>: [u'change_flatpage']} """ ctype = get_ctype_from_polymorphic(obj) if not attach_perms: # It's much easier without attached perms so we do it first if that is # the case group_model = get_group_obj_perms_model(obj) group_rel_name = group_model.group.field.related_query_name() if group_model.objects.is_generic(): group_filters = { '%s__content_type' % group_rel_name: ctype, '%s__object_pk' % group_rel_name: obj.pk, } else: group_filters = {'%s__content_object' % group_rel_name: obj} groups = Group.objects.filter(**group_filters).distinct() return groups else: # TODO: Do not hit db for each group! groups = {} for group in get_groups_with_perms(obj): if not group in groups: groups[group] = sorted(get_perms(group, obj)) return groups
def remove_perm(self, perm, group, obj): """ Removes permission ``perm`` for an instance ``obj`` and given ``group``. """ if getattr(obj, 'pk', None) is None: raise ObjectNotPersisted("Object %s needs to be persisted first" % obj) filters = { 'permission__codename': perm, 'permission__content_type': get_ctype_from_polymorphic(obj), 'group': group, } if self.is_generic(): filters['object_pk'] = obj.pk else: filters['content_object__pk'] = obj.pk self.filter(**filters).delete()
def has_object_permission(self, request, view, obj): ctype = get_ctype_from_polymorphic(obj) model_cls = ctype.model_class() user = request.user perms = self.get_required_object_permissions(request.method, model_cls) if not user.has_perms(perms, obj): if request.method in SAFE_METHODS: raise Http404 read_perms = self.get_required_object_permissions('GET', model_cls) if not user.has_perms(read_perms, obj): raise Http404 return False return True
def assign_perm(self, perm, group, obj): """ Assigns permission with given ``perm`` for an instance ``obj`` and ``group``. """ if getattr(obj, 'pk', None) is None: raise ObjectNotPersisted("Object %s needs to be persisted first" % obj) ctype = get_ctype_from_polymorphic(obj) permission = Permission.objects.get(content_type=ctype, codename=perm) kwargs = {'permission': permission, 'group': group} if self.is_generic(): kwargs['content_type'] = ctype kwargs['object_pk'] = obj.pk else: kwargs['content_object'] = obj obj_perm, created = self.get_or_create(**kwargs) return obj_perm
def has_object_permission(self, request, view, obj): ctype = get_ctype_from_polymorphic(obj) model_cls = ctype.model_class() user = request.user perms = self.get_required_object_permissions(request.method, model_cls) if not user.has_perms(perms, obj): if request.method in SAFE_METHODS: raise Http404 read_perms = self.get_required_object_permissions('GET', model_cls) if not user.has_perms(read_perms, obj): raise Http404 return False return True
def remove_perm(self, perm, user, obj): """ Removes permission ``perm`` for an instance ``obj`` and given ``user``. Please note that we do NOT fetch object permission from database - we use ``Queryset.delete`` method for removing it. Main implication of this is that ``post_delete`` signals would NOT be fired. """ if getattr(obj, 'pk', None) is None: raise ObjectNotPersisted("Object %s needs to be persisted first" % obj) filters = { 'permission__codename': perm, 'permission__content_type': get_ctype_from_polymorphic(obj), 'user': user, } if self.is_generic(): filters['object_pk'] = obj.pk else: filters['content_object__pk'] = obj.pk self.filter(**filters).delete()
def get_perms(self, obj): """ Returns list of ``codename``'s of all permissions for given ``obj``. :param obj: Django model instance for which permission should be checked """ if self.user and not self.user.is_active: return [] User = get_user_model() ctype = get_ctype_from_polymorphic(obj) key = self.get_local_cache_key(obj) if not key in self._obj_perms_cache: group_model = get_group_obj_perms_model(obj) group_rel_name = group_model.permission.field.related_query_name() if self.user: fieldname = '%s__group__%s' % ( group_rel_name, User.groups.field.related_query_name(), ) group_filters = {fieldname: self.user} else: group_filters = {'%s__group' % group_rel_name: self.group} if group_model.objects.is_generic(): group_filters.update({ '%s__content_type' % group_rel_name: ctype, '%s__object_pk' % group_rel_name: obj.pk, }) else: group_filters['%s__content_object' % group_rel_name] = obj if self.user and self.user.is_superuser: perms = list(chain(*Permission.objects .filter(content_type=ctype) .values_list("codename"))) elif self.user: model = get_user_obj_perms_model(obj) related_name = model.permission.field.related_query_name() user_filters = {'%s__user' % related_name: self.user} if model.objects.is_generic(): user_filters.update({ '%s__content_type' % related_name: ctype, '%s__object_pk' % related_name: obj.pk, }) else: user_filters['%s__content_object' % related_name] = obj perms_qs = Permission.objects.filter(content_type=ctype) # Query user and group permissions separately and then combine # the results to avoid a slow query user_perms_qs = perms_qs.filter(**user_filters) user_perms = user_perms_qs.values_list("codename", flat=True) group_perms_qs = perms_qs.filter(**group_filters) group_perms = group_perms_qs.values_list("codename", flat=True) perms = list(set(chain(user_perms, group_perms))) else: perms = list(set(chain(*Permission.objects .filter(content_type=ctype) .filter(**group_filters) .values_list("codename")))) self._obj_perms_cache[key] = perms return self._obj_perms_cache[key]
def get_local_cache_key(self, obj): """ Returns cache key for ``_obj_perms_cache`` dict. """ ctype = get_ctype_from_polymorphic(obj) return (ctype.id, obj.pk)
def get_users_with_perms(obj, attach_perms=False, with_superusers=False, with_group_users=True): """ Returns queryset of all ``User`` objects with *any* object permissions for the given ``obj``. :param obj: persisted Django's ``Model`` instance :param attach_perms: Default: ``False``. If set to ``True`` result would be dictionary of ``User`` instances with permissions' codenames list as values. This would fetch users eagerly! :param with_superusers: Default: ``False``. If set to ``True`` result would contain all superusers. :param with_group_users: Default: ``True``. If set to ``False`` result would **not** contain those users who have only group permissions for given ``obj``. Example:: >>> from django.contrib.flatpages.models import FlatPage >>> from django.contrib.auth.models import User >>> from guardian.shortcuts import assign_perm, get_users_with_perms >>> >>> page = FlatPage.objects.create(title='Some page', path='/some/page/') >>> joe = User.objects.create_user('joe', '*****@*****.**', 'joesecret') >>> assign_perm('change_flatpage', joe, page) >>> >>> get_users_with_perms(page) [<User: joe>] >>> >>> get_users_with_perms(page, attach_perms=True) {<User: joe>: [u'change_flatpage']} """ ctype = get_ctype_from_polymorphic(obj) if not attach_perms: # It's much easier without attached perms so we do it first if that is # the case user_model = get_user_obj_perms_model(obj) related_name = user_model.user.field.related_query_name() if user_model.objects.is_generic(): user_filters = { '%s__content_type' % related_name: ctype, '%s__object_pk' % related_name: obj.pk, } else: user_filters = {'%s__content_object' % related_name: obj} qset = Q(**user_filters) if with_group_users: group_model = get_group_obj_perms_model(obj) group_rel_name = group_model.group.field.related_query_name() if group_model.objects.is_generic(): group_filters = { 'groups__%s__content_type' % group_rel_name: ctype, 'groups__%s__object_pk' % group_rel_name: obj.pk, } else: group_filters = { 'groups__%s__content_object' % group_rel_name: obj, } qset = qset | Q(**group_filters) if with_superusers: qset = qset | Q(is_superuser=True) return get_user_model().objects.filter(qset).distinct() else: # TODO: Do not hit db for each user! users = {} for user in get_users_with_perms(obj, with_group_users=with_group_users): users[user] = sorted(get_perms(user, obj)) return users