Commit ade37eea authored by Arkadiusz Hiler's avatar Arkadiusz Hiler

API: Make msg-id lookup endpoint consistent with others

 * Use django-rest-framework views for nice browser previews
 * Add pretended pagination for consistency with other list endpoints
 * Extra: remove accidental print
Signed-off-by: Arkadiusz Hiler's avatarArkadiusz Hiler <arkadiusz.hiler@intel.com>
parent 9b042b14
Pipeline #13952 passed with stage
in 10 minutes and 31 seconds
......@@ -780,9 +780,62 @@ Patches
$ curl -s http://patchwork.example.com/api/1.0/patches/42/mbox/ | git am -3
Message-Id Lookup
~~~~~~~~~~~~~~~~~
.. http:get:: /api/1.0/msgids/(string: msgid)/
List series containing patches/cover letter with given Message-Id. If the
Message-Id resolves to a patch (instead of a cover letter) the ``patch_id``
of that patch is also provided. Additionaly ``project_id`` of the series and
list of revisions containing the patch/cover letter are always provided.
``msgid`` can be supplied either with or without less-than and greater-than
sings, i.e. both ``<msg@id>`` and ``msg@id`` are accepted.
This endpoint is never paginated.
.. sourcecode:: http
GET /api/1.0/msgids/<msg@id>/ HTTP/1.1
Accept: application/json
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
Vary: Accept
Allow: GET, HEAD, OPTIONS
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"patch_id": 112227,
"project_id": 9,
"series_id": 12938,
"revision_ids": [ 1 ]
},
{
"patch_id": 112229,
"project_id": 18,
"series_id": 12937,
"revision_ids": [ 1 ]
}
]
}
API Revisions
-------------
**Revision 4**
- Add Msg-Id Lookup entry point:
- /api/1.0/msgids/${msgid}/
**Revision 3**
- Add test results entry points:
......
......@@ -466,12 +466,13 @@ class MsgidsLookupTest(APITestBase):
def testSingleSeriesSingleRevisionLookup(self):
response = self.get_json(self.msgid_url.format(self.patch.msgid))
results = response['results']
self.assertEquals(len(response), 1) # just one matching patch
self.assertEquals(response[0]['patch_id'], self.patch.id)
self.assertEquals(response[0]['project_id'], self.patch.project_id)
self.assertEquals(response[0]['series_id'], self.patch.series().id)
self.assertEquals(response[0]['revision_ids'], [self.revision.version])
self.assertEquals(response['count'], 1) # just one matching patch
self.assertEquals(results[0]['patch_id'], self.patch.id)
self.assertEquals(results[0]['project_id'], self.patch.project_id)
self.assertEquals(results[0]['series_id'], self.patch.series().id)
self.assertEquals(results[0]['revision_ids'], [self.revision.version])
def testUnbracketedLookup(self):
msgid = self.patch.msgid
......@@ -482,16 +483,17 @@ class MsgidsLookupTest(APITestBase):
response1 = self.get_json(self.msgid_url.format(msgid))
response2 = self.get_json(self.msgid_url.format(stripped_msgid))
self.assertTrue(len(response1) != 0)
self.assertTrue(response1['count'] != 0)
self.assertEquals(response1, response2)
def testSingleSeriesMultipleRevisionsLookup(self):
rev2 = self.revision.duplicate()
response = self.get_json(self.msgid_url.format(self.patch.msgid))
results = response['results']
self.assertEquals(len(response), 1) # just one matching patch
self.assertEquals(response[0]['revision_ids'], # multiple revs
self.assertEquals(response['count'], 1) # just one matching patch
self.assertEquals(results[0]['revision_ids'], # multiple revs
[self.revision.version, rev2.version])
def testMulitpleSeriesSingleRevisionsLookup(self):
......@@ -508,16 +510,17 @@ class MsgidsLookupTest(APITestBase):
response = self.get_json(self.msgid_url.format(self.patch.msgid))
self.assertEquals(len(response), 2)
self.assertEquals(response['count'], 2)
def testCoverLetterLookup(self):
response = self.get_json(self.msgid_url.format(self.root_msgid))
results = response['results']
self.assertEquals(len(response), 1)
self.assertTrue('patch_id' not in response[0].keys())
self.assertEquals(response[0]['project_id'], self.series.project_id)
self.assertEquals(response[0]['series_id'], self.series.id)
self.assertEquals(response[0]['revision_ids'], [self.revision.version])
self.assertEquals(response['count'], 1)
self.assertTrue('patch_id' not in results[0].keys())
self.assertEquals(results[0]['project_id'], self.series.project_id)
self.assertEquals(results[0]['series_id'], self.series.id)
self.assertEquals(results[0]['revision_ids'], [self.revision.version])
class TestResultTest(APITestBase):
......
......@@ -835,7 +835,6 @@ class SeriesRevisionTest(GeneratedSeriesTest):
dup = org.duplicate_meta()
print(dup.pk)
self.assertTrue(dup.test_state is None)
self.assertNotEqual(dup.pk, org.pk)
......
......@@ -89,8 +89,8 @@ urlpatterns = [
url(r'^api/1.0/', include(patches_router.urls)),
url(r'^api/1.0/', include(patch_results_router.urls)),
url(r'^api/1.0/', include(event_router.urls)),
url(r'^api/1.0/msgids/(?P<msgid>[^/]+)/$', api.msgid,
name='msgid_to_patches'),
url(r'^api/1.0/msgids/(?P<msgid>[^/]+)/$', api.MsgidResultsView.as_view(),
name='msgid_to_series'),
# project views:
url(r'^$', patchwork.views.base.projects,
......
......@@ -23,8 +23,7 @@ from django.core.exceptions import FieldDoesNotExist, PermissionDenied
from django.conf import settings
from django.core import mail
from django.db.models import Q
from django.http import HttpResponse, JsonResponse
from itertools import groupby
from django.http import HttpResponse
from patchwork.tasks import send_reviewer_notification
from patchwork.models import (Project, Series, SeriesRevision, Patch, EventLog,
State, Test, TestResult, TestState, Person,
......@@ -43,9 +42,10 @@ from patchwork.views import patch_to_mbox, revision_cover_letter_to_mbox
from patchwork.views.patch import mbox as patch_mbox
from patchwork.permissions import Can
import django_filters
import itertools
API_REVISION = 2
API_REVISION = 4
class RelatedOrderingFilter(filters.OrderingFilter):
......@@ -549,39 +549,44 @@ class PatchViewSet(mixins.ListModelMixin,
return patch_mbox(request, pk)
def __grouping(iterable, key):
def group(iterable, key):
"""Sort and group in one go"""
sorted_iterable = sorted(iterable, key=key)
return groupby(sorted_iterable, key)
return itertools.groupby(sorted_iterable, key)
def msgid(request, msgid):
output = []
class MsgidResultsView(views.APIView):
def get(self, request, msgid):
output = []
if not (msgid.startswith('<') and msgid.endswith('>')):
msgid = '<{}>'.format(msgid)
if not (msgid.startswith('<') and msgid.endswith('>')):
msgid = '<{}>'.format(msgid)
patches = Patch.objects.filter(msgid=msgid)
for patch in patches:
series = patch.series()
revisions = series.revisions().filter(patches=patch)
patches = Patch.objects.filter(msgid=msgid)
for patch in patches:
series = patch.series()
revisions = series.revisions().filter(patches=patch)
desc = {'patch_id': patch.id,
'project_id': patch.project_id,
'series_id': series.id,
'revision_ids': [rev.version for rev in revisions]}
desc = {'patch_id': patch.id,
'project_id': patch.project_id,
'series_id': series.id,
'revision_ids': [rev.version for rev in revisions]}
output += [desc]
output += [desc]
revisions = SeriesRevision.objects.filter(root_msgid=msgid,
cover_letter__isnull=False)
for (series_id, rev_grp) in __grouping(revisions, lambda x: x.series_id):
rev_grp = list(rev_grp)
desc = {'project_id': rev_grp[0].series.project_id,
'series_id': series_id,
'revision_ids': [rev.version for rev in rev_grp]}
output += [desc]
revisions = SeriesRevision.objects.filter(root_msgid=msgid,
cover_letter__isnull=False)
for (series_id, rev_grp) in group(revisions, lambda x: x.series_id):
rev_grp = list(rev_grp)
desc = {'project_id': rev_grp[0].series.project_id,
'series_id': series_id,
'revision_ids': [rev.version for rev in rev_grp]}
output += [desc]
return JsonResponse(output, safe=False)
# let's mimic rest-framework's wrapping for consistency
return Response({'count': len(output),
'next': None, 'previous': None,
'results': output})
class PatchResultViewSet(viewsets.ViewSet, ResultMixin):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment