From ce86e45743c949a8b3cae09b3f22983ee17f6096 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Thu, 11 Oct 2018 11:39:50 +0200 Subject: [PATCH] Add content block deletion mutation --- client/src/components/Chapter.vue | 1 + client/src/components/ContentBlock.vue | 43 ++++++++++++++++--- client/src/graphql/client.js | 1 + .../gql/allContentBlocksCacheQuery.gql | 7 +++ client/src/graphql/gql/chapterQuery.gql | 6 +++ .../graphql/gql/fragments/chapterParts.gql | 13 ++++++ .../gql/fragments/contentBlockParts.gql | 1 + client/src/graphql/gql/moduleDetailsQuery.gql | 13 +----- .../gql/mutations/deleteContentBlock.gql | 12 ++++++ server/books/schema/mutations/contentblock.py | 21 +++++++++ server/books/schema/mutations/main.py | 3 +- server/books/schema/queries.py | 4 ++ 12 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 client/src/graphql/gql/allContentBlocksCacheQuery.gql create mode 100644 client/src/graphql/gql/chapterQuery.gql create mode 100644 client/src/graphql/gql/fragments/chapterParts.gql create mode 100644 client/src/graphql/gql/mutations/deleteContentBlock.gql diff --git a/client/src/components/Chapter.vue b/client/src/components/Chapter.vue index 00e6bbf9..59709e49 100644 --- a/client/src/components/Chapter.vue +++ b/client/src/components/Chapter.vue @@ -9,6 +9,7 @@ diff --git a/client/src/components/ContentBlock.vue b/client/src/components/ContentBlock.vue index fc0c766a..fdc7f214 100644 --- a/client/src/components/ContentBlock.vue +++ b/client/src/components/ContentBlock.vue @@ -2,7 +2,7 @@

{{contentBlock.title}} {{contentBlock.userCreated}}

