Source code for model_permissions.views

"""
django-model-permissions - simple object permissions for django.

Copyright (C) 2018 Mathias Stelzer

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
from django.contrib.auth.context_processors import PermLookupDict, PermWrapper
from django.core.exceptions import PermissionDenied
from django.views.generic import (
    DetailView as DjangoDetailView,
    UpdateView as DjangoUpdateView,
    DeleteView as DjangoDeleteView,
)


[docs]class ObjPermLookupDict(PermLookupDict): """Object permissions lookup dictionary.""" def __init__(self, user, app_label, obj=None): """Initialize object permission lookup dictionary.""" super(ObjPermLookupDict, self).__init__(user, app_label) self.object = obj def __getitem__(self, perm_name): """Check whether the user has the given permission for the object.""" return self.user.has_perm('{}.{}'.format(self.app_label, perm_name), self.object)
[docs]class ObjPermWrapper(PermWrapper): """Object permissions wrapper to traverse a list of permissions.""" def __init__(self, user, obj=None): """Initialize object permissions wrapper.""" super(ObjPermWrapper, self).__init__(user) self.object = obj def __getitem__(self, app_label): """Get a lookup dictionary for the object.""" return ObjPermLookupDict(self.user, app_label, self.object)
[docs]class PermissionContextMixin(object): """ View mixin to insert permissions in the template context. If the `get_context_data` method is called and the context contains an `'object'` element, this will insert a `'object_perms'` permission wrapper. The `get_context_object_name` method will be used too, if it exists. """
[docs] def get_context_data(self, **kwargs): """Add object permissions to template context.""" kwargs = super().get_context_data(**kwargs) if getattr(self, 'object', None): permission_wrapper = ObjPermWrapper(self.request.user, self.object) kwargs['object_perms'] = permission_wrapper if hasattr(self, 'get_context_object_name'): context_object_name = self.get_context_object_name(self.object) if context_object_name: kwargs[context_object_name + '_perms'] = permission_wrapper return kwargs
[docs]class RequirePermissionMixin(object): """View mixin to require object permissions for access.""" required_permission = None # noinspection PyMethodMayBeStatic
[docs] def get_required_permission_object(self, obj): """Overwrite to check the required_permission against another model object.""" return obj
[docs] def check_required_permission(self, permission_object): """ Check the `required_permission` on the given object. :raises: :class:`django.core.exceptions.PermissionDenied` if the current user does not have the `required_permission`. """ if not self.has_perm(self.required_permission, permission_object): raise PermissionDenied()
[docs] def get_object(self, queryset=None): """ Get the object and check the `required_permission` on it. :raises: :class:`django.core.exceptions.PermissionDenied` if the current user does not have the `required_permission`. """ obj = super().get_object(queryset=queryset) if self.required_permission is not None: perm_obj = self.get_required_permission_object(obj) self.check_required_permission(perm_obj) return obj
[docs] def has_perm(self, perm, obj=None): """Check the given permission on the given object.""" return self.request.user.has_perm(perm, obj=obj)
[docs]class PermissionMixin(RequirePermissionMixin, PermissionContextMixin): """View mixin to enable permissions.""" pass
[docs]class DetailView(PermissionMixin, DjangoDetailView): """DetailView with permissions.""" pass
[docs]class UpdateView(PermissionMixin, DjangoUpdateView): """UpdateView with permissions.""" pass
[docs]class DeleteView(PermissionMixin, DjangoDeleteView): """DeleteView with permissions.""" pass