Add content block deletion mutation

This commit is contained in:
Ramon Wenger 2018-10-11 11:39:50 +02:00
parent 4d1e156f9f
commit ce86e45743
12 changed files with 108 additions and 17 deletions

View File

@ -9,6 +9,7 @@
<add-content-block-button :parent="chapter.id"></add-content-block-button>
<content-block :contentBlock="contentBlock"
:parent="chapter.id"
:key="contentBlock.id" v-for="contentBlock in filteredContentBlocks">
</content-block>
</div>

View File

@ -2,7 +2,7 @@
<div class="content-block__container">
<div class="content-block" :class="specialClass">
<div class="content-block__actions">
<a @click="toggleVisibility()" v-if="canManageContent" class="content-block__visibility-button">
<a @click="toggleVisibility()" v-if="canManageContent" class="content-block__action-button">
<eye-icon class="content-block__action-icon"></eye-icon>
</a>
<visibility-popover
@ -10,9 +10,12 @@
:content-block="contentBlock"
class="content-block__visibility-menu"
></visibility-popover>
<a @click="editContentBlock()" v-if="contentBlock.userCreated">
<a @click="editContentBlock()" v-if="contentBlock.mine" class="content-block__action-button">
<pen-icon class="content-block__action-icon"></pen-icon>
</a>
<a @click="deleteContentBlock(contentBlock.id)" v-if="contentBlock.mine" class="content-block__action-button">
<trash-icon class="content-block__action-icon"></trash-icon>
</a>
</div>
<h4 class="content-block__title">{{contentBlock.title}} {{contentBlock.userCreated}}</h4>
@ -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;
}

View File

@ -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})
}
}

View File

@ -0,0 +1,7 @@
# to be read from cache only
#import "./fragments/contentBlockParts.gql"
query ContentBlockQuery {
contentBlocks {
...ContentBlockParts
}
}

View File

@ -0,0 +1,6 @@
#import "./fragments/chapterParts.gql"
query ChapterQuery($id: ID!) {
chapter(id: $id) {
...ChapterParts
}
}

View File

@ -0,0 +1,13 @@
#import "./contentBlockParts.gql"
fragment ChapterParts on ChapterNode {
id
title
description
contentBlocks {
edges {
node {
...ContentBlockParts
}
}
}
}

View File

@ -5,6 +5,7 @@ fragment ContentBlockParts on ContentBlockNode {
type
contents
userCreated
mine
hiddenFor {
edges {
node {

View File

@ -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
}
}
}

View File

@ -0,0 +1,12 @@
mutation DeleteContentBlock($input: DeleteContentBlockInput!) {
deleteContentBlock(input: $input) {
success
errors
}
}
#{
# "input": {
# "id": "Um9vbU5vZGU6MjY="
# }
#}

View File

@ -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')

View File

@ -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()

View File

@ -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)