]> git.ipfire.org Git - thirdparty/patchwork.git/commitdiff
REST: Allow filtering of submitters by email
authorStephen Finucane <stephen@that.guru>
Sun, 10 Dec 2017 17:30:34 +0000 (17:30 +0000)
committerStephen Finucane <stephen@that.guru>
Tue, 9 Jan 2018 23:45:52 +0000 (23:45 +0000)
This means we don't need to make a request to '/people' to filter things
like patches or series.

Signed-off-by: Stephen Finucane <stephen@that.guru>
patchwork/api/filters.py
patchwork/tests/test_rest_api.py
releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml [new file with mode: 0644]

index 15dff5fd58fc8cc5c4879f20ac0fc63c8dc427e0..fd33e017c369c5a67a0f816722e2f548b1b09b66 100644 (file)
@@ -28,6 +28,7 @@ from patchwork.models import Check
 from patchwork.models import CoverLetter
 from patchwork.models import Event
 from patchwork.models import Patch
+from patchwork.models import Person
 from patchwork.models import Project
 from patchwork.models import Series
 from patchwork.models import State
@@ -40,16 +41,16 @@ class TimestampMixin(FilterSet):
     since = IsoDateTimeFilter(name='date', lookup_expr='gte')
 
 
-class ProjectChoiceField(ModelChoiceField):
+class ModelMultiChoiceField(ModelChoiceField):
+
+    def _get_filters(self, value):
+        raise NotImplementedError
 
     def to_python(self, value):
         if value in self.empty_values:
             return None
 
-        try:
-            filters = {'pk': int(value)}
-        except ValueError:
-            filters = {'linkname__iexact': value}
+        filters = self._get_filters(value)
 
         try:
             value = self.queryset.get(**filters)
@@ -59,6 +60,15 @@ class ProjectChoiceField(ModelChoiceField):
         return value
 
 
+class ProjectChoiceField(ModelMultiChoiceField):
+
+    def _get_filters(self, value):
+        try:
+            return {'pk': int(value)}
+        except ValueError:
+            return {'linkname__iexact': value}
+
+
 class ProjectFilter(ModelChoiceFilter):
 
     field_class = ProjectChoiceField
@@ -70,8 +80,24 @@ class ProjectMixin(FilterSet):
                             queryset=Project.objects.all())
 
 
+class PersonChoiceField(ModelMultiChoiceField):
+
+    def _get_filters(self, value):
+        try:
+            return {'pk': int(value)}
+        except ValueError:
+            return {'email__iexact': value}
+
+
+class PersonFilter(ModelChoiceFilter):
+
+    field_class = PersonChoiceField
+
+
 class SeriesFilter(ProjectMixin, TimestampMixin, FilterSet):
 
+    submitter = PersonFilter(queryset=Person.objects.all())
+
     class Meta:
         model = Series
         fields = ('submitter', 'project')
@@ -79,6 +105,8 @@ class SeriesFilter(ProjectMixin, TimestampMixin, FilterSet):
 
 class CoverLetterFilter(ProjectMixin, TimestampMixin, FilterSet):
 
+    submitter = PersonFilter(queryset=Person.objects.all())
+
     class Meta:
         model = CoverLetter
         fields = ('project', 'series', 'submitter')
@@ -112,6 +140,7 @@ class StateFilter(ModelChoiceFilter):
 class PatchFilter(ProjectMixin, TimestampMixin, FilterSet):
 
     state = StateFilter(queryset=State.objects.all())
+    submitter = PersonFilter(queryset=Person.objects.all())
 
     class Meta:
         model = Patch
index 87112d9f2df64d889c2b2320b5e772cf08349e01..7d10f909716fe593e0af0f1ff9d832ef778f94a8 100644 (file)
@@ -341,9 +341,11 @@ class TestPatchAPI(APITestCase):
         self.assertEqual(status.HTTP_200_OK, resp.status_code)
         self.assertEqual(0, len(resp.data))
 
+        person_obj = create_person(email='test@example.com')
         state_obj = create_state(name='Under Review')
         project_obj = create_project(linkname='myproject')
-        patch_obj = create_patch(state=state_obj, project=project_obj)
+        patch_obj = create_patch(state=state_obj, project=project_obj,
+                                 submitter=person_obj)
 
         # anonymous user
         resp = self.client.get(self.api_url())
@@ -376,6 +378,16 @@ class TestPatchAPI(APITestCase):
         resp = self.client.get(self.api_url(), {'project': 'invalidproject'})
         self.assertEqual(0, len(resp.data))
 
+        # test filtering by submitter, both ID and email
+        resp = self.client.get(self.api_url(), {'submitter': person_obj.id})
+        self.assertEqual([patch_obj.id], [x['id'] for x in resp.data])
+        resp = self.client.get(self.api_url(), {
+            'submitter': 'test@example.com'})
+        self.assertEqual([patch_obj.id], [x['id'] for x in resp.data])
+        resp = self.client.get(self.api_url(), {
+            'submitter': 'test@example.org'})
+        self.assertEqual(0, len(resp.data))
+
     def test_detail(self):
         """Validate we can get a specific patch."""
         patch = create_patch(
@@ -493,8 +505,9 @@ class TestCoverLetterAPI(APITestCase):
         self.assertEqual(status.HTTP_200_OK, resp.status_code)
         self.assertEqual(0, len(resp.data))
 
+        person_obj = create_person(email='test@example.com')
         project_obj = create_project(linkname='myproject')
-        cover_obj = create_cover(project=project_obj)
+        cover_obj = create_cover(project=project_obj, submitter=person_obj)
 
         # anonymous user
         resp = self.client.get(self.api_url())
@@ -516,6 +529,16 @@ class TestCoverLetterAPI(APITestCase):
         resp = self.client.get(self.api_url(), {'project': 'invalidproject'})
         self.assertEqual(0, len(resp.data))
 
+        # test filtering by submitter, both ID and email
+        resp = self.client.get(self.api_url(), {'submitter': person_obj.id})
+        self.assertEqual([cover_obj.id], [x['id'] for x in resp.data])
+        resp = self.client.get(self.api_url(), {
+            'submitter': 'test@example.com'})
+        self.assertEqual([cover_obj.id], [x['id'] for x in resp.data])
+        resp = self.client.get(self.api_url(), {
+            'submitter': 'test@example.org'})
+        self.assertEqual(0, len(resp.data))
+
     def test_detail(self):
         """Validate we can get a specific cover letter."""
         cover_obj = create_cover()
@@ -574,8 +597,9 @@ class TestSeriesAPI(APITestCase):
         self.assertEqual(status.HTTP_200_OK, resp.status_code)
         self.assertEqual(0, len(resp.data))
 
+        person_obj = create_person(email='test@example.com')
         project_obj = create_project(linkname='myproject')
-        series_obj = create_series(project=project_obj)
+        series_obj = create_series(project=project_obj, submitter=person_obj)
 
         # anonymous user
         resp = self.client.get(self.api_url())
@@ -597,6 +621,16 @@ class TestSeriesAPI(APITestCase):
         resp = self.client.get(self.api_url(), {'project': 'invalidproject'})
         self.assertEqual(0, len(resp.data))
 
+        # test filtering by submitter, both ID and email
+        resp = self.client.get(self.api_url(), {'submitter': person_obj.id})
+        self.assertEqual([series_obj.id], [x['id'] for x in resp.data])
+        resp = self.client.get(self.api_url(), {
+            'submitter': 'test@example.com'})
+        self.assertEqual([series_obj.id], [x['id'] for x in resp.data])
+        resp = self.client.get(self.api_url(), {
+            'submitter': 'test@example.org'})
+        self.assertEqual(0, len(resp.data))
+
     def test_detail(self):
         """Validate we can get a specific series."""
         series = create_series()
diff --git a/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml b/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml
new file mode 100644 (file)
index 0000000..fda6879
--- /dev/null
@@ -0,0 +1,9 @@
+---
+api:
+  - |
+    Series, patches and cover letters can be filtered by submitter using email
+    addresses. For example:
+
+    .. code-block:: shell
+
+       $ curl /covers/?submitter=stephen@that.guru