@@ -45,10 +48,13 @@ import VisibilityPopover from '@/components/VisibilityPopover'; import EyeIcon from '@/components/icons/EyeIcon'; import PenIcon from '@/components/icons/PenIcon'; + import TrashIcon from '@/components/icons/TrashIcon'; import ME_QUERY from '@/graphql/gql/meQuery.gql'; + import CHAPTER_QUERY from '@/graphql/gql/chapterQuery.gql'; + import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql'; export default { - props: ['contentBlock'], + props: ['contentBlock', 'parent'], components: { 'text_block': TextBlock, @@ -63,7 +69,8 @@ AddContentBlockButton, VisibilityPopover, EyeIcon, - PenIcon + PenIcon, + TrashIcon }, computed: { @@ -82,6 +89,32 @@ editContentBlock() { this.$store.dispatch('editContentBlock', this.contentBlock.id); }, + deleteContentBlock(id) { + const parent = this.parent; + this.$apollo.mutate({ + mutation: DELETE_CONTENT_BLOCK_MUTATION, + variables: { + input: { + id: id + } + }, + update(store, {data: {deleteContentBlock: {success}}}) { + try { + if (success) { + const query = CHAPTER_QUERY; + const variables = { + id: parent + }; + const data = store.readQuery({query, variables}); + data.chapter.contentBlocks.edges.splice(data.chapter.contentBlocks.edges.findIndex(edge => edge.node.id === id), 1); + store.writeQuery({query, variables, data}); + } + } catch (e) { + // Query did not exist in the cache, and apollo throws a generic Error. Do nothing + } + } + }); + } }, apollo: { @@ -119,7 +152,7 @@ display: grid; } - &__visibility-button { + &__action-button { cursor: pointer; } diff --git a/client/src/graphql/client.js b/client/src/graphql/client.js index cfe714df..860ab3a1 100644 --- a/client/src/graphql/client.js +++ b/client/src/graphql/client.js @@ -42,6 +42,7 @@ const cache = new InMemoryCache({ cacheRedirects: { Query: { contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}), + chapter: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ChapterNode', id: args.id}), assignment: (_, args, {getCacheKey}) => getCacheKey({__typename: 'AssignmentNode', id: args.id}) } } diff --git a/client/src/graphql/gql/allContentBlocksCacheQuery.gql b/client/src/graphql/gql/allContentBlocksCacheQuery.gql new file mode 100644 index 00000000..58d0f226 --- /dev/null +++ b/client/src/graphql/gql/allContentBlocksCacheQuery.gql @@ -0,0 +1,7 @@ +# to be read from cache only +#import "./fragments/contentBlockParts.gql" +query ContentBlockQuery { + contentBlocks { + ...ContentBlockParts + } +} diff --git a/client/src/graphql/gql/chapterQuery.gql b/client/src/graphql/gql/chapterQuery.gql new file mode 100644 index 00000000..68136ae1 --- /dev/null +++ b/client/src/graphql/gql/chapterQuery.gql @@ -0,0 +1,6 @@ +#import "./fragments/chapterParts.gql" +query ChapterQuery($id: ID!) { + chapter(id: $id) { + ...ChapterParts + } +} diff --git a/client/src/graphql/gql/fragments/chapterParts.gql b/client/src/graphql/gql/fragments/chapterParts.gql new file mode 100644 index 00000000..cb4f391f --- /dev/null +++ b/client/src/graphql/gql/fragments/chapterParts.gql @@ -0,0 +1,13 @@ +#import "./contentBlockParts.gql" +fragment ChapterParts on ChapterNode { + id + title + description + contentBlocks { + edges { + node { + ...ContentBlockParts + } + } + } +} diff --git a/client/src/graphql/gql/fragments/contentBlockParts.gql b/client/src/graphql/gql/fragments/contentBlockParts.gql index 03f3485e..229c87cc 100644 --- a/client/src/graphql/gql/fragments/contentBlockParts.gql +++ b/client/src/graphql/gql/fragments/contentBlockParts.gql @@ -5,6 +5,7 @@ fragment ContentBlockParts on ContentBlockNode { type contents userCreated + mine hiddenFor { edges { node { diff --git a/client/src/graphql/gql/moduleDetailsQuery.gql b/client/src/graphql/gql/moduleDetailsQuery.gql index 82f7c160..e70233a3 100644 --- a/client/src/graphql/gql/moduleDetailsQuery.gql +++ b/client/src/graphql/gql/moduleDetailsQuery.gql @@ -1,4 +1,4 @@ -#import "./fragments/contentBlockParts.gql" +#import "./fragments/chapterParts.gql" #import "./fragments/assignmentParts.gql" query ModulesQuery($slug: String!) { module(slug: $slug) { @@ -34,16 +34,7 @@ query ModulesQuery($slug: String!) { chapters { edges { node { - id - title - description - contentBlocks { - edges { - node { - ...ContentBlockParts - } - } - } + ...ChapterParts } } } diff --git a/client/src/graphql/gql/mutations/deleteContentBlock.gql b/client/src/graphql/gql/mutations/deleteContentBlock.gql new file mode 100644 index 00000000..e9319845 --- /dev/null +++ b/client/src/graphql/gql/mutations/deleteContentBlock.gql @@ -0,0 +1,12 @@ +mutation DeleteContentBlock($input: DeleteContentBlockInput!) { + deleteContentBlock(input: $input) { + success + errors + } +} + +#{ +# "input": { +# "id": "Um9vbU5vZGU6MjY=" +# } +#} diff --git a/server/books/schema/mutations/contentblock.py b/server/books/schema/mutations/contentblock.py index 058129b6..ec18717c 100644 --- a/server/books/schema/mutations/contentblock.py +++ b/server/books/schema/mutations/contentblock.py @@ -3,6 +3,7 @@ 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 @@ -115,3 +116,23 @@ class AddContentBlock(relay.ClientIDMutation): 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') diff --git a/server/books/schema/mutations/main.py b/server/books/schema/mutations/main.py index 0833e648..d1e55c0b 100644 --- a/server/books/schema/mutations/main.py +++ b/server/books/schema/mutations/main.py @@ -1,6 +1,7 @@ -from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock +from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock class BookMutations(object): mutate_content_block = MutateContentBlock.Field() add_content_block = AddContentBlock.Field() + delete_content_block = DeleteContentBlock.Field() diff --git a/server/books/schema/queries.py b/server/books/schema/queries.py index 79093c43..146fe0e8 100644 --- a/server/books/schema/queries.py +++ b/server/books/schema/queries.py @@ -7,6 +7,8 @@ from ..models import Book, Topic, Module, Chapter, ContentBlock class ContentBlockNode(DjangoObjectType): + mine = graphene.Boolean() + class Meta: model = ContentBlock only_fields = [ @@ -17,6 +19,8 @@ class ContentBlockNode(DjangoObjectType): ] interfaces = (relay.Node,) + def resolve_mine(self, info, **kwargs): + return self.owner is not None and self.owner.pk == info.context.user.pk class ChapterNode(DjangoObjectType): content_blocks = DjangoFilterConnectionField(ContentBlockNode)