mirror of
https://github.com/etesync/server
synced 2024-11-25 18:28:46 +00:00
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.conf import settings
|
||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
from django.utils.functional import cached_property
|
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.')
|
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.
|
# FIXME: what is the etag for None? Though if we use the revision for collection it should be shared anyway.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return last_revision.uid
|
return last_revision.stoken.uid
|
||||||
|
|
||||||
|
|
||||||
class CollectionItem(models.Model):
|
class CollectionItem(models.Model):
|
||||||
@ -77,7 +78,7 @@ class CollectionItem(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def stoken(self):
|
def stoken(self):
|
||||||
return self.content.uid
|
return self.content.stoken.uid
|
||||||
|
|
||||||
|
|
||||||
def chunk_directory_path(instance, filename):
|
def chunk_directory_path(instance, filename):
|
||||||
@ -98,7 +99,17 @@ class CollectionItemChunk(models.Model):
|
|||||||
return self.uid
|
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):
|
class CollectionItemRevision(models.Model):
|
||||||
|
stoken = models.OneToOneField(Stoken, on_delete=models.PROTECT)
|
||||||
uid = models.CharField(db_index=True, unique=True, blank=False, null=False,
|
uid = models.CharField(db_index=True, unique=True, blank=False, null=False,
|
||||||
max_length=43, validators=[Base64Url256BitlValidator])
|
max_length=43, validators=[Base64Url256BitlValidator])
|
||||||
item = models.ForeignKey(CollectionItem, related_name='revisions', on_delete=models.CASCADE)
|
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)
|
chunk = models.CollectionItemChunk.objects.get(uid=uid)
|
||||||
chunks_objs.append(chunk)
|
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:
|
for chunk in chunks_objs:
|
||||||
models.RevisionChunkRelation.objects.create(chunk=chunk, revision=revision)
|
models.RevisionChunkRelation.objects.create(chunk=chunk, revision=revision)
|
||||||
return revision
|
return revision
|
||||||
|
@ -35,7 +35,15 @@ import nacl.secret
|
|||||||
import nacl.hash
|
import nacl.hash
|
||||||
|
|
||||||
from . import app_settings, permissions
|
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 (
|
from .serializers import (
|
||||||
b64encode,
|
b64encode,
|
||||||
AuthenticationSignupSerializer,
|
AuthenticationSignupSerializer,
|
||||||
@ -94,18 +102,18 @@ class BaseViewSet(viewsets.ModelViewSet):
|
|||||||
user = self.request.user
|
user = self.request.user
|
||||||
return queryset.filter(members__user=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)
|
cstoken = request.GET.get('cstoken', None)
|
||||||
|
|
||||||
if cstoken is not 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
|
return None
|
||||||
|
|
||||||
def filter_by_cstoken(self, request, queryset):
|
def filter_by_cstoken(self, request, queryset):
|
||||||
cstoken_id_field = self.cstoken_id_field + '__id'
|
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:
|
if cstoken_rev is not None:
|
||||||
filter_by = {cstoken_id_field + '__gt': cstoken_rev.id}
|
filter_by = {cstoken_id_field + '__gt': cstoken_rev.id}
|
||||||
queryset = queryset.filter(**filter_by)
|
queryset = queryset.filter(**filter_by)
|
||||||
@ -116,7 +124,7 @@ class BaseViewSet(viewsets.ModelViewSet):
|
|||||||
cstoken_id_field = self.cstoken_id_field + '__id'
|
cstoken_id_field = self.cstoken_id_field + '__id'
|
||||||
|
|
||||||
new_cstoken_id = queryset.aggregate(cstoken_id=Max(cstoken_id_field))['cstoken_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
|
return queryset, new_cstoken
|
||||||
|
|
||||||
@ -139,7 +147,7 @@ class CollectionViewSet(BaseViewSet):
|
|||||||
queryset = Collection.objects.all()
|
queryset = Collection.objects.all()
|
||||||
serializer_class = CollectionSerializer
|
serializer_class = CollectionSerializer
|
||||||
lookup_field = 'uid'
|
lookup_field = 'uid'
|
||||||
cstoken_id_field = 'items__revisions'
|
cstoken_id_field = 'items__revisions__stoken'
|
||||||
|
|
||||||
def get_queryset(self, queryset=None):
|
def get_queryset(self, queryset=None):
|
||||||
if queryset is None:
|
if queryset is None:
|
||||||
@ -199,7 +207,7 @@ class CollectionItemViewSet(BaseViewSet):
|
|||||||
queryset = CollectionItem.objects.all()
|
queryset = CollectionItem.objects.all()
|
||||||
serializer_class = CollectionItemSerializer
|
serializer_class = CollectionItemSerializer
|
||||||
lookup_field = 'uid'
|
lookup_field = 'uid'
|
||||||
cstoken_id_field = 'revisions'
|
cstoken_id_field = 'revisions__stoken'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
collection_uid = self.kwargs['collection_uid']
|
collection_uid = self.kwargs['collection_uid']
|
||||||
@ -290,8 +298,8 @@ class CollectionItemViewSet(BaseViewSet):
|
|||||||
queryset, cstoken_rev = self.filter_by_cstoken(request, queryset)
|
queryset, cstoken_rev = self.filter_by_cstoken(request, queryset)
|
||||||
|
|
||||||
uids, stokens = zip(*[(item['uid'], item.get('stoken')) for item in serializer.validated_data])
|
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)
|
revs = CollectionItemRevision.objects.filter(stoken__uid__in=stokens, current=True)
|
||||||
queryset = queryset.filter(uid__in=uids).exclude(revisions__id__in=rev_ids)
|
queryset = queryset.filter(uid__in=uids).exclude(revisions__in=revs)
|
||||||
|
|
||||||
queryset, new_cstoken = self.get_queryset_cstoken(queryset)
|
queryset, new_cstoken = self.get_queryset_cstoken(queryset)
|
||||||
cstoken = cstoken_rev and cstoken_rev.uid
|
cstoken = cstoken_rev and cstoken_rev.uid
|
||||||
|
Loading…
Reference in New Issue
Block a user