diff --git a/django_etesync/models.py b/django_etesync/models.py index 6c50ea2..c9c95a1 100644 --- a/django_etesync/models.py +++ b/django_etesync/models.py @@ -46,11 +46,11 @@ class Collection(models.Model): return self.main_item.content @property - def stoken(self): + def etag(self): return self.content.uid @cached_property - def cstoken(self): + def stoken(self): last_revision = CollectionItemRevision.objects.filter(item__collection=self).last() if last_revision is None: # FIXME: what is the etag for None? Though if we use the revision for collection it should be shared anyway. @@ -77,7 +77,7 @@ class CollectionItem(models.Model): return self.revisions.get(current=True) @property - def stoken(self): + def etag(self): return self.content.uid diff --git a/django_etesync/serializers.py b/django_etesync/serializers.py index d08fcfd..75baba0 100644 --- a/django_etesync/serializers.py +++ b/django_etesync/serializers.py @@ -114,17 +114,17 @@ class CollectionItemRevisionSerializer(serializers.ModelSerializer): class CollectionItemSerializer(serializers.ModelSerializer): encryptionKey = BinaryBase64Field() - stoken = serializers.CharField(allow_null=True) + etag = serializers.CharField(allow_null=True) content = CollectionItemRevisionSerializer(many=False) class Meta: model = models.CollectionItem - fields = ('uid', 'version', 'encryptionKey', 'content', 'stoken') + fields = ('uid', 'version', 'encryptionKey', 'content', 'etag') 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') + validate_etag = self.context.get('validate_etag', False) + etag = validated_data.pop('etag') revision_data = validated_data.pop('content') uid = validated_data.pop('uid') @@ -132,10 +132,10 @@ class CollectionItemSerializer(serializers.ModelSerializer): with transaction.atomic(): instance, created = Model.objects.get_or_create(uid=uid, defaults=validated_data) - cur_stoken = instance.stoken if not created else None + cur_etag = instance.etag if not created else None - if validate_stoken and cur_stoken != stoken: - raise serializers.ValidationError('Wrong stoken. Expected {} got {}'.format(cur_stoken, stoken)) + if validate_etag and cur_etag != etag: + raise serializers.ValidationError('Wrong etag. Expected {} got {}'.format(cur_etag, etag)) if not created: # We don't have to use select_for_update here because the unique constraint on current guards against @@ -154,39 +154,39 @@ class CollectionItemSerializer(serializers.ModelSerializer): class CollectionItemDepSerializer(serializers.ModelSerializer): - stoken = serializers.CharField() + etag = serializers.CharField() class Meta: model = models.CollectionItem - fields = ('uid', 'stoken') + fields = ('uid', 'etag') def validate(self, data): item = self.__class__.Meta.model.objects.get(uid=data['uid']) - stoken = data['stoken'] - if item.stoken != stoken: - raise serializers.ValidationError('Wrong stoken. Expected {} got {}'.format(item.stoken, stoken)) + etag = data['etag'] + if item.etag != etag: + raise serializers.ValidationError('Wrong etag. Expected {} got {}'.format(item.etag, etag)) return data class CollectionItemBulkGetSerializer(serializers.ModelSerializer): - stoken = serializers.CharField(required=False) + etag = serializers.CharField(required=False) class Meta: model = models.CollectionItem - fields = ('uid', 'stoken') + fields = ('uid', 'etag') class CollectionSerializer(serializers.ModelSerializer): encryptionKey = CollectionEncryptionKeyField() accessLevel = serializers.SerializerMethodField('get_access_level_from_context') - cstoken = serializers.CharField(read_only=True) - stoken = serializers.CharField(allow_null=True) + stoken = serializers.CharField(read_only=True) + etag = serializers.CharField(allow_null=True) content = CollectionItemRevisionSerializer(many=False) class Meta: model = models.Collection - fields = ('uid', 'version', 'accessLevel', 'encryptionKey', 'content', 'cstoken', 'stoken') + fields = ('uid', 'version', 'accessLevel', 'encryptionKey', 'content', 'stoken', 'etag') def get_access_level_from_context(self, obj): request = self.context.get('request', None) @@ -196,13 +196,13 @@ class CollectionSerializer(serializers.ModelSerializer): def create(self, validated_data): """Function that's called when this serializer creates an item""" - stoken = validated_data.pop('stoken') + etag = validated_data.pop('etag') revision_data = validated_data.pop('content') encryption_key = validated_data.pop('encryptionKey') instance = self.__class__.Meta.model(**validated_data) with transaction.atomic(): - if stoken is not None: + if etag is not None: raise serializers.ValidationError('Stoken is not None') instance.save() @@ -221,12 +221,12 @@ class CollectionSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): """Function that's called when this serializer is meant to update an item""" - stoken = validated_data.pop('stoken') + etag = validated_data.pop('etag') revision_data = validated_data.pop('content') with transaction.atomic(): - if stoken != instance.stoken: - raise serializers.ValidationError('Wrong stoken. Expected {} got {}'.format(instance.stoken, stoken)) + if etag != instance.etag: + raise serializers.ValidationError('Wrong etag. Expected {} got {}'.format(instance.etag, etag)) main_item = instance.main_item # We don't have to use select_for_update here because the unique constraint on current guards against diff --git a/django_etesync/views.py b/django_etesync/views.py index 2341484..e66bb82 100644 --- a/django_etesync/views.py +++ b/django_etesync/views.py @@ -70,7 +70,7 @@ User = get_user_model() class BaseViewSet(viewsets.ModelViewSet): authentication_classes = tuple(app_settings.API_AUTHENTICATORS) permission_classes = tuple(app_settings.API_PERMISSIONS) - cstoken_id_field = None + stoken_id_field = None def get_serializer_class(self): serializer_class = self.serializer_class @@ -84,43 +84,43 @@ class BaseViewSet(viewsets.ModelViewSet): user = self.request.user return queryset.filter(members__user=user) - def get_cstoken_obj(self, request): - cstoken = request.GET.get('cstoken', None) + def get_stoken_obj(self, request): + stoken = request.GET.get('stoken', None) - if cstoken is not None: - return get_object_or_404(Stoken.objects.all(), uid=cstoken) + if stoken is not None: + return get_object_or_404(Stoken.objects.all(), uid=stoken) return None - def filter_by_cstoken(self, request, queryset): - cstoken_id_field = self.cstoken_id_field + '__id' + def filter_by_stoken(self, request, queryset): + stoken_id_field = self.stoken_id_field + '__id' - cstoken_rev = self.get_cstoken_obj(request) - if cstoken_rev is not None: - filter_by = {cstoken_id_field + '__gt': cstoken_rev.id} + stoken_rev = self.get_stoken_obj(request) + if stoken_rev is not None: + filter_by = {stoken_id_field + '__gt': stoken_rev.id} queryset = queryset.filter(**filter_by) - return queryset, cstoken_rev + return queryset, stoken_rev - def get_queryset_cstoken(self, queryset): - cstoken_id_field = self.cstoken_id_field + '__id' + def get_queryset_stoken(self, queryset): + stoken_id_field = self.stoken_id_field + '__id' - new_cstoken_id = queryset.aggregate(cstoken_id=Max(cstoken_id_field))['cstoken_id'] - new_cstoken = new_cstoken_id and Stoken.objects.get(id=new_cstoken_id).uid + new_stoken_id = queryset.aggregate(stoken_id=Max(stoken_id_field))['stoken_id'] + new_stoken = new_stoken_id and Stoken.objects.get(id=new_stoken_id).uid - return queryset, new_cstoken + return queryset, new_stoken - def filter_by_cstoken_and_limit(self, request, queryset): + def filter_by_stoken_and_limit(self, request, queryset): limit = int(request.GET.get('limit', 50)) - queryset, cstoken_rev = self.filter_by_cstoken(request, queryset) - cstoken = cstoken_rev.uid if cstoken_rev is not None else None + queryset, stoken_rev = self.filter_by_stoken(request, queryset) + stoken = stoken_rev.uid if stoken_rev is not None else None queryset = queryset[:limit] - queryset, new_cstoken = self.get_queryset_cstoken(queryset) - new_cstoken = new_cstoken or cstoken + queryset, new_stoken = self.get_queryset_stoken(queryset) + new_stoken = new_stoken or stoken - return queryset, new_cstoken + return queryset, new_stoken class CollectionViewSet(BaseViewSet): @@ -129,7 +129,7 @@ class CollectionViewSet(BaseViewSet): queryset = Collection.objects.all() serializer_class = CollectionSerializer lookup_field = 'uid' - cstoken_id_field = 'items__revisions__stoken' + stoken_id_field = 'items__revisions__stoken' def get_queryset(self, queryset=None): if queryset is None: @@ -172,13 +172,13 @@ class CollectionViewSet(BaseViewSet): def list(self, request): queryset = self.get_queryset() - queryset, new_cstoken = self.filter_by_cstoken_and_limit(request, queryset) + queryset, new_stoken = self.filter_by_stoken_and_limit(request, queryset) serializer = self.serializer_class(queryset, context=self.get_serializer_context(), many=True) ret = { 'data': serializer.data, - 'cstoken': new_cstoken, + 'stoken': new_stoken, } return Response(ret) @@ -189,7 +189,7 @@ class CollectionItemViewSet(BaseViewSet): queryset = CollectionItem.objects.all() serializer_class = CollectionItemSerializer lookup_field = 'uid' - cstoken_id_field = 'revisions__stoken' + stoken_id_field = 'revisions__stoken' def get_queryset(self): collection_uid = self.kwargs['collection_uid'] @@ -240,13 +240,13 @@ class CollectionItemViewSet(BaseViewSet): def list(self, request, collection_uid=None): queryset = self.get_queryset() - queryset, new_cstoken = self.filter_by_cstoken_and_limit(request, queryset) + queryset, new_stoken = self.filter_by_stoken_and_limit(request, queryset) serializer = self.serializer_class(queryset, context=self.get_serializer_context(), many=True) ret = { 'data': serializer.data, - 'cstoken': new_cstoken, + 'stoken': new_stoken, } return Response(ret) @@ -277,21 +277,21 @@ class CollectionItemViewSet(BaseViewSet): 'detail': 'Request has too many items. Limit: {}'. format(item_limit)} return Response(content, status=status.HTTP_400_BAD_REQUEST) - queryset, cstoken_rev = self.filter_by_cstoken(request, queryset) + queryset, stoken_rev = self.filter_by_stoken(request, queryset) - uids, stokens = zip(*[(item['uid'], item.get('stoken')) for item in serializer.validated_data]) - revs = CollectionItemRevision.objects.filter(uid__in=stokens, current=True) + uids, etags = zip(*[(item['uid'], item.get('etag')) for item in serializer.validated_data]) + revs = CollectionItemRevision.objects.filter(uid__in=etags, current=True) queryset = queryset.filter(uid__in=uids).exclude(revisions__in=revs) - queryset, new_cstoken = self.get_queryset_cstoken(queryset) - cstoken = cstoken_rev and cstoken_rev.uid - new_cstoken = new_cstoken or cstoken + queryset, new_stoken = self.get_queryset_stoken(queryset) + stoken = stoken_rev and stoken_rev.uid + new_stoken = new_stoken or stoken serializer = self.get_serializer_class()(queryset, context=self.get_serializer_context(), many=True) ret = { 'data': serializer.data, - 'cstoken': new_cstoken, + 'stoken': new_stoken, } return Response(ret) @@ -299,11 +299,11 @@ class CollectionItemViewSet(BaseViewSet): @action_decorator(detail=False, methods=['POST']) def batch(self, request, collection_uid=None): - cstoken = request.GET.get('cstoken', None) + stoken = request.GET.get('stoken', 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'} + if stoken is not None and stoken != collection_object.stoken: + content = {'code': 'stale_stoken', 'detail': 'Stoken is too old'} return Response(content, status=status.HTTP_400_BAD_REQUEST) items = request.data.get('items') @@ -331,18 +331,18 @@ class CollectionItemViewSet(BaseViewSet): @action_decorator(detail=False, methods=['POST']) def transaction(self, request, collection_uid=None): - cstoken = request.GET.get('cstoken', None) + stoken = request.GET.get('stoken', 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'} + if stoken is not None and stoken != collection_object.stoken: + content = {'code': 'stale_stoken', 'detail': 'Stoken is too old'} return Response(content, status=status.HTTP_400_BAD_REQUEST) items = request.data.get('items') deps = request.data.get('deps', None) # FIXME: It should just be one serializer context = self.get_serializer_context() - context.update({'validate_stoken': True}) + context.update({'validate_etag': True}) serializer = self.get_serializer_class()(data=items, context=context, many=True) deps_serializer = CollectionItemDepSerializer(data=deps, context=context, many=True)