From cc220ba8be8ec263cd55936d77c6e39b61559d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20K=C3=BCnsem=C3=B6ller?= <jkuensem@physik.uni-bielefeld.de> Date: Wed, 31 Mar 2021 20:03:57 +0200 Subject: [PATCH] TMSS-230: Enable generic filtering by default, and improve custom filters on SUs --- .../tmss/tmssapp/viewsets/lofar_viewset.py | 64 ++++++------------- .../tmss/tmssapp/viewsets/specification.py | 31 +++++++-- 2 files changed, 45 insertions(+), 50 deletions(-) diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/lofar_viewset.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/lofar_viewset.py index fa74b76b1a3..86631f7c703 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/lofar_viewset.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/lofar_viewset.py @@ -19,50 +19,27 @@ from rest_framework.decorators import action from lofar.common import json_utils from lofar.sas.tmss.tmss.tmssapp.viewsets.permissions import TMSSPermissions, IsProjectMemberFilterBackend from lofar.sas.tmss.tmss.tmssapp.models import permissions -from django_filters.rest_framework import DjangoFilterBackend +from django_filters.rest_framework import DjangoFilterBackend, FilterSet, CharFilter +from django_filters import filterset from rest_framework.filters import OrderingFilter +from django.contrib.postgres.fields import JSONField, ArrayField +from copy import deepcopy -#class TMSSPermissionsMixin: - - # def __init__(self, *args, **kwargs): - # self.permission_classes = (TMSSPermissions,) - # self.filter_backends = (IsProjectMemberFilterBackend,) - # self.extra_action_permission_classes = self._create_extra_action_permission_classes() - # super(TMSSPermissionsMixin, self).__init__(*args, **kwargs) - # - # # TODO: Cache this method to avoid redundancy and overhead. - # def _create_extra_action_permission_classes(self): - # extra_action_permission_classes = [] - # extra_actions = [a.__name__ for a in self.get_extra_actions()] - # for ea in extra_actions: # Create permission classes - # permission_name = f'{ea}_{self.serializer_class.Meta.model.__name__.lower()}' - # permission_class_name = f'Can {ea} {self.serializer_class.Meta.model.__name__.lower()}' - # new_permission_class = type(f'{permission_class_name}', (permissions.TMSSBasePermissions,), { - # # TODO: Is it necessary to have both permissions and object permissions? - # # TODO: Find a way to use the "%(app_label)s." syntax. - # 'permission_name': permission_name, - # 'has_permission': lambda self, request, view: request.user.has_perm(f'tmssapp.{self.permission_name}'), - # 'has_object_permission': lambda self, request, view, obj: request.user.has_perm(f'tmssapp.{self.permission_name}'), - # }) - # new_permission_class.__setattr__(self, 'permission_name', permission_name) - # extra_action_permission_classes.append({ea: new_permission_class},) - # return extra_action_permission_classes - # - # # TODO: Refactoring. - # def get_model_permissions(self): - # extra_actions = [a.__name__ for a in self.get_extra_actions()] - # if self.action in extra_actions: - # for ea_permission_class in self.extra_action_permission_classes: - # if ea_permission_class.get(self.action): - # return [permissions.TMSSBasePermissions, ea_permission_class.get(self.action),] - # else: - # return [permissions.TMSSBasePermissions,] - # else: - # return [permissions.TMSSBasePermissions, ] - - #def get_permissions(self): - # self.get_extra_action_permission_classes() - # return super(TMSSPermissionsMixin, self).get_permissions() +class LOFARDefaultFilterSet(FilterSet): + FILTER_DEFAULTS = deepcopy(filterset.FILTER_FOR_DBFIELD_DEFAULTS) + FILTER_DEFAULTS.update({ + JSONField: { + 'filter_class': CharFilter + }, + ArrayField: { + 'filter_class': CharFilter, + 'extra': lambda f: {'lookup_expr': 'icontains'} + }, + }) + + +class LOFARFilterBackend(DjangoFilterBackend): + default_filter_set = LOFARDefaultFilterSet class LOFARViewSet(viewsets.ModelViewSet): @@ -71,7 +48,8 @@ class LOFARViewSet(viewsets.ModelViewSet): the `format=None` keyword argument for each action. """ permission_classes = (TMSSPermissions,) - filter_backends = (DjangoFilterBackend, OrderingFilter, IsProjectMemberFilterBackend,) + filter_backends = (LOFARFilterBackend, OrderingFilter, IsProjectMemberFilterBackend,) + filter_fields = '__all__' @swagger_auto_schema(responses={403: 'forbidden'}) def list(self, request, **kwargs): diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py index 620742eaa77..f5e8f1d554b 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py @@ -19,7 +19,7 @@ from rest_framework.decorators import action from drf_yasg.utils import swagger_auto_schema from drf_yasg.openapi import Parameter -from lofar.sas.tmss.tmss.tmssapp.viewsets.lofar_viewset import LOFARViewSet, LOFARNestedViewSet, AbstractTemplateViewSet, LOFARCopyViewSet +from lofar.sas.tmss.tmss.tmssapp.viewsets.lofar_viewset import LOFARViewSet, LOFARNestedViewSet, AbstractTemplateViewSet, LOFARCopyViewSet, LOFARFilterBackend from lofar.sas.tmss.tmss.tmssapp import models from lofar.sas.tmss.tmss.tmssapp import serializers from django.http import JsonResponse @@ -32,7 +32,6 @@ from lofar.sas.tmss.tmss.tmssapp.subtasks import * from lofar.sas.tmss.tmss.tmssapp.viewsets.permissions import TMSSDjangoModelPermissions from django.urls import resolve, get_script_prefix,Resolver404 -from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter import json @@ -312,7 +311,7 @@ class TaskConnectorTypeViewSet(LOFARViewSet): class CycleViewSet(LOFARViewSet): permission_classes = (TMSSDjangoModelPermissions,) # override default project permission - filter_backends = (DjangoFilterBackend, OrderingFilter) # override default project permission + filter_backends = (LOFARFilterBackend, OrderingFilter) # override default project permission queryset = models.Cycle.objects.all() serializer_class = serializers.CycleSerializer ordering = ['start'] @@ -431,13 +430,22 @@ class SchedulingUnitDraftPropertyFilter(property_filters.PropertyFilterSet): class Meta: model = models.SchedulingUnitDraft - fields = ['project'] + fields = '__all__' + filter_overrides = { + models.JSONField: { + 'filter_class': property_filters.CharFilter, + }, + models.ArrayField: { + 'filter_class': property_filters.CharFilter, + 'extra': lambda f: {'lookup_expr': 'icontains'} + }, + } class SchedulingUnitDraftViewSet(LOFARViewSet): queryset = models.SchedulingUnitDraft.objects.all() serializer_class = serializers.SchedulingUnitDraftSerializer - filter_class = SchedulingUnitDraftPropertyFilter + filter_class = SchedulingUnitDraftPropertyFilter # note that this breaks other filter backends from LOFARViewSet # prefetch all reverse related references from other models on their related_name to avoid a ton of duplicate queries queryset = queryset.prefetch_related('copied_from') \ @@ -733,13 +741,22 @@ class SchedulingUnitBlueprintPropertyFilter(property_filters.PropertyFilterSet): class Meta: model = models.SchedulingUnitBlueprint - fields = ['start_time', 'stop_time', 'project'] + fields = '__all__' + filter_overrides = { + models.JSONField: { + 'filter_class': property_filters.CharFilter, + }, + models.ArrayField: { + 'filter_class': property_filters.CharFilter, + 'extra': lambda f: {'lookup_expr': 'icontains'} + }, + } class SchedulingUnitBlueprintViewSet(LOFARViewSet): queryset = models.SchedulingUnitBlueprint.objects.all() serializer_class = serializers.SchedulingUnitBlueprintSerializer - filter_class = SchedulingUnitBlueprintPropertyFilter + filter_class = SchedulingUnitBlueprintPropertyFilter # note that this breaks other filter backends from LOFARViewSet # prefetch all reverse related references from other models on their related_name to avoid a ton of duplicate queries queryset = queryset.prefetch_related('task_blueprints') -- GitLab