From 687bf9924b80f10e852d69eaa78c291c3dd99763 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Thu, 16 Apr 2020 16:37:26 +0300 Subject: [PATCH] API: change how pagination and stoken are done --- django_etesync/paginators.py | 36 ---------------------------- django_etesync/views.py | 46 +++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 42 deletions(-) delete mode 100644 django_etesync/paginators.py diff --git a/django_etesync/paginators.py b/django_etesync/paginators.py deleted file mode 100644 index 6d55599..0000000 --- a/django_etesync/paginators.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright © 2017 Tom Hacohen -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, version 3. -# -# This library 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 this program. If not, see . - -from rest_framework import pagination -from rest_framework.response import Response - - -class LinkHeaderPagination(pagination.LimitOffsetPagination): - def get_paginated_response(self, data): - next_url = self.get_next_link() - previous_url = self.get_previous_link() - - if next_url is not None and previous_url is not None: - link = '<{next_url}>; rel="next", <{previous_url}>; rel="prev"' - elif next_url is not None: - link = '<{next_url}>; rel="next"' - elif previous_url is not None: - link = '<{previous_url}>; rel="prev"' - else: - link = '' - - link = link.format(next_url=next_url, previous_url=previous_url) - headers = {'Link': link} if link else {} - - return Response(data, headers=headers) diff --git a/django_etesync/views.py b/django_etesync/views.py index 6c2faf3..df22068 100644 --- a/django_etesync/views.py +++ b/django_etesync/views.py @@ -24,8 +24,8 @@ from rest_framework import parsers from rest_framework.decorators import action as action_decorator from rest_framework.response import Response -from . import app_settings, paginators -from .models import Collection, CollectionItem +from . import app_settings +from .models import Collection, CollectionItem, CollectionItemRevision from .serializers import ( CollectionSerializer, CollectionItemSerializer, @@ -61,8 +61,9 @@ class CollectionViewSet(BaseViewSet): serializer_class = CollectionSerializer lookup_field = 'uid' - def get_queryset(self): - queryset = type(self).queryset + def get_queryset(self, queryset=None): + if queryset is None: + queryset = type(self).queryset return self.get_collection_queryset(queryset) def get_serializer_context(self): @@ -89,10 +90,24 @@ class CollectionViewSet(BaseViewSet): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) def list(self, request): + stoken = request.GET.get('stoken', None) + limit = int(request.GET.get('limit', 50)) + queryset = self.get_queryset() + if stoken is not None: + last_rev = get_object_or_404(CollectionItemRevision.objects.all(), uid=stoken) + queryset = queryset.filter(items__revisions__id__gt=last_rev.id) + + queryset = queryset[:limit] + serializer = self.serializer_class(queryset, context=self.get_serializer_context(), many=True) - return Response(serializer.data) + + new_stoken = serializer.data[-1]['stoken'] if len(serializer.data) > 0 else stoken + ret = { + 'data': serializer.data, + } + return Response(ret, headers={'X-EteSync-SToken': new_stoken}) class CollectionItemViewSet(BaseViewSet): @@ -100,7 +115,6 @@ class CollectionItemViewSet(BaseViewSet): permission_classes = BaseViewSet.permission_classes queryset = CollectionItem.objects.all() serializer_class = CollectionItemSerializer - pagination_class = paginators.LinkHeaderPagination lookup_field = 'uid' def get_queryset(self): @@ -148,6 +162,26 @@ class CollectionItemViewSet(BaseViewSet): # FIXME: implement, or should it be implemented elsewhere? return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) + def list(self, request, collection_uid=None): + stoken = request.GET.get('stoken', None) + limit = int(request.GET.get('limit', 50)) + + queryset = self.get_queryset() + + if stoken is not None: + last_rev = get_object_or_404(CollectionItemRevision.objects.all(), uid=stoken) + queryset = queryset.filter(revisions__id__gt=last_rev.id) + + queryset = queryset[:limit] + + serializer = self.serializer_class(queryset, context=self.get_serializer_context(), many=True) + + new_stoken = serializer.data[-1]['content']['uid'] if len(serializer.data) > 0 else stoken + ret = { + 'data': serializer.data, + } + return Response(ret, headers={'X-EteSync-SToken': new_stoken}) + @action_decorator(detail=True, methods=['GET']) def revision(self, request, collection_uid=None, uid=None): col = get_object_or_404(self.get_collection_queryset(Collection.objects), uid=collection_uid)