dfunckt / django-rules

Awesome Django authorization, without the database

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: PermissionRequiredMethodMixin

martinlehoux opened this issue · comments

Hello !

As I was using django-rules in a project, I need to use different permissions for the same view, depending on the method used. My use case is very simple : instead of having a DetailView and an UpdateView, I only use UpdateView, but the page GET purpose is to display the detail (the form is hidden in a modal). So I wanted to enable to enable GET for this UpdateView for "track.view_track" permission, but the POST only for "track.edit_track".

I couldn't find in the documentation how to do so, so I ended up with this new class base view mixin. I wrote it inspired by django.auth.contrib.mixins.PermissionRequireMixin and rules.contrib.views.PermissionRequiredMixin. I thought it was generic enough to propose it here.

Maybe I have missed an already existing implementation, so don't hesitate to tell me !

class TrackDetailView(PermissionRequiredMethodMixin, generic.UpdateView):
    permission_required_map = {
        "GET": "track.view_track",
        "POST": "track.edit_track",
    }
class PermissionRequiredMethodMixin(PermissionRequiredMixin):
    permission_required_map: Dict[str, Union[str, Tuple[str]]] = None

    def get_permission_required(self):
        if self.permission_required_map is not None:
            if not isinstance(self.permission_required_map, dict):
                raise ImproperlyConfigured(
                    f"{self.__class__.__name__} has a wrong permission_required_map attribute. "
                    "It should be a mapping from http method to permission."
                )
            perms = self.permission_required_map.get(self.request.method)
            if perms is not None:
                return (perms,) if isinstance(perms, str) else perms
        return super().get_permission_required()