[PATCH 4/4] REST: Expose events

Stephen Finucane stephen at that.guru
Sat Jan 7 10:40:27 AEDT 2017


This is a list only endpoint as it's expected that we would kill events
after a certain duration and would have no reason to allow indexing of
past events.

Signed-off-by: Stephen Finucane <stephen at that.guru>
---
 patchwork/api/base.py  | 22 ++++++++++++++---
 patchwork/api/check.py |  4 ++-
 patchwork/api/event.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++
 patchwork/api/index.py |  2 ++
 patchwork/models.py    |  8 ++++++
 patchwork/urls.py      |  6 ++++-
 6 files changed, 104 insertions(+), 5 deletions(-)
 create mode 100644 patchwork/api/event.py

diff --git a/patchwork/api/base.py b/patchwork/api/base.py
index 13a8432..f5df740 100644
--- a/patchwork/api/base.py
+++ b/patchwork/api/base.py
@@ -20,6 +20,7 @@
 from django.conf import settings
 from django.shortcuts import get_object_or_404
 from rest_framework import permissions
+from rest_framework.pagination import CursorPagination
 from rest_framework.pagination import PageNumberPagination
 from rest_framework.response import Response
 
@@ -29,7 +30,7 @@ STATE_CHOICES = ['-'.join(x.name.lower().split(' '))
                  for x in State.objects.all()]
 
 
-class LinkHeaderPagination(PageNumberPagination):
+class LinkHeaderMixin(object):
     """Provide pagination based on rfc5988.
 
     This is the Link header, similar to how GitHub does it. See:
@@ -37,8 +38,6 @@ class LinkHeaderPagination(PageNumberPagination):
        https://tools.ietf.org/html/rfc5988#section-5
        https://developer.github.com/guides/traversing-with-pagination
     """
-    page_size = settings.REST_RESULTS_PER_PAGE
-    page_size_query_param = 'per_page'
 
     def get_paginated_response(self, data):
         next_url = self.get_next_link()
@@ -56,6 +55,23 @@ class LinkHeaderPagination(PageNumberPagination):
         return Response(data, headers=headers)
 
 
+class LinkHeaderPageNumberPagination(LinkHeaderMixin, PageNumberPagination):
+    """A Link header-based variant of page-based paginator."""
+
+    page_size = settings.REST_RESULTS_PER_PAGE
+    page_size_query_param = 'per_page'
+
+
+LinkHeaderPagination = LinkHeaderPageNumberPagination
+
+
+class LinkHeaderCursorPagination(LinkHeaderMixin, CursorPagination):
+    """A Link header-based variant of cursor-based paginator."""
+
+    ordering = 'date'
+    page_size = 1
+
+
 class PatchworkPermission(permissions.BasePermission):
     """This permission works for Project and Patch model objects"""
     def has_object_permission(self, request, view, obj):
diff --git a/patchwork/api/check.py b/patchwork/api/check.py
index a66106e..24a0a05 100644
--- a/patchwork/api/check.py
+++ b/patchwork/api/check.py
@@ -87,9 +87,11 @@ class CheckSerializer(HyperlinkedModelSerializer):
 
 class CheckMixin(object):
 
-    queryset = Check.objects.prefetch_related('patch', 'user')
     serializer_class = CheckSerializer
 
+    def get_queryset(self):
+        return Check.objects.prefetch_related('patch', 'user')
+
 
 class CheckListCreate(CheckMixin, ListCreateAPIView):
     """List or create checks."""
