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 Room, RoomEntry from rooms.schema import RoomNode, RoomEntryNode from rooms.serializers import RoomSerializer, RoomEntrySerializer from users.models import SchoolClass 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): if not info.context.user.has_perm('users.can_manage_school_class_content'): return cls(room=None, errors=['not allowed']) room_data = kwargs.get('room') room_data['school_class'] = get_object(SchoolClass, room_data.get('school_class').id).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') if room_entry_data.get('room') is not None: room_entry_data['room'] = get_object(Room, room_entry_data.get('room')).id if room_entry_data.get('id') is not None: # update path instance = get_object(RoomEntry, room_entry_data.get('id')) 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') serializer = RoomEntrySerializer(instance, data=room_entry_data, partial=True) else: # add path room_entry_data['author'] = info.context.user.pk serializer = RoomEntrySerializer(data=room_entry_data) 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()]) 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: id = graphene.ID(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): id = kwargs.get('id') room_entry = get_object(RoomEntry, id) 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 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()