From 356329f266059e1a4658e6c9c401b043006fcd09 Mon Sep 17 00:00:00 2001 From: Pawel Kowalski Date: Wed, 5 Sep 2018 13:14:09 +0200 Subject: [PATCH] Add first mutation and some util functions --- server/api/schema.py | 6 ++- server/api/utils.py | 33 ++++++++++++ server/book/schema/mutations.py | 90 +++++++++++++++------------------ 3 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 server/api/utils.py diff --git a/server/api/schema.py b/server/api/schema.py index 536b7f3c..2c7fe233 100644 --- a/server/api/schema.py +++ b/server/api/schema.py @@ -6,6 +6,8 @@ from graphene_django.debug import DjangoDebug # Keep this import exactly here, it's necessary for StreamField conversion from api import graphene_wagtail + +from book.schema.mutations import BookMutations from book.schema.queries import BookQuery from objectives.schema import ObjectivesQuery from rooms.schema import RoomsQuery @@ -18,10 +20,10 @@ class Query(RoomsQuery, ObjectivesQuery, BookQuery, graphene.ObjectType): debug = graphene.Field(DjangoDebug, name='__debug') -class Mutation(graphene.ObjectType): +class Mutation(graphene.ObjectType, BookMutations): if settings.DEBUG: debug = graphene.Field(DjangoDebug, name='__debug') -schema = graphene.Schema(query=Query) +schema = graphene.Schema(query=Query, mutation=Mutation) diff --git a/server/api/utils.py b/server/api/utils.py new file mode 100644 index 00000000..f0749075 --- /dev/null +++ b/server/api/utils.py @@ -0,0 +1,33 @@ +"""Script defined to create helper functions for graphql schema.""" +# https://medium.com/@jamesvaresamuel/mutation-and-query-in-graphql-using-python-django-part-2-79d9852a1092 +from graphene_django.filter import DjangoFilterConnectionField +from graphql_relay.node.node import from_global_id + + +def get_object(object_name, relayId, otherwise=None): + try: + return object_name.objects.get(pk=from_global_id(relayId)[1]) + except: + return otherwise + + +def update_create_instance(instance, args, exception=['id']): + if instance: + [setattr(instance, key, value) for key, value in args.items() if key not in exception] + + # caution if you literally cloned this project, then be sure to have + # elasticsearch running as every saved instance must go through + # elasticsearch according to the way this project is configured. + instance.save() + + return instance + + +def get_errors(e): + # transform django errors to redux errors + # django: {"key1": [value1], {"key2": [value2]}} + # redux: ["key1", "value1", "key2", "value2"] + fields = e.message_dict.keys() + messages = ['; '.join(m) for m in e.message_dict.values()] + errors = [i for pair in zip(fields, messages) for i in pair] + return errors diff --git a/server/book/schema/mutations.py b/server/book/schema/mutations.py index 94f8cb39..d8df883f 100644 --- a/server/book/schema/mutations.py +++ b/server/book/schema/mutations.py @@ -1,27 +1,54 @@ import graphene +from django.core.exceptions import ValidationError + +from api.utils import get_errors +from book.models import ContentBlock +from book.schema.queries import ContentBlockNode class MutateContentBlock(graphene.relay.ClientIDMutation): class Input: - id = None - - title = graphene.String() + id = graphene.ID() type = graphene.String() + title = graphene.String() - module_slug = graphene.String(required=True) - # text params - # learnings_text = graphene.String() - # impact_text = graphene.String() - # measurement_text = graphene.String() - # measures_text = graphene.String() - # time_frame_text = graphene.String() - # resources_skills_text = graphene.String() - # commitment_support_text = graphene.String() + errors = graphene.List(graphene.String) + content_block = graphene.Field(ContentBlockNode) + + # updated_title = graphene.String() + # updated_type = graphene.String() # user_module_progress = graphene.Field(UserModuleProgressNode) @classmethod def mutate_and_get_payload(cls, *args, **kwargs): + try: + + type_param = kwargs['type'] + title = kwargs['title'] + + cb = ContentBlock(type=type_param, title=title) + + # 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=cb) + + except ValidationError as e: + errors = get_errors(e) + except Exception as e: + errors = ['Error: {}'.format(e)] + + return cls(updated_image=None, tags=None, errors=errors) + # user_module_progress = get_object_or_404( # UserModuleProgress, # user=get_current_user(), @@ -32,44 +59,7 @@ class MutateContentBlock(graphene.relay.ClientIDMutation): # setattr(user_module_progress, k, v) # # user_module_progress.save() - return cls(user_module_progress=user_module_progress) - - -# class UpdateImage(relay.ClientIDMutation): -# class Input: -# image = graphene.Argument(ImageUpdateInput) -# id = graphene.String(required=True) -# -# errors = graphene.List(graphene.String) -# updated_image = graphene.Field(ImageNode) -# tags = graphene.List(TagNode) -# -# @classmethod -# def mutate_and_get_payload(cls, *args, **kwargs): -# try: -# 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(updated_image=updated_image, tags=Tag.objects.all()) -# except ValidationError as e: -# errors = get_errors(e) -# except Exception as e: -# errors = ['Error: {}'.format(e)] -# else: -# errors = ['image not found'] -# -# return cls(updated_image=None, tags=None, errors=errors) class BookMutations(object): - # start_module_progress = StartModuleProgress.Field() - # delete_module_progress = DeleteModuleProgress.Field() - define_action_plan = MutateContentBlock.Field() + mutate_content_block = MutateContentBlock.Field()