From 5574aaa8cb8556e6b2cbe2d29a9137da54f36c61 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 1 Jun 2020 10:45:49 -0400 Subject: [PATCH] Tweak restrict() to accept only an action keyword --- netbox/utilities/api.py | 20 ++++++++++++-------- netbox/utilities/querysets.py | 8 ++++++-- netbox/utilities/views.py | 3 ++- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index ac21d298c..50401dfd1 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -330,16 +330,20 @@ class ModelViewSet(_ModelViewSet): if not request.user.is_authenticated or request.user.is_superuser: return - # TODO: Move this to a cleaner function - # Determine the required permission based on the request method - kwargs = { - 'app_label': self.queryset.model._meta.app_label, - 'model_name': self.queryset.model._meta.model_name - } - permission_required = TokenPermissions.perms_map[request.method][0] % kwargs + # TODO: Reconcile this with TokenPermissions.perms_map + action = { + 'GET': 'view', + 'OPTIONS': None, + 'HEAD': 'view', + 'POST': 'add', + 'PUT': 'change', + 'PATCH': 'change', + 'DELETE': 'delete', + }[request.method] # Restrict the view's QuerySet to allow only the permitted objects - self.queryset = self.queryset.restrict(request.user, permission_required) + if action: + self.queryset = self.queryset.restrict(request.user, action) def dispatch(self, request, *args, **kwargs): logger = logging.getLogger('netbox.api.views.ModelViewSet') diff --git a/netbox/utilities/querysets.py b/netbox/utilities/querysets.py index 3bc41e072..07199e143 100644 --- a/netbox/utilities/querysets.py +++ b/netbox/utilities/querysets.py @@ -14,15 +14,19 @@ class DummyQuerySet: class RestrictedQuerySet(QuerySet): - def restrict(self, user, permission_required): + def restrict(self, user, action): """ Filter the QuerySet to return only objects on which the specified user has been granted the specified permission. :param queryset: Base QuerySet to be restricted :param user: User instance - :param permission_required: Name of the required permission (e.g. "dcim.view_site") + :param action: The action which must be permitted (e.g. "view" for "dcim.view_site") """ + # Resolve the full name of the required permission + app_label = self.model._meta.app_label + model_name = self.model._meta.model_name + permission_required = f'{app_label}.{action}_{model_name}' # Determine what constraints (if any) have been placed on this user for this action and model # TODO: Find a better way to ensure permissions are cached diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index fed774812..f59492a0c 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -66,7 +66,8 @@ class ObjectPermissionRequiredMixin(AccessMixin): # Update the view's QuerySet to filter only the permitted objects if user.is_authenticated and not user.is_superuser: - self.queryset = self.queryset.restrict(user, permission_required) + action = permission_required.split('.')[1].split('_')[0] + self.queryset = self.queryset.restrict(user, action) return True