Add parts for room entry deletion

This commit is contained in:
Ramon Wenger 2018-10-29 18:54:34 +01:00
parent acf59b218b
commit c536a04122
7 changed files with 160 additions and 10 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="room-entry"> <div class="room-entry">
<div class="room-entry__more"> <div class="room-entry__more" v-if="myEntry">
<a @click="showMenu = !showMenu" class="room-entry__more-link"> <a @click="showMenu = !showMenu" class="room-entry__more-link">
<ellipses class="room-entry__ellipses"></ellipses> <ellipses class="room-entry__ellipses"></ellipses>
</a> </a>
@ -28,6 +28,10 @@
</template> </template>
<script> <script>
import DELETE_ROOM_ENTRY_MUTATION from '@/graphql/gql/mutations/deleteRoomEntry.gql';
import ROOM_ENTRIES_QUERY from '@/graphql/gql/roomEntriesQuery.gql';
import ME_QUERY from '@/graphql/gql/meQuery.gql';
import UserWidget from '@/components/UserWidget.vue'; import UserWidget from '@/components/UserWidget.vue';
import Ellipses from '@/components/icons/Ellipses.vue'; import Ellipses from '@/components/icons/Ellipses.vue';
import WidgetPopover from '@/components/rooms/WidgetPopover'; import WidgetPopover from '@/components/rooms/WidgetPopover';
@ -42,7 +46,29 @@
}, },
methods: { methods: {
deleteRoomEntry() { deleteRoomEntry(id) {
this.$apollo.mutate({
mutation: DELETE_ROOM_ENTRY_MUTATION,
variables: {
input: {
id
}
},
update(store, {data: {deleteRoomEntry: {success, roomSlug}}}) {
if (success) {
const query = ROOM_ENTRIES_QUERY;
const variables = {slug: roomSlug};
const data = store.readQuery({query, variables});
if (data) {
data.room.roomEntries.edges.splice(data.room.roomEntries.edges.findIndex(edge => edge.node.id === id), 1);
store.writeQuery({query, data, variables});
}
}
}
})
},
editRoomEntry(id){
this.$store.dispatch('editRoomEntry', id);
} }
}, },
@ -70,6 +96,17 @@
} }
} }
return ''; return '';
},
myEntry() {
return this.author.id === this.me.id;
}
},
apollo: {
me() {
return {
query: ME_QUERY
}
} }
}, },
@ -114,20 +151,28 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
&__ellipses {
width: 30px;
fill: $color-darkgrey-1;
}
&__more { &__more {
position: absolute; position: absolute;
top: 5px; top: 10px;
right: 10px; right: 10px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
&__more-link { &__more-link {
background-color: rgba($color-white, 0.9);
width: 35px;
height: 15px;
border-radius: 15px;
display: flex;
justify-content: center;
}
&__ellipses {
width: 30px;
height: 30px;
fill: $color-darkgrey-1;
margin-top: -7px;
} }
&__popover { &__popover {

View File

@ -0,0 +1,13 @@
mutation DeleteRoomEntry($input: DeleteRoomEntryInput!) {
deleteRoomEntry(input: $input) {
success
errors
roomSlug
}
}
#{
# "input": {
# "id": "Um9vbU5vZGU6MjY="
# }
#}

View File

@ -51,7 +51,9 @@
data() { data() {
return { return {
rooms: [], rooms: [],
me: {} me: {
permissions: []
}
} }
} }
} }

View File

@ -32,6 +32,7 @@ class RoomEntryFactory(factory.django.DjangoModelFactory):
subtitle = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(8, 12))) subtitle = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(8, 12)))
description = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(20, 30))) description = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(20, 30)))
author = factory.Iterator(get_user_model().objects.all()) author = factory.Iterator(get_user_model().objects.all())
room = factory.SubFactory(RoomFactory)
contents = wagtail_factories.StreamFieldFactory({ contents = wagtail_factories.StreamFieldFactory({
'text_block': TextBlockFactory, 'text_block': TextBlockFactory,

View File

@ -1,9 +1,10 @@
import graphene import graphene
from graphene import relay from graphene import relay
from graphql_relay import to_global_id
from api.utils import get_object from api.utils import get_object
from rooms.inputs import UpdateRoomArgument, AddRoomArgument, AddRoomEntryArgument from rooms.inputs import UpdateRoomArgument, AddRoomArgument, AddRoomEntryArgument
from rooms.models import Room from rooms.models import Room, RoomEntry
from rooms.schema import RoomNode, RoomEntryNode from rooms.schema import RoomNode, RoomEntryNode
from rooms.serializers import RoomSerializer, RoomEntrySerializer from rooms.serializers import RoomSerializer, RoomEntrySerializer
from users.models import SchoolClass from users.models import SchoolClass
@ -93,8 +94,30 @@ class AddRoomEntry(relay.ClientIDMutation):
return cls(room_entry=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) return cls(room_entry=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()])
class DeleteRoomEntry(relay.ClientIDMutation):
class Input:
id = graphene.ID(required=True)
success = graphene.Boolean()
room_slug = graphene.String()
room_id = graphene.ID()
errors = graphene.List(graphene.String)
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
id = kwargs.get('id')
room_entry = get_object(RoomEntry, id)
if room_entry.author.pk != info.context.user.pk:
raise Exception('You are not the owner of this room entry')
room_id = to_global_id('RoomNode', room_entry.room.pk)
room_slug = room_entry.room.slug
room_entry.delete()
return cls(success=True, room_id=room_id, room_slug=room_slug)
class RoomMutations: class RoomMutations:
update_room = UpdateRoom.Field() update_room = UpdateRoom.Field()
add_room = AddRoom.Field() add_room = AddRoom.Field()
delete_room = DeleteRoom.Field() delete_room = DeleteRoom.Field()
add_room_entry = AddRoomEntry.Field() add_room_entry = AddRoomEntry.Field()
delete_room_entry = DeleteRoomEntry.Field()

View File

View File

@ -0,0 +1,66 @@
from django.test import TestCase, RequestFactory
from graphene.test import Client
from graphql_relay import to_global_id
from api.schema import schema
from core.factories import UserFactory
from rooms.factories import RoomEntryFactory, RoomFactory
from rooms.models import RoomEntry
from users.factories import SchoolClassFactory
from users.services import create_users
class RoomEntryMutationsTestCase(TestCase):
def setUp(self):
self.user = UserFactory(username='aschi')
self.another_user = UserFactory(username='pesche')
s = SchoolClassFactory(users=[self.user, self.another_user])
self.room_entry = RoomEntryFactory(author=self.user, room=RoomFactory(school_class=s))
request = RequestFactory().get('/')
request.user = self.user
self.client = Client(schema=schema, context_value=request)
def test_delete_room_entry(self):
self.assertEqual(RoomEntry.objects.count(), 1)
mutation = '''
mutation DeleteRoomEntry($input: DeleteRoomEntryInput!) {
deleteRoomEntry(input: $input) {
success
errors
}
}
'''
result = self.client.execute(mutation, variables={
'input': {
'id': to_global_id('RoomEntryNode', self.room_entry.pk)
}
})
self.assertIsNone(result.get('errors'))
self.assertEqual(RoomEntry.objects.count(), 0)
def test_delete_room_not_owner(self):
self.assertEqual(RoomEntry.objects.count(), 1)
mutation = '''
mutation DeleteRoomEntry($input: DeleteRoomEntryInput!) {
deleteRoomEntry(input: $input) {
success
errors
}
}
'''
request = RequestFactory().get('/')
request.user = self.another_user
client = Client(schema=schema, context_value=request)
result = client.execute(mutation, variables={
'input': {
'id': to_global_id('RoomEntryNode', self.room_entry.pk)
}
})
self.assertIsNotNone(result.get('errors'))
self.assertEqual(RoomEntry.objects.count(), 1)