diff --git a/patchwork/api/event.py b/patchwork/api/event.py
new file mode 100644
index 0000000..e256968
--- /dev/null
+++ b/patchwork/api/event.py
@@ -0,0 +1,67 @@
+# Patchwork - automated patch tracking system
+# Copyright (C) 2017 Stephen Finucane <stephen at that.guru>
+#
+# This file is part of the Patchwork package.
+#
+# Patchwork is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Patchwork is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Patchwork; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+from rest_framework.generics import ListAPIView
+from rest_framework.serializers import HyperlinkedModelSerializer
+
+from patchwork.api.base import LinkHeaderCursorPagination
+from patchwork.api.patch import StateField
+from patchwork.models import Event
+
+
+class EventSerializer(HyperlinkedModelSerializer):
+
+    previous_state = StateField()
+    current_state = StateField()
+
+    def to_representation(self, instance):
+        data = super(EventSerializer, self).to_representation(instance)
+        data['category'] = instance.get_category_display()
+
+        # drop any nullified fields
+        kept_fields = Event.CATEGORY_FIELD_MAP[instance.category] + [
+            'id', 'category', 'project', 'patch', 'public', 'date']
+        for field in [x for x in data if x not in kept_fields]:
+            del data[field]
+
+        return data
+
+    class Meta:
+        model = Event
+        fields = ('id', 'category', 'project', 'patch', 'public', 'date',
+                  'previous_state', 'current_state', 'previous_delegate',
+                  'current_delegate', 'created_check')
+        read_only_fields = fields
+        extra_kwargs = {
+            'project': {'view_name': 'api-project-detail'},
+            'patch': {'view_name': 'api-patch-detail'},
+            'previous_delegate': {'view_name': 'api-user-detail'},
+            'current_delegate': {'view_name': 'api-user-detail'},
+            'created_check': {'view_name': 'api-check-detail'},
+        }
+
+
+class EventList(ListAPIView):
+    """List events."""
+
+    serializer_class = EventSerializer
+    pagination_class = LinkHeaderCursorPagination
+
+    def get_queryset(self):
+        return Event.objects.all()
diff --git a/patchwork/api/index.py b/patchwork/api/index.py
index 58aeb87..84248cc 100644
--- a/patchwork/api/index.py
+++ b/patchwork/api/index.py
@@ -33,4 +33,6 @@ class IndexView(APIView):
             'patches': request.build_absolute_uri(reverse('api-patch-list')),
             'covers': request.build_absolute_uri(reverse('api-cover-list')),
             'series': request.build_absolute_uri(reverse('api-series-list')),
+            'events': request.build_absolute_uri(reverse('api-event-list')),
+            'checks': request.build_absolute_uri(reverse('api-check-list')),
         })
diff --git a/patchwork/models.py b/patchwork/models.py
index 45183f6..2c5fe12 100644
--- a/patchwork/models.py
+++ b/patchwork/models.py
@@ -810,6 +810,14 @@ class Event(models.Model):
         (CATEGORY_CHECK_ADDED, 'check-added'),
     )
 
+    CATEGORY_FIELD_MAP = {
+        CATEGORY_PATCH_CREATED: [],
+        CATEGORY_DEPENDENCIES_MET: [],
+        CATEGORY_STATE_CHANGED: ['previous_state', 'current_state'],
+        CATEGORY_DELEGATE_CHANGED: ['previous_delegate', 'current_delegate'],
+        CATEGORY_CHECK_ADDED: ['created_check'],
+    }
+
     project = models.ForeignKey(
         Project, related_name='+',
         help_text='The project that the events belongs to.')
diff --git a/patchwork/urls.py b/patchwork/urls.py
index 68aefc2..fbba807 100644
--- a/patchwork/urls.py
+++ b/patchwork/urls.py
@@ -153,8 +153,9 @@ if settings.ENABLE_REST_API:
             'djangorestframework must be installed to enable the REST API.')
 
     from patchwork.api import check as api_check_views
-    from patchwork.api import index as api_index_views
     from patchwork.api import cover as api_cover_views
+    from patchwork.api import event as api_event_views
+    from patchwork.api import index as api_index_views
     from patchwork.api import patch as api_patch_views
     from patchwork.api import person as api_person_views
     from patchwork.api import project as api_project_views
@@ -207,6 +208,9 @@ if settings.ENABLE_REST_API:
         url(r'^projects/(?P<pk>[^/]+)/$',
             api_project_views.ProjectDetail.as_view(),
             name='api-project-detail'),
+        url(r'^events/$',
+            api_event_views.EventList.as_view(),
+            name='api-event-list'),
     ]
 
     urlpatterns += [
-- 
2.9.3



More information about the Patchwork mailing list