[PATCH 3/4] REST: Allow filtering of submitters by email
Stephen Finucane
stephen at that.guru
Mon Dec 11 04:30:34 AEDT 2017
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 at that.guru>
---
patchwork/api/filters.py | 39 ++++++++++++++++++---
patchwork/tests/test_rest_api.py | 40 ++++++++++++++++++++--
.../improved-rest-filtering-bf68399270a9b245.yaml | 9 +++++
3 files changed, 80 insertions(+), 8 deletions(-)
create mode 100644 releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml
diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py
index 198d64f4..c34f5496 100644
--- a/patchwork/api/filters.py
+++ b/patchwork/api/filters.py
@@ -29,6 +29,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
@@ -41,16 +42,16 @@ class TimestampMixin(FilterSet):
since = IsoDateTimeFilter(name='date', **{LOOKUP_FIELD: '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)
@@ -60,6 +61,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
@@ -71,8 +81,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')
@@ -80,6 +106,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')
@@ -113,6 +141,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
diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py
index 87112d9f..7d10f909 100644
--- a/patchwork/tests/test_rest_api.py
+++ b/patchwork/tests/test_rest_api.py
@@ -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 at 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 at example.com'})
+ self.assertEqual([patch_obj.id], [x['id'] for x in resp.data])
+ resp = self.client.get(self.api_url(), {
+ 'submitter': 'test at 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 at 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 at example.com'})
+ self.assertEqual([cover_obj.id], [x['id'] for x in resp.data])
+ resp = self.client.get(self.api_url(), {
+ 'submitter': 'test at 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 at 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 at example.com'})
+ self.assertEqual([series_obj.id], [x['id'] for x in resp.data])
+ resp = self.client.get(self.api_url(), {
+ 'submitter': 'test at 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
index 00000000..fda68790
--- /dev/null
+++ b/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml
@@ -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 at that.guru
--
2.14.3
More information about the Patchwork
mailing list