More progress.
This commit is contained in:
parent
4075f775e7
commit
67fb714ddb
29
django_etesync/migrations/0005_auto_20200220_1123.py
Normal file
29
django_etesync/migrations/0005_auto_20200220_1123.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 3.0.3 on 2020-02-20 11:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_etesync', '0004_auto_20200220_1029'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitemchunk',
|
||||||
|
name='items',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='collectionitem',
|
||||||
|
name='chunks',
|
||||||
|
field=models.ManyToManyField(related_name='items', to='django_etesync.CollectionItemChunk'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='collectionitemchunk',
|
||||||
|
name='collection',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='chunks', to='django_etesync.Collection'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
49
django_etesync/migrations/0006_auto_20200220_1137.py
Normal file
49
django_etesync/migrations/0006_auto_20200220_1137.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Generated by Django 3.0.3 on 2020-02-20 11:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_etesync', '0005_auto_20200220_1123'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitem',
|
||||||
|
name='chunks',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitem',
|
||||||
|
name='current',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitem',
|
||||||
|
name='encryptionKey',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitem',
|
||||||
|
name='hmac',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitem',
|
||||||
|
name='version',
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CollectionItemSnapshot',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('version', models.PositiveSmallIntegerField()),
|
||||||
|
('encryptionKey', models.BinaryField(editable=True)),
|
||||||
|
('hmac', models.CharField(max_length=50)),
|
||||||
|
('current', models.BooleanField(db_index=True, default=True)),
|
||||||
|
('chunks', models.ManyToManyField(related_name='items', to='django_etesync.CollectionItemChunk')),
|
||||||
|
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='snapshots', to='django_etesync.CollectionItem')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'unique_together': {('item', 'current')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
28
django_etesync/migrations/0007_auto_20200220_1144.py
Normal file
28
django_etesync/migrations/0007_auto_20200220_1144.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 3.0.3 on 2020-02-20 11:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_etesync', '0006_auto_20200220_1137'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='collectionitemchunk',
|
||||||
|
name='item',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='chunks', to='django_etesync.CollectionItem'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='collectionitemchunk',
|
||||||
|
unique_together={('item', 'order')},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collectionitemchunk',
|
||||||
|
name='collection',
|
||||||
|
),
|
||||||
|
]
|
@ -35,26 +35,6 @@ class Collection(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.uid
|
return self.uid
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def current_items(self):
|
|
||||||
return self.items.filter(current=True)
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionItem(models.Model):
|
|
||||||
uid = models.CharField(db_index=True, blank=False, null=False,
|
|
||||||
max_length=44, validators=[UidValidator])
|
|
||||||
version = models.PositiveSmallIntegerField()
|
|
||||||
encryptionKey = models.BinaryField(editable=True, blank=False, null=False)
|
|
||||||
collection = models.ForeignKey(Collection, related_name='items', on_delete=models.CASCADE)
|
|
||||||
hmac = models.CharField(max_length=50, blank=False, null=False)
|
|
||||||
current = models.BooleanField(db_index=True, default=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
unique_together = ('uid', 'collection')
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.uid
|
|
||||||
|
|
||||||
|
|
||||||
def chunk_directory_path(instance, filename):
|
def chunk_directory_path(instance, filename):
|
||||||
col = instance.itemSnapshot.item.collection
|
col = instance.itemSnapshot.item.collection
|
||||||
@ -62,15 +42,49 @@ def chunk_directory_path(instance, filename):
|
|||||||
return Path('user_{}'.format(user_id), col.uid, instance.uid)
|
return Path('user_{}'.format(user_id), col.uid, instance.uid)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionItem(models.Model):
|
||||||
|
uid = models.CharField(db_index=True, blank=False, null=False,
|
||||||
|
max_length=44, validators=[UidValidator])
|
||||||
|
collection = models.ForeignKey(Collection, related_name='items', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('uid', 'collection')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.uid
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def content(self):
|
||||||
|
return self.snapshots.get(current=True)
|
||||||
|
|
||||||
|
|
||||||
class CollectionItemChunk(models.Model):
|
class CollectionItemChunk(models.Model):
|
||||||
uid = models.CharField(db_index=True, blank=False, null=False,
|
uid = models.CharField(db_index=True, blank=False, null=False,
|
||||||
max_length=44, validators=[UidValidator])
|
max_length=44, validators=[UidValidator])
|
||||||
items = models.ManyToManyField(CollectionItem, related_name='chunks')
|
item = models.ForeignKey(CollectionItem, related_name='chunks', on_delete=models.CASCADE)
|
||||||
order = models.CharField(max_length=100, blank=False, null=False)
|
order = models.CharField(max_length=100, blank=False, null=False)
|
||||||
# We probably just want to implement this manually because we can have more than one pointing to a file. chunkFile = models.FileField(upload_to=chunk_directory_path)
|
# We probably just want to implement this manually because we can have more than one pointing to a file. chunkFile = models.FileField(upload_to=chunk_directory_path)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
unique_together = ('item', 'order')
|
||||||
ordering = ['order']
|
ordering = ['order']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.uid
|
return self.uid
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionItemSnapshot(models.Model):
|
||||||
|
version = models.PositiveSmallIntegerField()
|
||||||
|
encryptionKey = models.BinaryField(editable=True, blank=False, null=False)
|
||||||
|
item = models.ForeignKey(CollectionItem, related_name='snapshots', on_delete=models.CASCADE)
|
||||||
|
chunks = models.ManyToManyField(CollectionItemChunk, related_name='items')
|
||||||
|
hmac = models.CharField(max_length=50, blank=False, null=False)
|
||||||
|
current = models.BooleanField(db_index=True, default=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('item', 'current')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '{} {} current={}'.format(self.item.uid, self.id, self.current)
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class CollectionItemChunkSerializer(serializers.ModelSerializer):
|
|||||||
fields = ('uid', )
|
fields = ('uid', )
|
||||||
|
|
||||||
|
|
||||||
class CollectionItemSerializer(serializers.ModelSerializer):
|
class CollectionItemSnapshotSerializer(serializers.ModelSerializer):
|
||||||
encryptionKey = BinaryBase64Field()
|
encryptionKey = BinaryBase64Field()
|
||||||
chunks = serializers.SlugRelatedField(
|
chunks = serializers.SlugRelatedField(
|
||||||
slug_field='uid',
|
slug_field='uid',
|
||||||
@ -73,18 +73,30 @@ class CollectionItemSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.CollectionItem
|
model = models.CollectionItemSnapshot
|
||||||
fields = ('uid', 'version', 'encryptionKey', 'chunks', 'hmac')
|
fields = ('version', 'encryptionKey', 'chunks', 'hmac')
|
||||||
|
|
||||||
|
|
||||||
class CollectionItemInlineSerializer(CollectionItemSerializer):
|
class CollectionItemSnapshotInlineSerializer(CollectionItemSnapshotSerializer):
|
||||||
chunksData = serializers.SerializerMethodField('get_inline_chunks_from_context')
|
chunksData = serializers.SerializerMethodField('get_inline_chunks_from_context')
|
||||||
|
|
||||||
class Meta(CollectionItemSerializer.Meta):
|
class Meta(CollectionItemSnapshotSerializer.Meta):
|
||||||
fields = CollectionItemSerializer.Meta.fields + ('chunksData', )
|
fields = CollectionItemSnapshotSerializer.Meta.fields + ('chunksData', )
|
||||||
|
|
||||||
def get_inline_chunks_from_context(self, obj):
|
def get_inline_chunks_from_context(self, obj):
|
||||||
request = self.context.get('request', None)
|
request = self.context.get('request', None)
|
||||||
if request is not None:
|
if request is not None:
|
||||||
return ['SomeInlineData', 'Somemoredata']
|
return ['SomeInlineData', 'Somemoredata']
|
||||||
return 'readOnly'
|
return 'readOnly'
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionItemSerializer(serializers.ModelSerializer):
|
||||||
|
content = CollectionItemSnapshotSerializer(read_only=True, many=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.CollectionItem
|
||||||
|
fields = ('uid', 'content')
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionItemInlineSerializer(CollectionItemSerializer):
|
||||||
|
content = CollectionItemSnapshotInlineSerializer(read_only=True, many=False)
|
||||||
|
@ -24,6 +24,7 @@ from django.views.decorators.http import require_POST
|
|||||||
|
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
from rest_framework import parsers
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from . import app_settings, paginators
|
from . import app_settings, paginators
|
||||||
@ -143,3 +144,40 @@ class CollectionItemViewSet(BaseViewSet):
|
|||||||
def partial_update(self, request, collection_uid=None, uid=None):
|
def partial_update(self, request, collection_uid=None, uid=None):
|
||||||
# FIXME: implement, or should it be implemented elsewhere?
|
# FIXME: implement, or should it be implemented elsewhere?
|
||||||
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionItemChunkViewSet(viewsets.ViewSet):
|
||||||
|
allowed_methods = ['GET', 'POST']
|
||||||
|
authentication_classes = BaseViewSet.authentication_classes
|
||||||
|
permission_classes = BaseViewSet.permission_classes
|
||||||
|
parser_classes = (parsers.MultiPartParser, )
|
||||||
|
lookup_field = 'uid'
|
||||||
|
|
||||||
|
def create(self, request, collection_uid=None):
|
||||||
|
# FIXME: we are potentially not getting the correct queryset
|
||||||
|
collection_object = Collection.objects.get(uid=collection_uid)
|
||||||
|
|
||||||
|
many = isinstance(request.data, list)
|
||||||
|
serializer = self.serializer_class(data=request.data, many=many)
|
||||||
|
if serializer.is_valid():
|
||||||
|
try:
|
||||||
|
serializer.save(collection=collection_object)
|
||||||
|
except IntegrityError:
|
||||||
|
content = {'code': 'integrity_error'}
|
||||||
|
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
return Response({}, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
def destroy(self, request, collection_uid=None, uid=None):
|
||||||
|
# FIXME: implement
|
||||||
|
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
def update(self, request, collection_uid=None, uid=None):
|
||||||
|
# FIXME: implement, or should it be implemented elsewhere?
|
||||||
|
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
def partial_update(self, request, collection_uid=None, uid=None):
|
||||||
|
# FIXME: implement, or should it be implemented elsewhere?
|
||||||
|
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
Loading…
Reference in New Issue
Block a user