From a965a76c36081958ee9f3a495ac295e0240f9045 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Sun, 24 May 2020 18:19:22 +0300 Subject: [PATCH] Invitation: move outgoing invitations to invite/outgoing. --- django_etesync/permissions.py | 8 +++++-- django_etesync/serializers.py | 15 +++++-------- django_etesync/views.py | 42 +++++++++++++++++++++-------------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/django_etesync/permissions.py b/django_etesync/permissions.py index 29806c6..c371743 100644 --- a/django_etesync/permissions.py +++ b/django_etesync/permissions.py @@ -16,6 +16,11 @@ from rest_framework import permissions from django_etesync.models import Collection, AccessLevels +def is_collection_admin(collection, user): + member = collection.members.filter(user=user).first() + return (member is not None) and (member.accessLevel == AccessLevels.ADMIN) + + class IsCollectionAdmin(permissions.BasePermission): """ Custom permission to only allow owners of a collection to view it @@ -27,8 +32,7 @@ class IsCollectionAdmin(permissions.BasePermission): collection_uid = view.kwargs['collection_uid'] try: collection = view.get_collection_queryset().get(uid=collection_uid) - member = collection.members.filter(user=request.user).first() - return (member is not None) and (member.accessLevel == AccessLevels.ADMIN) + return is_collection_admin(collection, request.user) except Collection.DoesNotExist: # If the collection does not exist, we want to 404 later, not permission denied. return True diff --git a/django_etesync/serializers.py b/django_etesync/serializers.py index 95dbc1f..29068fa 100644 --- a/django_etesync/serializers.py +++ b/django_etesync/serializers.py @@ -268,29 +268,24 @@ class CollectionInvitationSerializer(serializers.ModelSerializer): slug_field=User.USERNAME_FIELD, queryset=User.objects ) - collection = serializers.SerializerMethodField('get_collection') - fromPubkey = serializers.SerializerMethodField('get_from_pubkey') + collection = serializers.CharField(source='collection.uid') + fromPubkey = BinaryBase64Field(source='fromMember.user.userinfo.pubkey', read_only=True) signedEncryptionKey = BinaryBase64Field() class Meta: model = models.CollectionInvitation fields = ('username', 'uid', 'collection', 'signedEncryptionKey', 'accessLevel', 'fromPubkey', 'version') - def get_collection(self, obj): - return obj.collection.uid - - def get_from_pubkey(self, obj): - return b64encode(obj.fromMember.user.userinfo.pubkey) - def validate_user(self, value): request = self.context['request'] - if request.user == value: + if request.user == value.lower(): raise serializers.ValidationError('Inviting yourself is not allowed') + return value def create(self, validated_data): - collection = self.context['collection'] request = self.context['request'] + collection = validated_data.pop('collection') member = collection.members.get(user=request.user) diff --git a/django_etesync/views.py b/django_etesync/views.py index 7130eae..bde22e4 100644 --- a/django_etesync/views.py +++ b/django_etesync/views.py @@ -16,6 +16,7 @@ import json from django.conf import settings from django.contrib.auth import get_user_model +from django.core.exceptions import PermissionDenied from django.db import transaction, IntegrityError from django.db.models import Max from django.http import HttpResponseBadRequest, HttpResponse, Http404 @@ -426,9 +427,9 @@ class CollectionMemberViewSet(BaseViewSet): return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) -class CollectionInvitationViewSet(BaseViewSet): +class InvitationOutgoingViewSet(BaseViewSet): allowed_methods = ['GET', 'POST', 'PUT', 'DELETE'] - permission_classes = BaseViewSet.permission_classes + (permissions.IsCollectionAdmin, ) + permission_classes = BaseViewSet.permission_classes queryset = CollectionInvitation.objects.all() serializer_class = CollectionInvitationSerializer lookup_field = 'uid' @@ -436,29 +437,36 @@ class CollectionInvitationViewSet(BaseViewSet): def get_serializer_context(self): context = super().get_serializer_context() - collection_uid = self.kwargs['collection_uid'] - try: - collection = self.get_collection_queryset(Collection.objects).get(uid=collection_uid) - except Collection.DoesNotExist: - raise Http404('Collection does not exist') - - context.update({'request': self.request, 'collection': collection}) + context.update({'request': self.request}) return context def get_queryset(self, queryset=None): - collection_uid = self.kwargs['collection_uid'] - try: - collection = self.get_collection_queryset(Collection.objects).get(uid=collection_uid) - except Collection.DoesNotExist: - raise Http404('Collection does not exist') - if queryset is None: queryset = type(self).queryset - return queryset.filter(fromMember__collection=collection) + return queryset.filter(fromMember__user=self.request.user) + + def create(self, request, *args, **kwargs): + serializer = self.serializer_class(data=request.data, context=self.get_serializer_context()) + if serializer.is_valid(): + collection_uid = serializer.validated_data.get('collection', {}).get('uid') + + try: + collection = self.get_collection_queryset(Collection.objects).get(uid=collection_uid) + except Collection.DoesNotExist: + raise Http404('Collection does not exist') + + if not permissions.is_collection_admin(collection, request.user): + raise PermissionDenied('User is not an admin of this collection') + + serializer.save(collection=collection) + + return Response({}, status=status.HTTP_201_CREATED) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @action_decorator(detail=False, allowed_methods=['GET'], methods=['GET']) - def fetch_user_profile(self, request, collection_uid=None): + def fetch_user_profile(self, request): username = request.GET.get('username') kwargs = {'owner__' + User.USERNAME_FIELD: username} user_info = get_object_or_404(UserInfo.objects.all(), **kwargs)