Rename stoken to etag and cstoken to stoken.

This conforms better with what people know from HTTP and properly
differentiates from CSToken which is now renamed to stoken.
pull/56/head
Tom Hacohen 4 years ago
parent 8eee280bbb
commit 9c63f8d674

@ -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

@ -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

@ -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)

Loading…
Cancel
Save