import graphene from django.core.exceptions import PermissionDenied from graphene import relay from graphql_relay import to_global_id from api.utils import get_object from rooms.inputs import UpdateRoomArgument, AddRoomArgument, AddRoomEntryArgument, UpdateRoomEntryArgument from rooms.models import Comment, Room, RoomEntry from rooms.schema import CommentNode, RoomNode, RoomEntryNode from rooms.serializers import RoomSerializer, RoomEntrySerializer from users.models import SchoolClass, SchoolClassMember class MutateRoom(relay.ClientIDMutation): errors = graphene.List(graphene.String) room = graphene.Field(RoomNode) @classmethod def mutate_and_get_payload(cls, *args, **kwargs): room_data = kwargs.get('room') school_class = get_object(SchoolClass, room_data.get('school_class').get('id')) room_data['school_class'] = school_class.id if room_data.get('id') is not None: room = get_object(Room, room_data['id']) serializer = RoomSerializer(room, data=room_data) else: serializer = RoomSerializer(data=room_data) if serializer.is_valid(): serializer.save() return cls(room=serializer.instance, errors=None) return cls(room=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) class AddRoom(MutateRoom): class Input: room = graphene.Argument(AddRoomArgument) # NB: can't be named AddRoomInput, otherwise graphene complains @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): user = info.context.user if not user.is_teacher(): return cls(room=None, errors=['not allowed']) room_data = kwargs.get('room') school_class_id = user.selected_class.id room_data['school_class'] = school_class_id serializer = RoomSerializer(data=room_data) if serializer.is_valid(): serializer.save() return cls(room=serializer.instance) return cls(room=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) class UpdateRoom(MutateRoom): class Input: room = graphene.Argument(UpdateRoomArgument) # NB: can't be named ChangeRoomInput, otherwise graphene complains class DeleteRoom(relay.ClientIDMutation): class Input: id = graphene.ID(required=True) success = graphene.Boolean() errors = graphene.List(graphene.String) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): id = kwargs.get('id') room = get_object(Room, id) user = info.context.user if not user.has_perm('users.can_manage_school_class_content'): raise PermissionDenied('Missing permissions') if room.school_class not in user.school_classes.all(): raise PermissionDenied('Permission denied: Incorrect school classes') room.delete() return cls(success=True) class MutateRoomEntry(relay.ClientIDMutation): room_entry = graphene.Field(RoomEntryNode) errors = graphene.List(graphene.String) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): room_entry_data = kwargs.get('room_entry') room = None room_slug = room_entry_data.get('room_slug') if room_slug is not None: room = Room.objects.get(slug=room_slug) room_entry_data['room'] = room.id if room_entry_data.get('slug') is not None: serializer = cls.update_room_entry(info, room_entry_data) else: serializer = cls.add_room_entry(info, room_entry_data, room) if serializer.is_valid(): serializer.save() return cls(room_entry=serializer.instance) return cls(room_entry=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) @classmethod def update_room_entry(cls, info, room_entry_data): instance = RoomEntry.objects.get(slug=room_entry_data.get('slug')) if not instance.room.school_class.is_user_in_schoolclass(info.context.user): raise Exception('You are in the wrong class') if instance.author.pk != info.context.user.pk: raise Exception('You are not the author') return RoomEntrySerializer(instance, data=room_entry_data, partial=True) @classmethod def add_room_entry(cls, info, room_entry_data, room): if not room or not room.school_class.is_user_in_schoolclass(info.context.user): raise PermissionDenied('You are in the wrong class') room_entry_data['author'] = info.context.user.pk return RoomEntrySerializer(data=room_entry_data) class AddRoomEntry(MutateRoomEntry): class Input: room_entry = graphene.Argument(AddRoomEntryArgument) class UpdateRoomEntry(MutateRoomEntry): class Input: room_entry = graphene.Argument(UpdateRoomEntryArgument) class DeleteRoomEntry(relay.ClientIDMutation): class Input: slug = graphene.String(required=True) success = graphene.Boolean() room_slug = graphene.String() room_id = graphene.ID() errors = graphene.List(graphene.String) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): slug = kwargs.get('slug') room_entry = RoomEntry.objects.get(slug=slug) if room_entry.author.pk != info.context.user.pk: raise Exception('You are not the owner of this room entry') room_id = to_global_id('RoomNode', room_entry.room.pk) room_slug = room_entry.room.slug room_entry.delete() return cls(success=True, room_id=room_id, room_slug=room_slug) class UpdateRoomVisibility(relay.ClientIDMutation): class Input: id = graphene.ID(required=True) restricted = graphene.Boolean(required=True) success = graphene.Boolean() room = graphene.Field(RoomNode) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): id = kwargs.get('id') restricted = kwargs.get('restricted') user = info.context.user room = get_object(Room, id) if not user.is_teacher() or not SchoolClassMember.objects.filter(active=True, user=user, school_class=room.school_class).exists(): raise Exception('You are not permitted to do this') room.restricted = restricted room.save() return cls(success=True, room=room) class AddComment(relay.ClientIDMutation): class Input: comment = graphene.String(required=True) room_entry = graphene.ID(required=True) success = graphene.Boolean() comment = graphene.Field(CommentNode) @classmethod def mutate_and_get_payload(cls, root, info, **args): room_entry_id = args.get('room_entry') text = args.get('comment') user = info.context.user room_entry = get_object(RoomEntry, room_entry_id) comment = Comment.objects.create(text=text, room_entry=room_entry, owner=user) return cls(success=True, comment=comment) class RoomMutations: update_room = UpdateRoom.Field() add_room = AddRoom.Field() delete_room = DeleteRoom.Field() add_room_entry = AddRoomEntry.Field() delete_room_entry = DeleteRoomEntry.Field() update_room_entry = UpdateRoomEntry.Field() add_comment = AddComment.Field() update_room_visibility = UpdateRoomVisibility.Field()