import json import graphene from django.core.exceptions import ValidationError from graphene import relay from graphql_relay import from_global_id from api.utils import get_object, get_errors from books.models import ContentBlock, Chapter, SchoolClass from books.schema.inputs import ContentBlockInput from books.schema.queries import ContentBlockNode from core.utils import set_hidden_for, set_visible_for from .utils import handle_content_block, set_user_defined_block_type class MutateContentBlock(relay.ClientIDMutation): class Input: id = graphene.ID(required=True) content_block = graphene.Argument(ContentBlockInput) content_block = graphene.Field(ContentBlockNode) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): try: id_param = kwargs['id'] content_block_data = kwargs.get('content_block') # type_param = content_block_data.get('type') title = content_block_data.get('title', None) contents = content_block_data.get('contents', None) visibility_list = content_block_data.get('visibility', None) content_block = get_object(ContentBlock, id_param) block_type = content_block_data.get('type') if block_type is not None: # only change the type if the user has set a type content_block.type = set_user_defined_block_type(block_type) module = content_block.get_parent().get_parent().specific if visibility_list is not None: if content_block.user_created: set_visible_for(content_block, visibility_list) else: set_hidden_for(content_block, visibility_list) if title is not None: content_block.title = title if contents is not None: content_block.contents = json.dumps([handle_content_block(c, info.context, module) for c in contents]) content_block.save() return cls(content_block=content_block) except ValidationError as e: errors = get_errors(e) raise errors except Exception as e: errors = ['Error: {}'.format(e)] raise errors class AddContentBlock(relay.ClientIDMutation): class Input: content_block = graphene.Argument(ContentBlockInput) parent = graphene.ID() # ID of chapter node; new content block will be inserted at the start of it after = graphene.ID() # ID of content block node; new content block will be inserted after this content block node new_content_block = graphene.Field(ContentBlockNode) errors = graphene.List(graphene.String) @classmethod def create_content_block(cls, content_block_data, parent=None, after=None, context=None): if after is None and parent is None: raise Exception('Define either a parent or a sibling id') title = content_block_data.get('title') contents = content_block_data.get('contents') block_type = set_user_defined_block_type(content_block_data.get('type', ContentBlock.NORMAL)) new_content_block = ContentBlock(title=title, user_created=True, owner=context.user, type=block_type) if parent is not None: parent_chapter = get_object(Chapter, parent).specific first_sibling = parent_chapter.get_first_child() if first_sibling is not None: first_sibling.add_sibling(instance=new_content_block, pos='left') else: parent_chapter.add_child(instance=new_content_block) elif after is not None: sibling = get_object(ContentBlock, after).specific sibling.add_sibling(instance=new_content_block, pos='right') revision = new_content_block.save_revision() revision.publish() new_content_block.save() module = new_content_block.get_parent().get_parent().specific new_content_block.contents = json.dumps([handle_content_block(c, context, module) for c in contents]) # can only do this after the content block has been saved new_content_block.save() return new_content_block @classmethod def mutate_and_get_payload(cls, root, info, **args): try: parent = args.get('parent', None) after = args.get('after', None) new_content_block = cls.create_content_block(content_block_data=args.get('content_block'), parent=parent, after=after, context=info.context) return cls(new_content_block=new_content_block) except ValidationError as e: errors = get_errors(e) except Exception as e: errors = ['Error: {}'.format(e)] return cls(new_content_block=None, errors=errors) class DeleteContentBlock(relay.ClientIDMutation): class Input: id = graphene.ID(required=True) success = graphene.Boolean() errors = graphene.String() @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): id = from_global_id(kwargs.get('id'))[1] user = info.context.user try: content_block = ContentBlock.objects.get(pk=id, owner=user) content_block.delete() return cls(success=True) except ContentBlock.DoesNotExist: return cls(success=False, errors='Content block not found')