From 32d36d5eb9ebdca5c17713b47090388fba71e3bb Mon Sep 17 00:00:00 2001 From: Tanner Prestegard <tanner.prestegard@ligo.org> Date: Wed, 22 Aug 2018 13:31:24 -0500 Subject: [PATCH] Global and object permission filter for viewsets The built-in DjangoObjectPermissionsFilter from DRF doesn't accept global (table-level) permissions as higher-level than object permissions. This filter replaces the built-in one and sets the 'accept_global_perms' argument to True so that global permissions are accepted when filtering objects based on user view permissions. --- gracedb/superevents/api/filters.py | 28 ++++++++++++++++++++++++++++ gracedb/superevents/api/views.py | 17 +++++------------ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/gracedb/superevents/api/filters.py b/gracedb/superevents/api/filters.py index 797955cf3..f07078d76 100644 --- a/gracedb/superevents/api/filters.py +++ b/gracedb/superevents/api/filters.py @@ -82,3 +82,31 @@ class SupereventOrderingFilter(filters.OrderingFilter): # No ordering was included, or all the ordering fields were invalid return self.get_default_ordering(view) + + +class DjangoObjectAndGlobalPermissionsFilter( + filters.DjangoObjectPermissionsFilter): + """ + Same as DjangoObjectPermissionsFilter, except it allows global permissions. + """ + accept_global_perms = True + + def filter_queryset(self, request, queryset, view): + # Mostly from rest_framework.filters.DjangoObjectPermissionsFilter + # + # We want to defer this import until run-time, rather than import-time. + # See https://github.com/encode/django-rest-framework/issues/4608 + # (Also see #1624 for why we need to make this import explicitly) + from guardian.shortcuts import get_objects_for_user + + extra = {} + user = request.user + model_cls = queryset.model + kwargs = { + 'app_label': model_cls._meta.app_label, + 'model_name': model_cls._meta.model_name + } + permission = self.perm_format % kwargs + extra['accept_global_perms'] = self.accept_global_perms + + return get_objects_for_user(user, permission, queryset, **extra) diff --git a/gracedb/superevents/api/views.py b/gracedb/superevents/api/views.py index 5743be0e7..830d34d79 100644 --- a/gracedb/superevents/api/views.py +++ b/gracedb/superevents/api/views.py @@ -26,7 +26,8 @@ from events.view_utils import reverse as gracedb_reverse from events.api.backends import LigoAuthentication from ..buildVOEvent import VOEventBuilderException -from .filters import SupereventSearchFilter, SupereventOrderingFilter +from .filters import SupereventSearchFilter, SupereventOrderingFilter, \ + DjangoObjectAndGlobalPermissionsFilter from .mixins import GetParentSupereventMixin, BaseGetObjectMixin, \ SafeDestroyMixin, SafeCreateMixin from .paginators import BasePaginationFactory, CustomLabelPagination, \ @@ -52,7 +53,8 @@ class SupereventViewSet(SafeCreateMixin, viewsets.ModelViewSet): pagination_class = CustomSupereventPagination lookup_field = SUPEREVENT_LOOKUP_FIELD lookup_value_regex = SUPEREVENT_LOOKUP_REGEX - filter_backends = (SupereventSearchFilter, SupereventOrderingFilter,) + filter_backends = (DjangoObjectAndGlobalPermissionsFilter, + SupereventSearchFilter, SupereventOrderingFilter,) ordering_fields = ('created', 't_0', 't_start', 't_end', 'preferred_event__id', 't_0_date', 'is_gw', 'base_date_number', 'gw_date_number', 'category') @@ -64,15 +66,6 @@ class SupereventViewSet(SafeCreateMixin, viewsets.ModelViewSet): serializer_class = SupereventUpdateSerializer return serializer_class - def get_queryset(self): - """Filter queryset for user""" - # TODO: do we need to filter this any further? - # TODO: Check that this might be causing slowness - #queryset = get_objects_for_user(self.request.user, - # 'superevents.view_superevent') - queryset = self.queryset - return queryset - def get_object(self): queryset = self.filter_queryset(self.get_queryset()) superevent_id = self.kwargs.get(self.lookup_field) @@ -172,9 +165,9 @@ class SupereventLogViewSet(mixins.ListModelMixin, parser_class = parsers.FileUploadParser serializer_class = SupereventLogSerializer pagination_class = BasePaginationFactory(results_name='log') + filter_backends = (DjangoObjectAndGlobalPermissionsFilter,) lookup_field = 'N' - # TODO: filter logs for viewers def get_queryset(self): superevent = self.get_parent() queryset = superevent.log_set.all().order_by('N') -- GitLab