From: Stephen Finucane Date: Sun, 10 Dec 2017 17:30:34 +0000 (+0000) Subject: REST: Allow filtering of submitters by email X-Git-Tag: v2.1.0-rc1~88 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bf5cdd34baca3c397ab6e012cb212dedbefca450;p=thirdparty%2Fpatchwork.git REST: Allow filtering of submitters by email This means we don't need to make a request to '/people' to filter things like patches or series. Signed-off-by: Stephen Finucane --- diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index 15dff5fd..fd33e017 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -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 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@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 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@that.guru