[PATCH v2 6/6] REST: Add '/bundle' endpoint
Andy Doan
andy.doan at linaro.org
Wed Mar 15 02:48:06 AEDT 2017
On 03/07/2017 01:22 PM, Stephen Finucane wrote:
> I had initially resisted adding a '/bundle' endpoint to the API as I
> wanted to kill this feature in favour of series. However, series are not
> a like-for-like replacement for bundles. Among other things, series do
> not provide the composability of bundles: bundles can be manually
> created, meaning you can use bundles to group not only multiple patches
> but also multiple series (or at least the patches in those series).
>
> Seeing as we're not getting rid of this feature, we should expose it via
> the API. Bundles are little unusual, in that they can be public or
> private, thus, we should only show bundles that are public or belonging
> to the currently authenticated user, if any. For now, this is a
> read-only endpoint. We may well allow creation of bundles via the API
> once we figure out how to do this cleanly.
>
> Signed-off-by: Stephen Finucane <stephen at that.guru>
> Cc: Andy Doan <andy.doan at linaro.org>
This looks fine to me. Two things though:
1) Can you add some unit tests for this?
2) Are you planning a follow on patch to allow updates via this endpoint?
> ---
> v2:
> - Add '/bundles' to endpoint list at '/'
> ---
> patchwork/api/bundle.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
> patchwork/api/filters.py | 8 +++++
> patchwork/api/index.py | 1 +
> patchwork/urls.py | 7 +++++
> 4 files changed, 96 insertions(+)
> create mode 100644 patchwork/api/bundle.py
>
> diff --git a/patchwork/api/bundle.py b/patchwork/api/bundle.py
> new file mode 100644
> index 0000000..2b17d05
> --- /dev/null
> +++ b/patchwork/api/bundle.py
> @@ -0,0 +1,80 @@
> +# 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 django.db.models import Q
> +from rest_framework.generics import ListAPIView
> +from rest_framework.generics import RetrieveAPIView
> +from rest_framework.serializers import HyperlinkedModelSerializer
> +from rest_framework.serializers import SerializerMethodField
> +
> +from patchwork.api.base import PatchworkPermission
> +from patchwork.api.filters import BundleFilter
> +from patchwork.models import Bundle
> +
> +
> +class BundleSerializer(HyperlinkedModelSerializer):
> +
> + mbox = SerializerMethodField()
> +
> + def get_mbox(self, instance):
> + request = self.context.get('request')
> + return request.build_absolute_uri(instance.get_mbox_url())
> +
> + class Meta:
> + model = Bundle
> + fields = ('id', 'url', 'project', 'name', 'owner', 'patches',
> + 'public', 'mbox')
> + read_only_fields = ('project', 'owner', 'patches', 'mbox')
> + extra_kwargs = {
> + 'url': {'view_name': 'api-bundle-detail'},
> + 'project': {'view_name': 'api-project-detail'},
> + 'owner': {'view_name': 'api-user-detail'},
> + 'patches': {'view_name': 'api-patch-detail'},
> + }
> +
> +
> +class BundleMixin(object):
> +
> + permission_classes = (PatchworkPermission,)
> + serializer_class = BundleSerializer
> +
> + def get_queryset(self):
> + if not self.request.user.is_anonymous:
> + bundle_filter = Q(owner=self.request.user) | Q(public=True)
> + else:
> + bundle_filter = Q(public=True)
> +
> + return Bundle.objects\
> + .filter(bundle_filter)\
> + .prefetch_related('patches',)\
> + .select_related('owner', 'project')
> +
> +
> +class BundleList(BundleMixin, ListAPIView):
> + """List bundles."""
> +
> + filter_class = BundleFilter
> + search_fields = ('name',)
> + ordering_fields = ('id', 'name', 'owner')
> +
> +
> +class BundleDetail(BundleMixin, RetrieveAPIView):
> + """Show a bundle."""
> +
> + pass
> diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py
> index 0f2e6e9..eff7ceb 100644
> --- a/patchwork/api/filters.py
> +++ b/patchwork/api/filters.py
> @@ -20,6 +20,7 @@
> from django_filters import FilterSet
> from django_filters import IsoDateTimeFilter
>
> +from patchwork.models import Bundle
> from patchwork.models import Check
> from patchwork.models import CoverLetter
> from patchwork.models import Event
> @@ -68,3 +69,10 @@ class EventFilter(FilterSet):
> class Meta:
> model = Event
> fields = ('project', 'series', 'patch', 'cover')
> +
> +
> +class BundleFilter(FilterSet):
> +
> + class Meta:
> + model = Bundle
> + fields = ('project', 'owner', 'public')
> diff --git a/patchwork/api/index.py b/patchwork/api/index.py
> index 210c32e..513e8b6 100644
> --- a/patchwork/api/index.py
> +++ b/patchwork/api/index.py
> @@ -34,4 +34,5 @@ class IndexView(APIView):
> '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')),
> + 'bundles': request.build_absolute_uri(reverse('api-bundle-list')),
> })
> diff --git a/patchwork/urls.py b/patchwork/urls.py
> index 09b8b31..57d5cd7 100644
> --- a/patchwork/urls.py
> +++ b/patchwork/urls.py
> @@ -158,6 +158,7 @@ if settings.ENABLE_REST_API:
> raise RuntimeError(
> 'djangorestframework must be installed to enable the REST API.')
>
> + from patchwork.api import bundle as api_bundle_views
> from patchwork.api import check as api_check_views
> from patchwork.api import cover as api_cover_views
> from patchwork.api import event as api_event_views
> @@ -208,6 +209,12 @@ if settings.ENABLE_REST_API:
> url(r'^series/(?P<pk>[^/]+)/$',
> api_series_views.SeriesDetail.as_view(),
> name='api-series-detail'),
> + url(r'^bundles/$',
> + api_bundle_views.BundleList.as_view(),
> + name='api-bundle-list'),
> + url(r'^bundles/(?P<pk>[^/]+)/$',
> + api_bundle_views.BundleDetail.as_view(),
> + name='api-bundle-detail'),
> url(r'^projects/$',
> api_project_views.ProjectList.as_view(),
> name='api-project-list'),
>
More information about the Patchwork
mailing list