]> git.ipfire.org Git - thirdparty/patchwork.git/commitdiff
api: allow filtering patches and covers by msgid
authorDaniel Axtens <dja@axtens.net>
Tue, 14 Apr 2020 05:34:40 +0000 (15:34 +1000)
committerDaniel Axtens <dja@axtens.net>
Tue, 14 Apr 2020 13:27:17 +0000 (23:27 +1000)
In the process of fixing the previous bug, I realised that:

 a) /api/patches/msgid is a perfectly reasonable thing to attempt
 b) We have no way of finding a patch by message id in the API

We can't actualy make /api/patches/msgid work because it may not
be unique, but we can add a filter.

I'm shoehorning this into stable/2.2, even though it's technically
an API change: it's minor, not incompatible and in hindsight a
glaring hole.

Cc: Michael Ellerman <mpe@ellerman.id.au>
Tested-by: Jeremy Kerr <jk@ozlabs.org>
Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com>
Reviewed-by: Stephen Finucane <stephen@that.guru>
Signed-off-by: Daniel Axtens <dja@axtens.net>
docs/api/schemas/latest/patchwork.yaml
docs/api/schemas/patchwork.j2
docs/api/schemas/v1.2/patchwork.yaml
patchwork/api/filters.py
patchwork/tests/api/test_cover.py
patchwork/tests/api/test_patch.py
releasenotes/notes/rest-filter-msgid-41f693cd4e53cf93.yaml [new file with mode: 0644]

index 13cdc9cd78fd5c5c42ad034bcadaa344ca8b3606..cc0d97e696b655f7c27b3034c5d52e8e57ee5361 100644 (file)
@@ -246,6 +246,14 @@ paths:
           schema:
             title: ''
             type: string
+        - in: query
+          name: msgid
+          description: >
+            The cover message-id as a case-sensitive string, without leading or
+            trailing angle brackets, to filter by.
+          schema:
+            title: ''
+            type: string
       responses:
         '200':
           description: ''
@@ -474,6 +482,14 @@ paths:
           schema:
             title: ''
             type: string
+        - in: query
+          name: msgid
+          description: >
+            The patch message-id as a case-sensitive string, without leading or
+            trailing angle brackets, to filter by.
+          schema:
+            title: ''
+            type: string
       responses:
         '200':
           description: ''
index bd714d5e7a2acb00895809c0635a15030a44a9dd..f5618d41faa05f6a0d6373e92c116c29dc1dc939 100644 (file)
@@ -251,6 +251,16 @@ paths:
           schema:
             title: ''
             type: string
+{% if version >= (1, 2) %}
+        - in: query
+          name: msgid
+          description: >
+            The cover message-id as a case-sensitive string, without leading or
+            trailing angle brackets, to filter by.
+          schema:
+            title: ''
+            type: string
+{% endif %}
       responses:
         '200':
           description: ''
@@ -488,6 +498,14 @@ paths:
           schema:
             title: ''
             type: string
+        - in: query
+          name: msgid
+          description: >
+            The patch message-id as a case-sensitive string, without leading or
+            trailing angle brackets, to filter by.
+          schema:
+            title: ''
+            type: string
 {% endif %}
       responses:
         '200':
index db2ed122eec2ac52c46422b0c71c20252119e790..7bdbe66997c01d392cea57039074f8443c6f3df4 100644 (file)
@@ -246,6 +246,14 @@ paths:
           schema:
             title: ''
             type: string
+        - in: query
+          name: msgid
+          description: >
+            The cover message-id as a case-sensitive string, without leading or
+            trailing angle brackets, to filter by.
+          schema:
+            title: ''
+            type: string
       responses:
         '200':
           description: ''
@@ -474,6 +482,14 @@ paths:
           schema:
             title: ''
             type: string
+        - in: query
+          name: msgid
+          description: >
+            The patch message-id as a case-sensitive string, without leading or
+            trailing angle brackets, to filter by.
+          schema:
+            title: ''
+            type: string
       responses:
         '200':
           description: ''
index deb5ace11880893f6f161a96e21fbb96e66ffade..93e6281bf5e66141208afb21f40cc0f542eeb5c6 100644 (file)
@@ -184,6 +184,10 @@ class SeriesFilterSet(TimestampMixin, BaseFilterSet):
         fields = ('submitter', 'project')
 
 
