diff --git a/gracedb/api/tests/__init__.py b/gracedb/api/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/gracedb/api/v1/superevents/tests/utils.py b/gracedb/api/tests/utils.py similarity index 89% rename from gracedb/api/v1/superevents/tests/utils.py rename to gracedb/api/tests/utils.py index ccb49b2bbf4581b092a318ae2f6c9047448f81aa..2540d725fd8fc0fd6e53b9b8887d5e5304eacc98 100644 --- a/gracedb/api/v1/superevents/tests/utils.py +++ b/gracedb/api/tests/utils.py @@ -19,7 +19,8 @@ class GraceDbApiTestBase(GraceDbTestBase): # Set up user dict user_dict = { 'HTTP_REMOTE_USER': user.username, - 'HTTP_ISMEMBEROF': ';'.join([g.name for g in user.groups.all()]), + 'HTTP_ISMEMBEROF': ';'.join([g.name for g in + user.groups.all()]), } # Make request and return response diff --git a/gracedb/api/v1/filters.py b/gracedb/api/v1/filters.py new file mode 100644 index 0000000000000000000000000000000000000000..1c6ec442e0bc2dd51ae8467b6857447b5923b4f6 --- /dev/null +++ b/gracedb/api/v1/filters.py @@ -0,0 +1,34 @@ +import logging + +from rest_framework import filters + +# Set up logger +logger = logging.getLogger(__name__) + + +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/api/v1/superevents/mixins.py b/gracedb/api/v1/mixins.py similarity index 95% rename from gracedb/api/v1/superevents/mixins.py rename to gracedb/api/v1/mixins.py index 0b487859983c99022acb87046f9a3a623a9e6129..d526b62f3d776276aadf36c523b91953ded7b958 100644 --- a/gracedb/api/v1/superevents/mixins.py +++ b/gracedb/api/v1/mixins.py @@ -16,7 +16,7 @@ class SafeDestroyMixin(mixins.DestroyModelMixin): """ Copy of rest_framework's DestroyModelMixin which wraps the call to perform_destroy() in a try-except block for - proper response handling. + proper error handling. """ destroy_error_classes = (Exception,) destroy_error_response_status = status.HTTP_500_INTERNAL_SERVER_ERROR @@ -36,7 +36,7 @@ class SafeCreateMixin(mixins.CreateModelMixin): """ Copy of rest_framework's CreateModelMixin which wraps the call to perform_destroy() in a try-except block for - proper response handling. + proper error handling. """ create_error_classes = \ (DjangoValidationError, RestFrameworkValidationError) @@ -52,5 +52,6 @@ class SafeCreateMixin(mixins.CreateModelMixin): err_msg = self.create_error_message or e.__str__() return Response(err_msg, status=self.create_error_response_status) headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + return Response(serializer.data, status=status.HTTP_201_CREATED, + headers=headers) diff --git a/gracedb/api/v1/paginators.py b/gracedb/api/v1/paginators.py new file mode 100644 index 0000000000000000000000000000000000000000..6fa5e67775bc13b30d876740eaa129d8dac0d330 --- /dev/null +++ b/gracedb/api/v1/paginators.py @@ -0,0 +1,97 @@ +from collections import OrderedDict +import logging +import urllib + +from rest_framework import pagination +from rest_framework.response import Response + +# Set up logger +logger = logging.getLogger(__name__) + +# TP (30 Apr 2018): +# This module has a bunch of hacked together pagination which is intended +# to match the existing "pagination" of the events API. We should definitely +# redo both APIs to do something reasonable and consistent when we have a +# chance. + + +def BasePaginationFactory(links_dict=True, results_name='results'): + class CustomBasePagination(pagination.PageNumberPagination): + generate_links = links_dict + results_key = results_name + + def get_paginated_response(self, data): + output = OrderedDict([ + ('start', 0), + ('numRows', len(data)), + (self.results_key, data), + ]) + + if self.generate_links: + link_dict = OrderedDict([ + ('self', self.request.build_absolute_uri()), + ('first', self.request.build_absolute_uri()), + ('last', self.request.build_absolute_uri()), + ]) + output['links'] = link_dict + + return Response(output) + + return CustomBasePagination + + +class CustomLabelPagination(pagination.PageNumberPagination): + def get_paginated_response(self, data): + output = OrderedDict([ + ('labels', data), + ('links', + OrderedDict([ + ('self', self.request.build_absolute_uri()), + ('superevent', self.request.build_absolute_uri()), + ])), + ]) + + return Response(output) + + +class CustomLogTagPagination(pagination.PageNumberPagination): + def get_paginated_response(self, data): + output = OrderedDict([ + ('tags', data), + ]) + + return Response(output) + + +class CustomSupereventPagination(pagination.LimitOffsetPagination): + default_limit = 10 + limit_query_param = 'count' + offset_query_param = 'start' + + def get_paginated_response(self, data): + numRows = self.count + + # Get base URI + base_uri = self.request.build_absolute_uri(self.request.path) + + # Construct custom link for "last" page + last = max(0, (numRows / self.limit)) * self.limit + param_dict = { + 'start': last, + self.limit_query_param: self.limit, + } + last_uri = base_uri + '?' + urllib.urlencode(param_dict) + + output = OrderedDict([ + ('numRows', numRows), + ('superevents', data), + ('links', + OrderedDict([ + ('self', self.request.build_absolute_uri()), + ('next', self.get_next_link()), + ('previous', self.get_previous_link()), + ('first', base_uri), + ('last', last_uri), + ])), + ]) + return Response(output) diff --git a/gracedb/api/v1/permissions.py b/gracedb/api/v1/permissions.py new file mode 100644 index 0000000000000000000000000000000000000000..3db9703fe4cc55d515e1529b9dabe02831eeaddb --- /dev/null +++ b/gracedb/api/v1/permissions.py @@ -0,0 +1,136 @@ +import logging + +from rest_framework import exceptions, permissions + +# Set up logger +logger = logging.getLogger(__name__) + +# NOTE: considering only LVC and lv-em users for now. Will have to +# think about public in the future. + + +class FunctionalModelPermissions(permissions.BasePermission): + """ + Model-based table-level permissions which allow for custom functionality. + + Custom permission requirements should be defined in methods called + 'get_METHOD_permissions', where METHOD is the HTTP method for which the + permissions apply. If such a class method does not exist, no permissions + are required for that method. + + Designed around rest_framework.permissions.DjangoModelPermissions and + takes a lot of the logic from there. + """ + authenticated_users_only = True + allowed_methods = ['GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', + 'DELETE'] + + def get_required_permissions(self, request): + # Is permission in allowed methods? + if request.method not in self.allowed_methods: + raise exceptions.MethodNotAllowed(request.method) + + # Get method for checking permissions - named like + # get_{http_method}_permissions() + perm_getter_function_name = "get_{method}_permissions".format( + method=request.method.lower()) + + # If method exists, call it and get permissions + if hasattr(self, perm_getter_function_name): + perm_getter_function = getattr(self, perm_getter_function_name) + perms = perm_getter_function(request) + else: + # If the method is not defined, no permissions are required + perms = [] + + return perms + + def has_permission(self, request, view): + # Run by at the start of request processing by view.initial(), + # which calls view.check_permissions(). + + # Workaround to ensure there permissions are not applied + # to the root view when using DefaultRouter. + if getattr(view, '_ignore_model_permissions', False): + return True + + # Check user authentication status + if not request.user or (not request.user.is_authenticated and + self.authenticated_users_only): + return False + + # Get required permissions + perms = self.get_required_permissions(request) + + # Return True/False + return request.user.has_perms(perms) + + +class FunctionalObjectPermissions(permissions.BasePermission): + """ + Model-based row-level permissions which allow for custom functionality. + + Custom permission requirements should be defined in methods called + 'get_METHOD_object_permissions', where METHOD is the HTTP method for which + the permissions apply. If such a class method does not exist, we fall back + to the base class and check the self.perms_map attribute for a list of + required permissions. We also pass the object to the permission checker, + since its attributes may be used to determine which permissions should + be required. + """ + authenticated_users_only = True + allowed_methods = ['GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', + 'DELETE'] + + def get_required_object_permissions(self, request, obj): + # Is permission in allowed methods? + if request.method not in self.allowed_methods: + raise exceptions.MethodNotAllowed(request.method) + + # Get method for checking permissions - named like + # get_{http_method}_object_permissions() + perm_getter_function_name = "get_{method}_object_permissions".format( + method=request.method.lower()) + + # If method exists, call it and get permissions + if hasattr(self, perm_getter_function_name): + perm_getter_function = getattr(self, perm_getter_function_name) + perms = perm_getter_function(request, obj) + else: + # If the method is not defined, no permissions are required + perms = [] + + return perms + + def has_object_permission(self, request, view, obj): + # This is called within view.get_object(), which calls + # view.check_object_permissions() + + # Check user authentication status + if not request.user or (not request.user.is_authenticated and + self.authenticated_users_only): + return False + + # Get permissions + perms = self.get_required_object_permissions(request, obj) + + # Return True/False + return request.user.has_perms(perms, obj) + + +class FunctionalParentObjectPermissions(FunctionalObjectPermissions): + """ + Inherits almost everything from FunctionalObjectPermissions, but + we want to simply rename has_object_permission to + "has_parent_object_permission", so we have to override that method. + + Permission-getting methods should be named as for + FunctionalObjectPermissions; i.e., like 'get_post_object_permissions'. + """ + + def has_object_permission(self, request, view, obj): + return True + + def has_parent_object_permission(self, request, view, parent_obj): + return super(FunctionalParentObjectPermissions, self) \ + .has_object_permission(request, view, parent_obj) diff --git a/gracedb/api/v1/superevents/filters.py b/gracedb/api/v1/superevents/filters.py index 85e974487c4783a57771375ca54ba5b364fc29b5..8c0f73ba724b277c5c5fb861b44933531133467d 100644 --- a/gracedb/api/v1/superevents/filters.py +++ b/gracedb/api/v1/superevents/filters.py @@ -87,31 +87,3 @@ 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/api/v1/superevents/paginators.py b/gracedb/api/v1/superevents/paginators.py index 6fa5e67775bc13b30d876740eaa129d8dac0d330..599682a17d4b8a02e5b15c8c6f02c1ebf0b0bfde 100644 --- a/gracedb/api/v1/superevents/paginators.py +++ b/gracedb/api/v1/superevents/paginators.py @@ -8,60 +8,6 @@ from rest_framework.response import Response # Set up logger logger = logging.getLogger(__name__) -# TP (30 Apr 2018): -# This module has a bunch of hacked together pagination which is intended -# to match the existing "pagination" of the events API. We should definitely -# redo both APIs to do something reasonable and consistent when we have a -# chance. - - -def BasePaginationFactory(links_dict=True, results_name='results'): - class CustomBasePagination(pagination.PageNumberPagination): - generate_links = links_dict - results_key = results_name - - def get_paginated_response(self, data): - output = OrderedDict([ - ('start', 0), - ('numRows', len(data)), - (self.results_key, data), - ]) - - if self.generate_links: - link_dict = OrderedDict([ - ('self', self.request.build_absolute_uri()), - ('first', self.request.build_absolute_uri()), - ('last', self.request.build_absolute_uri()), - ]) - output['links'] = link_dict - - return Response(output) - - return CustomBasePagination - - -class CustomLabelPagination(pagination.PageNumberPagination): - def get_paginated_response(self, data): - output = OrderedDict([ - ('labels', data), - ('links', - OrderedDict([ - ('self', self.request.build_absolute_uri()), - ('superevent', self.request.build_absolute_uri()), - ])), - ]) - - return Response(output) - - -class CustomLogTagPagination(pagination.PageNumberPagination): - def get_paginated_response(self, data): - output = OrderedDict([ - ('tags', data), - ]) - - return Response(output) - class CustomSupereventPagination(pagination.LimitOffsetPagination): default_limit = 10 diff --git a/gracedb/api/v1/superevents/permissions.py b/gracedb/api/v1/superevents/permissions.py index a935d44a60fabf836e8009fb8d2e6655e6974981..8419762aa8515af7e80af8aef8ba93f943ad7b81 100644 --- a/gracedb/api/v1/superevents/permissions.py +++ b/gracedb/api/v1/superevents/permissions.py @@ -3,9 +3,11 @@ import logging from django.conf import settings from django.urls import resolve -from rest_framework import exceptions, permissions +from rest_framework import permissions from superevents.models import Superevent +from ..permissions import FunctionalModelPermissions, \ + FunctionalObjectPermissions, FunctionalParentObjectPermissions # Set up logger logger = logging.getLogger(__name__) @@ -14,133 +16,6 @@ logger = logging.getLogger(__name__) # think about public in the future. -class FunctionalModelPermissions(permissions.BasePermission): - """ - Model-based table-level permissions which allow for custom functionality. - - Custom permission requirements should be defined in methods called - 'get_METHOD_permissions', where METHOD is the HTTP method for which the - permissions apply. If such a class method does not exist, no permissions - are required for that method. - - Designed around rest_framework.permissions.DjangoModelPermissions and - takes a lot of the logic from there. - """ - authenticated_users_only = True - allowed_methods = ['GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', - 'DELETE'] - - def get_required_permissions(self, request): - # Is permission in allowed methods? - if request.method not in self.allowed_methods: - raise exceptions.MethodNotAllowed(request.method) - - # Get method for checking permissions - named like - # get_{http_method}_permissions() - perm_getter_function_name = "get_{method}_permissions".format( - method=request.method.lower()) - - # If method exists, call it and get permissions - if hasattr(self, perm_getter_function_name): - perm_getter_function = getattr(self, perm_getter_function_name) - perms = perm_getter_function(request) - else: - # If the method is not defined, no permissions are required - perms = [] - - return perms - - def has_permission(self, request, view): - # Run by at the start of request processing by view.initial(), - # which calls view.check_permissions(). - - # Workaround to ensure there permissions are not applied - # to the root view when using DefaultRouter. - if getattr(view, '_ignore_model_permissions', False): - return True - - # Check user authentication status - if not request.user or (not request.user.is_authenticated and - self.authenticated_users_only): - return False - - # Get required permissions - perms = self.get_required_permissions(request) - - # Return True/False - return request.user.has_perms(perms) - - -class FunctionalObjectPermissions(permissions.BasePermission): - """ - Model-based row-level permissions which allow for custom functionality. - - Custom permission requirements should be defined in methods called - 'get_METHOD_object_permissions', where METHOD is the HTTP method for which - the permissions apply. If such a class method does not exist, we fall back - to the base class and check the self.perms_map attribute for a list of - required permissions. We also pass the object to the permission checker, - since its attributes may be used to determine which permissions should - be required. - """ - authenticated_users_only = True - allowed_methods = ['GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', - 'DELETE'] - - def get_required_object_permissions(self, request, obj): - # Is permission in allowed methods? - if request.method not in self.allowed_methods: - raise exceptions.MethodNotAllowed(request.method) - - # Get method for checking permissions - named like - # get_{http_method}_object_permissions() - perm_getter_function_name = "get_{method}_object_permissions".format( - method=request.method.lower()) - - # If method exists, call it and get permissions - if hasattr(self, perm_getter_function_name): - perm_getter_function = getattr(self, perm_getter_function_name) - perms = perm_getter_function(request, obj) - else: - # If the method is not defined, no permissions are required - perms = [] - - return perms - - def has_object_permission(self, request, view, obj): - # This is called within view.get_object(), which calls - # view.check_object_permissions() - - # Check user authentication status - if not request.user or (not request.user.is_authenticated and - self.authenticated_users_only): - return False - - # Get permissions - perms = self.get_required_object_permissions(request, obj) - - # Return True/False - return request.user.has_perms(perms, obj) - - -class FunctionalParentObjectPermissions(FunctionalObjectPermissions): - """ - Inherits almost everything from FunctionalObjectPermissions, but - we want to simply rename has_object_permission to - "has_parent_object_permission", so we have to override that method. - - Permission-getting methods should be named as for - FunctionalObjectPermissions; i.e., like 'get_post_object_permissions'. - """ - - def has_object_permission(self, request, view, obj): - return True - - def has_parent_object_permission(self, request, view, parent_obj): - return super(FunctionalParentObjectPermissions, self) \ - .has_object_permission(request, view, parent_obj) - - class SupereventModelPermissions(FunctionalModelPermissions): """ Custom permissions for the superevent list view - we require different diff --git a/gracedb/api/v1/superevents/serializers.py b/gracedb/api/v1/superevents/serializers.py index ea0c44081afb6b096a94e7212e6aac5d8994021e..30523629c15d735b8a8f2d1aa65d0e538d670ecc 100644 --- a/gracedb/api/v1/superevents/serializers.py +++ b/gracedb/api/v1/superevents/serializers.py @@ -13,9 +13,9 @@ from rest_framework.exceptions import ValidationError from events.models import Event, Label, Tag, EMGroup from superevents.models import Superevent, Labelling, Log, VOEvent, \ EMObservation, EMFootprint, Signoff -from .fields import ParentObjectDefault, CommaSeparatedOrListField, \ - ChoiceDisplayField from .settings import SUPEREVENT_LOOKUP_URL_KWARG +from ..fields import ParentObjectDefault, CommaSeparatedOrListField, \ + ChoiceDisplayField from ..events.fields import EventGraceidField from ...utils import api_reverse diff --git a/gracedb/api/v1/superevents/tests/test_access.py b/gracedb/api/v1/superevents/tests/test_access.py index 0650d334d8888a042d468145d5d1ea1f7338f837..2b25d8febc03e7d883ed553252f5a3320fc0b475 100644 --- a/gracedb/api/v1/superevents/tests/test_access.py +++ b/gracedb/api/v1/superevents/tests/test_access.py @@ -10,6 +10,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from guardian.shortcuts import assign_perm, remove_perm +from api.tests.utils import GraceDbApiTestBase from core.permission_utils import expose_event_or_superevent_to_lvem, \ expose_event_or_superevent_to_public, expose_log_to_lvem, \ expose_log_to_public @@ -20,7 +21,7 @@ from superevents.models import Superevent, Labelling, Log, VOEvent, \ EMObservation from superevents.utils import create_log from .mixins import SupereventCreateMixin -from .utils import GraceDbApiTestBase + class SupereventSetup(GraceDbTestBase, SupereventCreateMixin): """ diff --git a/gracedb/api/v1/superevents/views.py b/gracedb/api/v1/superevents/views.py index 16602f253080fc8ee874b87da1d521b290540cc4..41bca975dce8a49881be8177aa2dbe3197bcfbc6 100644 --- a/gracedb/api/v1/superevents/views.py +++ b/gracedb/api/v1/superevents/views.py @@ -23,12 +23,8 @@ from superevents.models import Superevent, Log from superevents.utils import remove_tag_from_log, \ remove_event_from_superevent, remove_label_from_superevent, \ confirm_superevent_as_gw, get_superevent_by_date_id_or_404 -from .base_viewsets import SupereventNestedViewSet -from .filters import SupereventSearchFilter, SupereventOrderingFilter, \ - DjangoObjectAndGlobalPermissionsFilter -from .mixins import SafeCreateMixin, SafeDestroyMixin -from .paginators import BasePaginationFactory, CustomLabelPagination, \ - CustomLogTagPagination, CustomSupereventPagination +from .filters import SupereventSearchFilter, SupereventOrderingFilter +from .paginators import CustomSupereventPagination from .permissions import SupereventModelPermissions, \ SupereventObjectPermissions, SupereventLabellingModelPermissions, \ EventParentSupereventPermissions, SupereventLogModelPermissions, \ @@ -39,6 +35,11 @@ from .serializers import SupereventSerializer, SupereventUpdateSerializer, \ SupereventLogSerializer, SupereventLogTagSerializer, \ SupereventVOEventSerializer, SupereventEMObservationSerializer from .settings import SUPEREVENT_LOOKUP_URL_KWARG, SUPEREVENT_LOOKUP_REGEX +from .viewsets import SupereventNestedViewSet +from ..filters import DjangoObjectAndGlobalPermissionsFilter +from ..mixins import SafeCreateMixin, SafeDestroyMixin +from ..paginators import BasePaginationFactory, CustomLabelPagination, \ + CustomLogTagPagination from ...utils import api_reverse # Set up logger diff --git a/gracedb/api/v1/superevents/viewsets.py b/gracedb/api/v1/superevents/viewsets.py new file mode 100644 index 0000000000000000000000000000000000000000..da0033c27d7a3f4851512ffcfc4d46b9a27a8a0b --- /dev/null +++ b/gracedb/api/v1/superevents/viewsets.py @@ -0,0 +1,30 @@ +import logging + +from superevents.models import Superevent +from superevents.utils import get_superevent_by_date_id_or_404 +from .settings import SUPEREVENT_LOOKUP_URL_KWARG +from ..viewsets import NestedViewSet + +# Set up logger +logger = logging.getLogger(__name__) + + +class SupereventNestedViewSet(NestedViewSet): + """ + Gets a parent superevent object for a nested object by using the + URL kwargs. Also does a check on object permissions for the superevent, + since some actions, like annotation, are controlled by a custom permission + on the parent superevent itself. + """ + parent_lookup_field = None # not needed due to custom lookup function + parent_lookup_url_kwarg = SUPEREVENT_LOOKUP_URL_KWARG + parent_queryset = Superevent.objects.all() + parent_access_permission = 'superevents.view_superevent' + check_permissions_on_parent_object = True + + def _set_parent(self): + parent_lookup_value = self.get_parent_lookup_value() + parent_queryset = self.get_parent_queryset() + parent = get_superevent_by_date_id_or_404(parent_lookup_value, + parent_queryset) + self._parent = parent diff --git a/gracedb/api/v1/superevents/base_viewsets.py b/gracedb/api/v1/viewsets.py similarity index 84% rename from gracedb/api/v1/superevents/base_viewsets.py rename to gracedb/api/v1/viewsets.py index 59f13047e44fb709a009bf3f5bbefafa8fa3fca3..3fcca879423c6ea5053f3c45d00ba74889482c59 100644 --- a/gracedb/api/v1/superevents/base_viewsets.py +++ b/gracedb/api/v1/viewsets.py @@ -5,10 +5,6 @@ from django.shortcuts import get_object_or_404 from guardian.shortcuts import get_objects_for_user from rest_framework import viewsets -from superevents.models import Superevent -from superevents.utils import get_superevent_by_date_id_or_404 -from .settings import SUPEREVENT_LOOKUP_URL_KWARG - # Set up logger logger = logging.getLogger(__name__) @@ -135,24 +131,3 @@ class NestedViewSet(viewsets.GenericViewSet): parent = get_object_or_404(parent_queryset, **{self.parent_lookup_field: parent_lookup_value}) self._parent = parent - - -class SupereventNestedViewSet(NestedViewSet): - """ - Gets a parent superevent object for a nested object by using the - URL kwargs. Also does a check on object permissions for the superevent, - since some actions, like annotation, are controlled by a custom permission - on the parent superevent itself. - """ - parent_lookup_field = None # not needed due to custom lookup function - parent_lookup_url_kwarg = SUPEREVENT_LOOKUP_URL_KWARG - parent_queryset = Superevent.objects.all() - parent_access_permission = 'superevents.view_superevent' - check_permissions_on_parent_object = True - - def _set_parent(self): - parent_lookup_value = self.get_parent_lookup_value() - parent_queryset = self.get_parent_queryset() - parent = get_superevent_by_date_id_or_404(parent_lookup_value, - parent_queryset) - self._parent = parent