From 7eaa0a493216ab0aa384cae8e2d27c5f0fbdead4 Mon Sep 17 00:00:00 2001
From: Konrad Mohrfeldt <konrad.mohrfeldt@farbdev.org>
Date: Thu, 17 Mar 2022 13:32:25 +0100
Subject: [PATCH] refactor: use django_filters FilterSet for APINoteViewSet

This change re-implements all existing collection filters for the
APINoteViewSet with a FilterSet. No breaking changes are expected.
---
 program/filters.py | 26 ++++++++++++++++
 program/views.py   | 78 ++++++++--------------------------------------
 2 files changed, 39 insertions(+), 65 deletions(-)

diff --git a/program/filters.py b/program/filters.py
index 9be299df..e05e58d7 100644
--- a/program/filters.py
+++ b/program/filters.py
@@ -201,6 +201,32 @@ class TimeSlotFilterSet(filters.FilterSet):
                 return end or self.cleaned_data["start"] + datetime.timedelta(days=60)
 
 
+class NoteFilterSet(StaticFilterHelpTextMixin, filters.FilterSet):
+    ids = ModelMultipleChoiceFilter(
+        field_name="id",
+        queryset=models.Note.objects.all(),
+        help_text="Return only notes matching the specified id(s).",
+    )
+    owner = ModelMultipleChoiceFilter(
+        field_name="show__owners",
+        queryset=models.User.objects.all(),
+        help_text="Return only notes by show the specified owner(s): all notes the user may edit.",
+    )
+
+    class Meta:
+        model = models.Note
+        help_texts = {
+            "host": "Return only notes from the specified host.",
+            "user": "Return only notes created by the specified user.",
+        }
+        fields = [
+            "host",
+            "ids",
+            "owner",
+            "user",
+        ]
+
+
 class ActiveFilterSet(StaticFilterHelpTextMixin, filters.FilterSet):
     active = filters.BooleanFilter(field_name="is_active")
 
diff --git a/program/views.py b/program/views.py
index 2ef6198a..51f95b55 100644
--- a/program/views.py
+++ b/program/views.py
@@ -617,80 +617,28 @@ class APITimeSlotViewSet(
 
 class APINoteViewSet(viewsets.ModelViewSet):
     """
-    /notes/ returns all notes (GET)
-    /notes/{pk} returns a single note (if owned) (GET)
-    /notes/?ids={...} returns given notes (if owned) (GET)
-    /notes/?host={host} returns notes assigned to a given host (GET)
-    /notes/?owner={owner} returns notes editable by a given user (GET)
-    /notes/?user={user} returns notes created by a given user (GET)
-    /shows/{show_pk}/notes returns all notes of a show (GET)
-    /shows/{show_pk}/notes/{pk} returns a note by its ID (GET)
-    /shows/{show_pk}/timeslots/{timeslot_pk}/note/ returns a note of the timeslot (GET)
-    /shows/{show_pk}/timeslots/{timeslot_pk}/note/{pk} returns a note by its ID (GET)
-    /shows/{show_pk}/schedules/{schedule_pk}/timeslots/{timeslot_pk}/note returns a note to the
-     timeslot (GET, POST).
-    /shows/{show_pk}/schedules/{schedule_pk}/timeslots/{timeslot_pk}/note/{pk} returns a note by
-     its ID (GET, PUT, DELETE)
-
-    Superusers may access and update all notes
+    Returns a list of notes.
+
+    Superusers may access and update all notes.
     """
 
-    queryset = Note.objects.none()
+    queryset = Note.objects.all()
     serializer_class = NoteSerializer
     permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]
     pagination_class = LimitOffsetPagination
+    filter_class = filters.NoteFilterSet
 
     def get_queryset(self):
-        timeslot_pk, show_pk = get_values(self.kwargs, "timeslot_pk", "show_pk")
-
-        # Endpoints
-
-        #
-        #     /shows/1/schedules/1/timeslots/1/note
-        #     /shows/1/timeslots/1/note
-        #
-        #     Return a note to the timeslot
-        #
-        if show_pk and timeslot_pk:
-            notes = Note.objects.filter(show=show_pk, timeslot=timeslot_pk)
-
-        #
-        #     /shows/1/notes
-        #
-        #     Returns notes to the show
-        #
-        elif show_pk and timeslot_pk is None:
-            notes = Note.objects.filter(show=show_pk)
-
-        #
-        #     /notes
-        #
-        #     Returns all notes
-        #
-        else:
-            notes = Note.objects.all()
-
-        # Filters
-
-        if ids := self.request.query_params.get("ids"):
-            # Filter notes by their IDs
-            note_ids = list(map(int, ids.split(",")))
-            notes = notes.filter(id__in=note_ids)
-
-        if host := self.request.query_params.get("host"):
-            # Filter notes by host
-            notes = notes.filter(host=int(host))
-
-        if owner := self.request.query_params.get("owner"):
-            # Filter notes by show owner: all notes the user may edit
-            shows = Show.objects.filter(owners=int(owner))
-            notes = notes.filter(show__in=shows)
+        queryset = super().get_queryset()
 
-        if user := self.request.query_params.get("user"):
-            # Filter notes by their creator
-            notes = notes.filter(user=int(user))
+        # subroute filters
+        show_pk, timeslot_pk = get_values(self.kwargs, "show_pk", "timeslot_pk")
+        if show_pk:
+            queryset = queryset.filter(show=show_pk)
+        if timeslot_pk:
+            queryset = queryset.filter(timeslot=timeslot_pk)
 
-        return notes
+        return queryset
 
     def create(self, request, *args, **kwargs):
         """Create a note"""
-- 
GitLab