+def msgid_filter(queryset, name, value):
+    return queryset.filter(**{name: '<' + value + '>'})
+
+
 class CoverLetterFilterSet(TimestampMixin, BaseFilterSet):
 
     project = ProjectFilter(queryset=Project.objects.all(), distinct=False)
@@ -192,6 +196,7 @@ class CoverLetterFilterSet(TimestampMixin, BaseFilterSet):
     series = BaseFilter(queryset=Project.objects.all(),
                         widget=MultipleHiddenInput, distinct=False)
     submitter = PersonFilter(queryset=Person.objects.all(), distinct=False)
+    msgid = CharFilter(method=msgid_filter)
 
     class Meta:
         model = CoverLetter
@@ -210,17 +215,18 @@ class PatchFilterSet(TimestampMixin, BaseFilterSet):
     delegate = UserFilter(queryset=User.objects.all(), distinct=False)
     state = StateFilter(queryset=State.objects.all(), distinct=False)
     hash = CharFilter(lookup_expr='iexact')
+    msgid = CharFilter(method=msgid_filter)
 
     class Meta:
         model = Patch
-        # NOTE(dja): ideally we want to version the hash field, but I cannot
-        # find a way to do that which is reliable and not extremely ugly.
+        # NOTE(dja): ideally we want to version the hash/msgid field, but I
+        # can't find a way to do that which is reliable and not extremely ugly.
         # The best I can come up with is manually working with request.GET
         # which seems to rather defeat the point of using django-filters.
         fields = ('project', 'series', 'submitter', 'delegate',
-                  'state', 'archived', 'hash')
+                  'state', 'archived', 'hash', 'msgid')
         versioned_fields = {
-            '1.2': ('hash', ),
+            '1.2': ('hash', 'msgid'),
         }
 
 
index 5eeb1902e1d17cc0cc7e2718db6e07e65136d20a..1b19ded1b4d51d138d1f256ca6e42eff11b1cdb6 100644 (file)
@@ -111,6 +111,18 @@ class TestCoverLetterAPI(utils.APITestCase):
             'submitter': 'test@example.org'})
         self.assertEqual(0, len(resp.data))
 
+    def test_list_filter_msgid(self):
+        """Filter covers by msgid."""
+        cover = create_cover()
+
+        resp = self.client.get(self.api_url(), {'msgid': cover.url_msgid})
+        self.assertEqual([cover.id], [x['id'] for x in resp.data])
+
+        # empty response if nothing matches
+        resp = self.client.get(self.api_url(), {
+            'msgid': 'fishfish@fish.fish'})
+        self.assertEqual(0, len(resp.data))
+
     @utils.store_samples('cover-list-1-0')
     def test_list_version_1_0(self):
         create_cover()
index b24c5ab28947bf562070aa90d9260fb3aaf6e141..da2dd6e9084b6ccfe509d1e1011307edace6fe84 100644 (file)
@@ -199,6 +199,18 @@ class TestPatchAPI(utils.APITestCase):
                                {'hash': 'garbagevalue'})
         self.assertEqual(1, len(resp.data))
 
+    def test_list_filter_msgid(self):
+        """Filter patches by msgid."""
+        patch = self._create_patch()
+
+        resp = self.client.get(self.api_url(), {'msgid': patch.url_msgid})
+        self.assertEqual([patch.id], [x['id'] for x in resp.data])
+
+        # empty response if nothing matches
+        resp = self.client.get(self.api_url(), {
+            'msgid': 'fishfish@fish.fish'})
+        self.assertEqual(0, len(resp.data))
+
     @utils.store_samples('patch-list-1-0')
     def test_list_version_1_0(self):
         """List patches using API v1.0."""
diff --git a/releasenotes/notes/rest-filter-msgid-41f693cd4e53cf93.yaml b/releasenotes/notes/rest-filter-msgid-41f693cd4e53cf93.yaml
new file mode 100644 (file)
index 0000000..0fcbbeb
--- /dev/null
@@ -0,0 +1,6 @@
+---
+api:
+  - |
+    The REST API now supports filtering patches and cover letters by message
+    ID, using the ``msgid`` query parameter. Don't include leading or trailing
+    angle brackets.