From c63210fe77ff0c3d839174e32b4fe8f91818f590 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Tue, 19 May 2020 16:16:40 +0300 Subject: [PATCH] CollectionItem: implement batch updating. --- django_etesync/serializers.py | 3 ++- django_etesync/views.py | 38 +++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/django_etesync/serializers.py b/django_etesync/serializers.py index e5a9e4f..773a8a2 100644 --- a/django_etesync/serializers.py +++ b/django_etesync/serializers.py @@ -121,6 +121,7 @@ class CollectionItemSerializer(serializers.ModelSerializer): def create(self, validated_data): """Function that's called when this serializer creates an item""" + validate_stoken = self.context.get('validate_stoken', False) stoken = validated_data.pop('stoken') revision_data = validated_data.pop('content') uid = validated_data.pop('uid') @@ -131,7 +132,7 @@ class CollectionItemSerializer(serializers.ModelSerializer): instance, created = Model.objects.get_or_create(uid=uid, defaults=validated_data) cur_stoken = instance.stoken if not created else None - if cur_stoken != stoken: + if validate_stoken and cur_stoken != stoken: raise serializers.ValidationError('Wrong stoken. Expected {} got {}'.format(cur_stoken, stoken)) if not created: diff --git a/django_etesync/views.py b/django_etesync/views.py index 081bd37..ab5c0c7 100644 --- a/django_etesync/views.py +++ b/django_etesync/views.py @@ -245,8 +245,36 @@ class CollectionItemViewSet(BaseViewSet): @action_decorator(detail=False, methods=['POST']) def batch(self, request, collection_uid=None): - # FIXME: different to transaction slightly - return self.transaction(request, collection_uid) + cstoken = request.GET.get('cstoken', None) + collection_object = get_object_or_404(self.get_collection_queryset(Collection.objects), uid=collection_uid) + + if cstoken is not None and cstoken != collection_object.cstoken: + content = {'code': 'stale_cstoken', 'detail': 'CSToken is too old'} + return Response(content, status=status.HTTP_400_BAD_REQUEST) + + items = request.data.get('items') + context = self.get_serializer_context() + serializer = self.get_serializer_class()(data=items, context=context, many=True) + + if serializer.is_valid(): + try: + with transaction.atomic(): + items = serializer.save(collection=collection_object) + except IntegrityError: + # FIXME: should return the items with a bad token (including deps) so we don't have to fetch them after + content = {'code': 'integrity_error'} + return Response(content, status=status.HTTP_400_BAD_REQUEST) + + ret = { + "data": [item.stoken for item in items], + } + return Response(ret, status=status.HTTP_200_OK) + + return Response( + { + "items": serializer.errors, + }, + status=status.HTTP_400_BAD_REQUEST) @action_decorator(detail=False, methods=['POST']) def transaction(self, request, collection_uid=None): @@ -260,8 +288,10 @@ class CollectionItemViewSet(BaseViewSet): items = request.data.get('items') deps = request.data.get('deps', None) # FIXME: It should just be one serializer - serializer = self.get_serializer_class()(data=items, context=self.get_serializer_context(), many=True) - deps_serializer = CollectionItemDepSerializer(data=deps, context=self.get_serializer_context(), many=True) + context = self.get_serializer_context() + context.update({'validate_stoken': True}) + serializer = self.get_serializer_class()(data=items, context=context, many=True) + deps_serializer = CollectionItemDepSerializer(data=deps, context=context, many=True) ser_valid = serializer.is_valid() deps_ser_valid = (deps is None or deps_serializer.is_valid())