diff --git a/drf_roles/mixins.py b/drf_roles/mixins.py index 2c87a6c..03334f1 100644 --- a/drf_roles/mixins.py +++ b/drf_roles/mixins.py @@ -1,8 +1,12 @@ from django.conf import settings -from django.contrib.auth.models import Group +from django.contrib.auth.models import Group, Permission # Default settings DEFAULT_GROUPS = [group.name.lower() for group in Group.objects.all()] +DEFAULT_PERMISSIONS = [ + permission.codename.lower() for permission in Permission.objects.all() +] + DEFAULT_REGISTRY = ( "get_queryset", "get_serializer_class", @@ -42,6 +46,36 @@ def _get_role(self, user): else: return user_role.pop() + +class PermissionViewSetMixin(object): + """A ViewSet mixin that parameterizes DRF methods over permissions.""" + _viewset_method_registry = set(getattr(settings, "VIEWSET_METHOD_REGISTRY", DEFAULT_REGISTRY)) + _permissions = DEFAULT_PERMISSIONS + + def __init__(self, *args, **kwargs): + for permission in self._permissions: + for fn in self._viewset_method_registry: + register_permission_fn(permission, fn) + + def _call_permission_fn(self, fn, permission, *args, **kwargs): + """Attempts to call a permission-scoped method""" + try: + if not self.request.user.has_perm(permission): + raise RoleError("The user does not have the required permission") + permission_fn = "{}_for_{}".format(fn, permission) + return getattr(self, permission_fn)(*args, **kwargs) + except (AttributeError, RoleError): + return getattr(super(PermissionViewSetMixin, self), fn)(*args, **kwargs) + + +def register_permission_fn(permission, fn): + """Dynamically adds fn to PermissionViewSetMixin. + """ + def inner(self, *args, **kwargs): + return self._call_permission_fn(fn, permission, *args, **kwargs) + setattr(PermissionViewSetMixin, fn, inner) + + def register_fn(fn): """Dynamically adds fn to RoleViewSetMixin""" def inner(self, *args, **kwargs): diff --git a/setup.py b/setup.py index 3e24528..3868ef6 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name='django-rest-framework-roles', - version='0.5', + version='0.6', packages=['drf_roles'], include_package_data=True, license='BSD License',