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 <[email protected]> --- 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 <[email protected]> +# +# 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 _______________________________________________ Patchwork mailing list [email protected] https://lists.ozlabs.org/listinfo/patchwork
