Change to standalone stoken objects (+ small optimisation).
Makes it possible to now generate Stokens as we need so we can add them to non-revision objects, for example, membership changes. We also slightly improved how we filter by revs.
This commit is contained in:
parent
3cdb7783fe
commit
2a39f3538e
@ -18,6 +18,7 @@ from django.db import models
|
||||
from django.conf import settings
|
||||
from django.core.validators import RegexValidator
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
|
||||
Base64Url256BitlValidator = RegexValidator(regex=r'^[a-zA-Z0-9\-_]{42,43}$', message='Expected a base64url.')
|
||||
@ -55,7 +56,7 @@ class Collection(models.Model):
|
||||
# FIXME: what is the etag for None? Though if we use the revision for collection it should be shared anyway.
|
||||
return None
|
||||
|
||||
return last_revision.uid
|
||||
return last_revision.stoken.uid
|
||||
|
||||
|
||||
class CollectionItem(models.Model):
|
||||
@ -77,7 +78,7 @@ class CollectionItem(models.Model):
|
||||
|
||||
@property
|
||||
def stoken(self):
|
||||
return self.content.uid
|
||||
return self.content.stoken.uid
|
||||
|
||||
|
||||
def chunk_directory_path(instance, filename):
|
||||
@ -98,7 +99,17 @@ class CollectionItemChunk(models.Model):
|
||||
return self.uid
|
||||
|
||||
|
||||
def generate_stoken_uid():
|
||||
return get_random_string(32, allowed_chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_')
|
||||
|
||||
|
||||
class Stoken(models.Model):
|
||||
uid = models.CharField(db_index=True, unique=True, blank=False, null=False, default=generate_stoken_uid,
|
||||
max_length=43, validators=[Base64Url256BitlValidator])
|
||||
|
||||
|
||||
class CollectionItemRevision(models.Model):
|
||||
stoken = models.OneToOneField(Stoken, on_delete=models.PROTECT)
|
||||
uid = models.CharField(db_index=True, unique=True, blank=False, null=False,
|
||||
max_length=43, validators=[Base64Url256BitlValidator])
|
||||
item = models.ForeignKey(CollectionItem, related_name='revisions', on_delete=models.CASCADE)
|
||||
|
@ -38,7 +38,9 @@ def process_revisions_for_item(item, revision_data):
|
||||
chunk = models.CollectionItemChunk.objects.get(uid=uid)
|
||||
chunks_objs.append(chunk)
|
||||
|
||||
revision = models.CollectionItemRevision.objects.create(**revision_data, item=item)
|
||||
stoken = models.Stoken.objects.create()
|
||||
|
||||
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
|
||||
|
@ -35,7 +35,15 @@ import nacl.secret
|
||||
import nacl.hash
|
||||
|
||||
from . import app_settings, permissions
|
||||
from .models import Collection, CollectionItem, CollectionItemRevision, CollectionMember, CollectionInvitation, UserInfo
|
||||
from .models import (
|
||||
Collection,
|
||||
CollectionItem,
|
||||
CollectionItemRevision,
|
||||
CollectionMember,
|
||||
CollectionInvitation,
|
||||
Stoken,
|
||||
UserInfo,
|
||||
)
|
||||
from .serializers import (
|
||||
b64encode,
|
||||
AuthenticationSignupSerializer,
|
||||
@ -94,18 +102,18 @@ class BaseViewSet(viewsets.ModelViewSet):
|
||||
user = self.request.user
|
||||
return queryset.filter(members__user=user)
|
||||
|
||||
def get_cstoken_rev(self, request):
|
||||
def get_cstoken_obj(self, request):
|
||||
cstoken = request.GET.get('cstoken', None)
|
||||
|
||||
if cstoken is not None:
|
||||
return get_object_or_404(CollectionItemRevision.objects.all(), uid=cstoken)
|
||||
return get_object_or_404(Stoken.objects.all(), uid=cstoken)
|
||||
|
||||
return None
|
||||
|
||||
def filter_by_cstoken(self, request, queryset):
|
||||
cstoken_id_field = self.cstoken_id_field + '__id'
|
||||
|
||||
cstoken_rev = self.get_cstoken_rev(request)
|
||||
cstoken_rev = self.get_cstoken_obj(request)
|
||||
if cstoken_rev is not None:
|
||||
filter_by = {cstoken_id_field + '__gt': cstoken_rev.id}
|
||||
queryset = queryset.filter(**filter_by)
|
||||
@ -116,7 +124,7 @@ class BaseViewSet(viewsets.ModelViewSet):
|
||||
cstoken_id_field = self.cstoken_id_field + '__id'
|
||||
|
||||
new_cstoken_id = queryset.aggregate(cstoken_id=Max(cstoken_id_field))['cstoken_id']
|
||||
new_cstoken = new_cstoken_id and CollectionItemRevision.objects.get(id=new_cstoken_id).uid
|
||||
new_cstoken = new_cstoken_id and Stoken.objects.get(id=new_cstoken_id).uid
|
||||
|
||||
return queryset, new_cstoken
|
||||
|
||||
@ -139,7 +147,7 @@ class CollectionViewSet(BaseViewSet):
|
||||
queryset = Collection.objects.all()
|
||||
serializer_class = CollectionSerializer
|
||||
lookup_field = 'uid'
|
||||
cstoken_id_field = 'items__revisions'
|
||||
cstoken_id_field = 'items__revisions__stoken'
|
||||
|
||||
def get_queryset(self, queryset=None):
|
||||
if queryset is None:
|
||||
@ -199,7 +207,7 @@ class CollectionItemViewSet(BaseViewSet):
|
||||
queryset = CollectionItem.objects.all()
|
||||
serializer_class = CollectionItemSerializer
|
||||
lookup_field = 'uid'
|
||||
cstoken_id_field = 'revisions'
|
||||
cstoken_id_field = 'revisions__stoken'
|
||||
|
||||
def get_queryset(self):
|
||||
collection_uid = self.kwargs['collection_uid']
|
||||
@ -290,8 +298,8 @@ class CollectionItemViewSet(BaseViewSet):
|
||||
queryset, cstoken_rev = self.filter_by_cstoken(request, queryset)
|
||||
|
||||
uids, stokens = zip(*[(item['uid'], item.get('stoken')) for item in serializer.validated_data])
|
||||
rev_ids = CollectionItemRevision.objects.filter(uid__in=stokens, current=True).values_list('id', flat=True)
|
||||
queryset = queryset.filter(uid__in=uids).exclude(revisions__id__in=rev_ids)
|
||||
revs = CollectionItemRevision.objects.filter(stoken__uid__in=stokens, 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
|
||||
|
Loading…
Reference in New Issue
Block a user