From bdd787b9158cee532fc9ba1e579d7ef7337dcf8a Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Mon, 9 Nov 2020 17:31:12 +0200 Subject: [PATCH] Gracefully handle uploading the same item twice. We were failing until now, but since the uid is sure to be unique, we can just assume that if it's the same uid it's the same content. This means we can just gracefully fail as the data is the same. Until now, we were raising an error, but we now just do nothing and consider it a success. This is especially useful when a network error caused an item to be uploaded but not updated on the client side. --- django_etebase/serializers.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/django_etebase/serializers.py b/django_etebase/serializers.py index 97dcd64..4f2d802 100644 --- a/django_etebase/serializers.py +++ b/django_etebase/serializers.py @@ -30,6 +30,10 @@ User = get_user_model() def process_revisions_for_item(item, revision_data): chunks_objs = [] chunks = revision_data.pop('chunks_relation') + + revision = models.CollectionItemRevision(**revision_data, item=item) + revision.validate_unique() # Verify there aren't any validation issues + for chunk in chunks: uid = chunk[0] chunk_obj = models.CollectionItemChunk.objects.filter(uid=uid).first() @@ -47,8 +51,9 @@ def process_revisions_for_item(item, revision_data): chunks_objs.append(chunk_obj) stoken = models.Stoken.objects.create() + revision.stoken = stoken + revision.save() - revision = models.CollectionItemRevision.objects.create(**revision_data, item=item, stoken=stoken) for chunk in chunks_objs: models.RevisionChunkRelation.objects.create(chunk=chunk, revision=revision) return revision @@ -196,6 +201,9 @@ class CollectionItemRevisionSerializer(BetterErrorsMixin, serializers.ModelSeria class Meta: model = models.CollectionItemRevision fields = ('chunks', 'meta', 'uid', 'deleted') + extra_kwargs = { + 'uid': {'validators': []}, # We deal with it in the serializers + } class CollectionItemSerializer(BetterErrorsMixin, serializers.ModelSerializer): @@ -220,6 +228,10 @@ class CollectionItemSerializer(BetterErrorsMixin, serializers.ModelSerializer): instance, created = Model.objects.get_or_create(uid=uid, defaults=validated_data) cur_etag = instance.etag if not created else None + # If we are trying to update an up to date item, abort early and consider it a success + if cur_etag == revision_data.get('uid'): + return instance + if validate_etag and cur_etag != etag: raise EtebaseValidationError('wrong_etag', 'Wrong etag. Expected {} got {}'.format(cur_etag, etag), status_code=status.HTTP_409_CONFLICT) @@ -231,7 +243,10 @@ class CollectionItemSerializer(BetterErrorsMixin, serializers.ModelSerializer): current_revision.current = None current_revision.save() - process_revisions_for_item(instance, revision_data) + try: + process_revisions_for_item(instance, revision_data) + except django_exceptions.ValidationError as e: + self.transform_validation_error("content", e) return instance