import json import bleach import graphene from graphene import relay from django.core.exceptions import ValidationError from api.utils import get_object, get_errors from book.models import ContentBlock, Chapter from book.schema.inputs import ContentBlockInput from book.schema.queries import ContentBlockNode def handle_content_blocks(content_data): new_contents = [] for content in content_data: # todo: add all the content blocks # todo: sanitize user inputs! if content['type'] == 'text_block': new_contents.append({ 'type': 'text_block', 'value': { 'text': '

{}

'.format(bleach.clean(content['text'])) }}) elif content['type'] == 'student_entry': pass elif content['type'] == 'image_block': pass elif content['type'] == 'link_block': pass elif content['type'] == 'task': pass elif content['type'] == 'video_block': pass elif content['type'] == 'document_block': pass return new_contents class MutateContentBlock(relay.ClientIDMutation): class Input: id = graphene.ID() type = graphene.String() title = graphene.String() contents = graphene.String() errors = graphene.List(graphene.String) content_block = graphene.Field(ContentBlockNode) # updated_title = graphene.String() # updated_type = graphene.String() @classmethod def mutate_and_get_payload(cls, *args, **kwargs): try: id_param = kwargs['id'] type_param = kwargs['type'] title = kwargs['title'] contents_data = kwargs['contents'] new_content_block = ContentBlock(type=type_param, title=title, contents=contents_data) content_block = get_object(ContentBlock, id_param) content_block.add_sibling(instance=new_content_block, pos='right') # ContentBlock.objects.get() # cb.add_sibling() new_content_block.save() # image_instance = get_object(Image, kwargs['id']) # if image_instance: # image_data = kwargs.get('image') # updated_image = update_create_instance(image_instance, image_data, exception=['id', 'tags']) # tag_slugs = image_data.get('tag_slugs', '') # if tag_slugs is not None: # tag_slugs = [t.strip() for t in tag_slugs.split(',') if t.strip()] # tags = list(Tag.objects.filter(slug__in=tag_slugs)) # tag_slugs = [t for t in tag_slugs if t not in [e.slug for e in tags]] # updated_image.tags.set(*(tags + tag_slugs)) return cls(content_block=new_content_block) except ValidationError as e: errors = get_errors(e) except Exception as e: errors = ['Error: {}'.format(e)] return cls(content_block=None, errors=errors) # todo: handle mutation for add and for edit (with the ID of the content block instead of a sibling) # todo: merge with above class, for error handling and sibling assignment class AddContentBlock(relay.ClientIDMutation): class Input: content_block = graphene.Argument(ContentBlockInput) # todo: handle both of these differently, one for a new chapter maybe parent = graphene.ID() after = graphene.ID() new_content_block = graphene.Field(ContentBlockNode) @classmethod def mutate_and_get_payload(cls, root, info, **args): content_block_data = args.get('content_block') title = content_block_data.get('title') new_content_block = ContentBlock(title=title) parent = Chapter.objects.get( pk=18).specific # atm just "1.1 Lehrbeginn" / todo: dynamic, refactor in above class parent.add_child(instance=new_content_block) revision = new_content_block.save_revision() revision.publish() contents = content_block_data.get('contents') new_contents = handle_content_blocks(contents) new_content_block.contents = json.dumps(new_contents) new_content_block.save() return cls(new_content_block=new_content_block) class BookMutations(object): mutate_content_block = MutateContentBlock.Field() add_content_block = AddContentBlock.Field()