From b1bdd6d9bee3a545e7f65e39ffbf2fa84f241b11 Mon Sep 17 00:00:00 2001 From: Keoni Mahelona Date: Thu, 9 Jan 2025 05:54:53 +1300 Subject: [PATCH] feat(api): added filters on genre & md5 for files api (#3127) ### Description Added filters for genre and md5 to the files API, e.g. `/api/v2/files?genre=soul` **This is a new feature**: Yes **I have updated the documentation to reflect these changes**: No There should be a schema and docs that are generated automatically. I don't know where that is. ### Testing Notes **What I did:** - Used docker to deploy locally - Confirmed filters work at http://localhost:8080/api/v2/files?genre=Soul **How you can replicate my testing:** - `make clean dev` - Upload some files! - Visit http://localhost:8080/api/v2/files - You can use the filters Screenshot 2024-12-23 at 01 36 01 Screenshot 2024-12-23 at 01 35 56 _How can the reviewer validate this PR?_ - See above - wrote tests to confirm filters work --- .../storage/tests/views/test_file.py | 33 +++++++++++++++++++ api/libretime_api/storage/views/file.py | 3 ++ api/schema.yml | 9 +++++ 3 files changed, 45 insertions(+) diff --git a/api/libretime_api/storage/tests/views/test_file.py b/api/libretime_api/storage/tests/views/test_file.py index ebe99f8f8..4a62c9801 100644 --- a/api/libretime_api/storage/tests/views/test_file.py +++ b/api/libretime_api/storage/tests/views/test_file.py @@ -61,3 +61,36 @@ class TestFileViewSet(APITestCase): file_id = "1" response = self.client.delete(f"/api/v2/files/{file_id}") self.assertEqual(response.status_code, 404) + + def test_filters(self): + file = baker.make( + "storage.File", + mime="audio/mp3", + filepath=AUDIO_FILENAME, + genre="Soul", + md5="5a11ffe0e6c6d70fcdbad1b734be6482", + ) + baker.make( + "storage.File", + mime="audio/mp3", + filepath=AUDIO_FILENAME, + genre="R&B", + md5="5a11ffe0e6c6d70fcdbad1b734be6483", + ) + self.client.credentials(HTTP_AUTHORIZATION=f"Api-Key {self.token}") + + path = "/api/v2/files" + results = self.client.get(path).json() + self.assertEqual(len(results), 2) + + path = f"/api/v2/files?md5={file.md5}" + results = self.client.get(path).json() + self.assertEqual(len(results), 1) + + path = "/api/v2/files?genre=Soul" + results = self.client.get(path).json() + self.assertEqual(len(results), 1) + + path = "/api/v2/files?genre=R%26B" + results = self.client.get(path).json() + self.assertEqual(len(results), 1) diff --git a/api/libretime_api/storage/views/file.py b/api/libretime_api/storage/views/file.py index 8565fbbc0..35176d4ba 100644 --- a/api/libretime_api/storage/views/file.py +++ b/api/libretime_api/storage/views/file.py @@ -5,6 +5,7 @@ from os import remove from django.conf import settings from django.http import HttpResponse from django.utils.encoding import filepath_to_uri +from django_filters import rest_framework as filters from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.exceptions import APIException @@ -26,6 +27,8 @@ class FileViewSet(viewsets.ModelViewSet): queryset = File.objects.all() serializer_class = FileSerializer model_permission_name = "file" + filter_backends = (filters.DjangoFilterBackend,) + filterset_fields = ("md5", "genre") # pylint: disable=invalid-name,unused-argument @action(detail=True, methods=["GET"]) diff --git a/api/schema.yml b/api/schema.yml index 9962bf882..07ffd06fe 100644 --- a/api/schema.yml +++ b/api/schema.yml @@ -154,6 +154,15 @@ paths: /api/v2/files: get: operationId: files_list + parameters: + - in: query + name: genre + schema: + type: string + - in: query + name: md5 + schema: + type: string tags: - files security: