mirror of
https://github.com/etesync/server
synced 2024-11-26 02:38:15 +00:00
Collections: add support for collection types.
We also added the field for invitations, as it's needed for collections to work.
This commit is contained in:
parent
acd22b9b47
commit
5d8a92f000
29
django_etebase/migrations/0031_auto_20201013_1336.py
Normal file
29
django_etebase/migrations/0031_auto_20201013_1336.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Generated by Django 3.1.1 on 2020-10-13 13:36
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('django_etebase', '0030_auto_20200922_0832'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CollectionType',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('uid', models.BinaryField(db_index=True, editable=True)),
|
||||
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='collectionmember',
|
||||
name='collectionType',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='django_etebase.collectiontype'),
|
||||
),
|
||||
]
|
18
django_etebase/migrations/0032_auto_20201013_1409.py
Normal file
18
django_etebase/migrations/0032_auto_20201013_1409.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.1.1 on 2020-10-13 14:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_etebase', '0031_auto_20201013_1336'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='collectiontype',
|
||||
name='uid',
|
||||
field=models.BinaryField(db_index=True, editable=True, unique=True),
|
||||
),
|
||||
]
|
@ -30,6 +30,11 @@ from .exceptions import EtebaseValidationError
|
||||
UidValidator = RegexValidator(regex=r'^[a-zA-Z0-9\-_]{20,}$', message='Not a valid UID')
|
||||
|
||||
|
||||
class CollectionType(models.Model):
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
uid = models.BinaryField(editable=True, blank=False, null=False, db_index=True, unique=True)
|
||||
|
||||
|
||||
class Collection(models.Model):
|
||||
main_item = models.OneToOneField('CollectionItem', related_name='parent', null=True, on_delete=models.SET_NULL)
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
@ -162,6 +167,7 @@ class CollectionMember(models.Model):
|
||||
collection = models.ForeignKey(Collection, related_name='members', on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
encryptionKey = models.BinaryField(editable=True, blank=False, null=False)
|
||||
collectionType = models.ForeignKey(CollectionType, on_delete=models.PROTECT, null=True)
|
||||
accessLevel = models.IntegerField(
|
||||
choices=AccessLevels.choices,
|
||||
default=AccessLevels.READ_ONLY,
|
||||
|
@ -86,6 +86,15 @@ class CollectionEncryptionKeyField(BinaryBase64Field):
|
||||
return None
|
||||
|
||||
|
||||
class CollectionTypeField(BinaryBase64Field):
|
||||
def get_attribute(self, instance):
|
||||
request = self.context.get('request', None)
|
||||
if request is not None:
|
||||
collection_type = instance.members.get(user=request.user).collectionType
|
||||
return collection_type and collection_type.uid
|
||||
return None
|
||||
|
||||
|
||||
class UserSlugRelatedField(serializers.SlugRelatedField):
|
||||
def get_queryset(self):
|
||||
view = self.context.get('view', None)
|
||||
@ -256,8 +265,15 @@ class CollectionItemBulkGetSerializer(BetterErrorsMixin, serializers.ModelSerial
|
||||
fields = ('uid', 'etag')
|
||||
|
||||
|
||||
class CollectionListMultiSerializer(BetterErrorsMixin, serializers.Serializer):
|
||||
collectionTypes = serializers.ListField(
|
||||
child=BinaryBase64Field()
|
||||
)
|
||||
|
||||
|
||||
class CollectionSerializer(BetterErrorsMixin, serializers.ModelSerializer):
|
||||
collectionKey = CollectionEncryptionKeyField()
|
||||
collectionType = CollectionTypeField()
|
||||
accessLevel = serializers.SerializerMethodField('get_access_level_from_context')
|
||||
stoken = serializers.CharField(read_only=True)
|
||||
|
||||
@ -265,7 +281,7 @@ class CollectionSerializer(BetterErrorsMixin, serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = models.Collection
|
||||
fields = ('item', 'accessLevel', 'collectionKey', 'stoken')
|
||||
fields = ('item', 'accessLevel', 'collectionKey', 'collectionType', 'stoken')
|
||||
|
||||
def get_access_level_from_context(self, obj):
|
||||
request = self.context.get('request', None)
|
||||
@ -276,6 +292,7 @@ class CollectionSerializer(BetterErrorsMixin, serializers.ModelSerializer):
|
||||
def create(self, validated_data):
|
||||
"""Function that's called when this serializer creates an item"""
|
||||
collection_key = validated_data.pop('collectionKey')
|
||||
collection_type = validated_data.pop('collectionType')
|
||||
|
||||
main_item_data = validated_data.pop('main_item')
|
||||
etag = main_item_data.pop('etag')
|
||||
@ -297,11 +314,16 @@ class CollectionSerializer(BetterErrorsMixin, serializers.ModelSerializer):
|
||||
|
||||
process_revisions_for_item(main_item, revision_data)
|
||||
|
||||
user = validated_data.get('owner')
|
||||
|
||||
collection_type_obj, _ = models.CollectionType.objects.get_or_create(uid=collection_type, owner=user)
|
||||
|
||||
models.CollectionMember(collection=instance,
|
||||
stoken=models.Stoken.objects.create(),
|
||||
user=validated_data.get('owner'),
|
||||
user=user,
|
||||
accessLevel=models.AccessLevels.ADMIN,
|
||||
encryptionKey=collection_key,
|
||||
collectionType=collection_type_obj,
|
||||
).save()
|
||||
|
||||
return instance
|
||||
@ -381,6 +403,7 @@ class CollectionInvitationSerializer(BetterErrorsMixin, serializers.ModelSeriali
|
||||
|
||||
|
||||
class InvitationAcceptSerializer(BetterErrorsMixin, serializers.Serializer):
|
||||
collectionType = BinaryBase64Field()
|
||||
encryptionKey = BinaryBase64Field()
|
||||
|
||||
def create(self, validated_data):
|
||||
@ -388,13 +411,18 @@ class InvitationAcceptSerializer(BetterErrorsMixin, serializers.Serializer):
|
||||
with transaction.atomic():
|
||||
invitation = self.context['invitation']
|
||||
encryption_key = validated_data.get('encryptionKey')
|
||||
collection_type = validated_data.pop('collectionType')
|
||||
|
||||
user = invitation.user
|
||||
collection_type_obj, _ = models.CollectionType.objects.get_or_create(uid=collection_type, owner=user)
|
||||
|
||||
member = models.CollectionMember.objects.create(
|
||||
collection=invitation.collection,
|
||||
stoken=models.Stoken.objects.create(),
|
||||
user=invitation.user,
|
||||
user=user,
|
||||
accessLevel=invitation.accessLevel,
|
||||
encryptionKey=encryption_key,
|
||||
collectionType=collection_type_obj,
|
||||
)
|
||||
|
||||
models.CollectionMemberRemoved.objects.filter(
|
||||
|
@ -66,6 +66,7 @@ from .serializers import (
|
||||
CollectionItemDepSerializer,
|
||||
CollectionItemRevisionSerializer,
|
||||
CollectionItemChunkSerializer,
|
||||
CollectionListMultiSerializer,
|
||||
CollectionMemberSerializer,
|
||||
CollectionInvitationSerializer,
|
||||
InvitationAcceptSerializer,
|
||||
@ -210,6 +211,21 @@ class CollectionViewSet(BaseViewSet):
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
queryset = self.get_queryset()
|
||||
return self.list_common(request, queryset, *args, **kwargs)
|
||||
|
||||
@action_decorator(detail=False, methods=['POST'])
|
||||
def list_multi(self, request, *args, **kwargs):
|
||||
serializer = CollectionListMultiSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
collection_types = serializer.validated_data['collectionTypes']
|
||||
|
||||
queryset = self.get_queryset()
|
||||
queryset = queryset.filter(members__collectionType__uid__in=collection_types)
|
||||
|
||||
return self.list_common(request, queryset, *args, **kwargs)
|
||||
|
||||
def list_common(self, request, queryset, *args, **kwargs):
|
||||
result, new_stoken_obj, done = self.filter_by_stoken_and_limit(request, queryset)
|
||||
new_stoken = new_stoken_obj and new_stoken_obj.uid
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user