Fix a bug with adding room entries in module rooms
Resolves MS-656 #complete
This commit is contained in:
parent
1ca3b47b07
commit
7ee322ec20
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="module-slug">
|
<div class="module-slug">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'moduleRoom', params: { slug: value.slug } }"
|
:to="{ name: 'module-room', params: { slug: value.slug } }"
|
||||||
class="button button--primary"
|
class="button button--primary"
|
||||||
>
|
>
|
||||||
Raum anzeigen
|
Raum anzeigen
|
||||||
|
|
|
||||||
|
|
@ -9,25 +9,27 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
|
import { ADD_ROOM_ENTRY_PAGE, ADD_MODULE_ROOM_ENTRY_PAGE } from '@/router/room.names';
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent } from 'vue';
|
||||||
const PlusIcon = defineAsyncComponent(() => import(/* webpackChunkName: "icons" */ '@/components/icons/PlusIcon'));
|
const PlusIcon = defineAsyncComponent(() => import('@/components/icons/PlusIcon.vue'));
|
||||||
import { ADD_ROOM_ENTRY_PAGE } from '@/router/room.names';
|
|
||||||
|
|
||||||
export default {
|
const props = withDefaults(
|
||||||
props: ['parent'],
|
defineProps<{
|
||||||
|
module: boolean;
|
||||||
components: {
|
}>(),
|
||||||
PlusIcon,
|
{
|
||||||
},
|
module: false,
|
||||||
|
}
|
||||||
data() {
|
);
|
||||||
return {
|
let name;
|
||||||
addRoomEntryRoute: {
|
if (props.module) {
|
||||||
name: ADD_ROOM_ENTRY_PAGE,
|
name = ADD_MODULE_ROOM_ENTRY_PAGE;
|
||||||
},
|
} else {
|
||||||
};
|
name = ADD_ROOM_ENTRY_PAGE;
|
||||||
},
|
}
|
||||||
|
const addRoomEntryRoute = {
|
||||||
|
name,
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#import "../../fragments/roomEntryParts.gql"
|
||||||
|
mutation AddModuleRoomEntry($input: AddModuleRoomEntryInput!) {
|
||||||
|
addModuleRoomEntry(input: $input) {
|
||||||
|
roomEntry {
|
||||||
|
...RoomEntryParts
|
||||||
|
}
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#{"input": {
|
||||||
|
# "roomEntry": {
|
||||||
|
# "title": "Hi",
|
||||||
|
# "contents": [{
|
||||||
|
# "type": "text_block",
|
||||||
|
# "value": {"text": "Something more\r\n what what"}
|
||||||
|
# }],
|
||||||
|
# "room": "Um9vbU5vZGU6MjM="
|
||||||
|
#
|
||||||
|
# }}
|
||||||
|
#}
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
<div class="room__content">
|
<div class="room__content">
|
||||||
<add-room-entry-button
|
<add-room-entry-button
|
||||||
:parent="room"
|
:parent="room"
|
||||||
|
:module="true"
|
||||||
v-if="room.id"
|
v-if="room.id"
|
||||||
>
|
>
|
||||||
<!--
|
<!--
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,13 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
import NEW_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/addRoomEntry.gql';
|
import NEW_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/addRoomEntry.gql';
|
||||||
|
import NEW_MODULE_ROOM_ENTRY_MUTATION from 'gql/mutations/rooms/addModuleRoomEntry.gql';
|
||||||
import ROOM_ENTRIES_QUERY from '@/graphql/gql/queries/roomEntriesQuery.gql';
|
import ROOM_ENTRIES_QUERY from '@/graphql/gql/queries/roomEntriesQuery.gql';
|
||||||
|
import me from '@/mixins/me';
|
||||||
|
|
||||||
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
import ContentBlockForm from '@/components/content-block-form/ContentBlockForm';
|
||||||
import { ROOMS_FEATURE_SET } from '@/consts/features.consts';
|
import { ROOMS_FEATURE_SET } from '@/consts/features.consts';
|
||||||
import { ROOM_PAGE } from '@/router/room.names';
|
import { ROOM_PAGE, MODULE_ROOM_PAGE } from '@/router/room.names';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -23,8 +25,14 @@ export default defineComponent({
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
isModule: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [me],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ContentBlockForm,
|
ContentBlockForm,
|
||||||
},
|
},
|
||||||
|
|
@ -41,8 +49,9 @@ export default defineComponent({
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
goBack() {
|
goBack() {
|
||||||
|
const name = this.isModule ? MODULE_ROOM_PAGE : ROOM_PAGE;
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: ROOM_PAGE,
|
name,
|
||||||
params: {
|
params: {
|
||||||
slug: this.slug,
|
slug: this.slug,
|
||||||
},
|
},
|
||||||
|
|
@ -53,24 +62,20 @@ export default defineComponent({
|
||||||
title,
|
title,
|
||||||
contents,
|
contents,
|
||||||
roomSlug: this.slug,
|
roomSlug: this.slug,
|
||||||
|
schoolClass: this.isModule ? this.me.selectedClass.id : null,
|
||||||
};
|
};
|
||||||
|
const mutation = this.isModule ? NEW_MODULE_ROOM_ENTRY_MUTATION : NEW_ROOM_ENTRY_MUTATION;
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.mutate({
|
.mutate({
|
||||||
mutation: NEW_ROOM_ENTRY_MUTATION,
|
mutation,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
roomEntry: entry,
|
roomEntry: entry,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: (
|
update: (store, { data }) => {
|
||||||
store,
|
|
||||||
{
|
|
||||||
data: {
|
|
||||||
addRoomEntry: { roomEntry },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
|
const { roomEntry } = this.isModule ? data.addRoomEntry : data.addModuleRoomEntry;
|
||||||
const query = ROOM_ENTRIES_QUERY;
|
const query = ROOM_ENTRIES_QUERY;
|
||||||
const variables = { slug: this.slug };
|
const variables = { slug: this.slug };
|
||||||
const { room } = store.readQuery({ query, variables });
|
const { room } = store.readQuery({ query, variables });
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
export const NEW_ROOM_PAGE = 'new-room';
|
export const NEW_ROOM_PAGE = 'new-room';
|
||||||
export const ROOMS_PAGE = 'rooms';
|
export const ROOMS_PAGE = 'rooms';
|
||||||
export const ROOM_PAGE = 'room';
|
export const ROOM_PAGE = 'room';
|
||||||
|
export const MODULE_ROOM_PAGE = 'module-room';
|
||||||
export const ADD_ROOM_ENTRY_PAGE = 'add-room-entry';
|
export const ADD_ROOM_ENTRY_PAGE = 'add-room-entry';
|
||||||
|
export const ADD_MODULE_ROOM_ENTRY_PAGE = 'add-module-room-entry';
|
||||||
export const UPDATE_ROOM_ENTRY_PAGE = 'update-room-entry';
|
export const UPDATE_ROOM_ENTRY_PAGE = 'update-room-entry';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
import { NEW_ROOM_PAGE, ROOMS_PAGE, ADD_ROOM_ENTRY_PAGE, ROOM_PAGE, UPDATE_ROOM_ENTRY_PAGE } from '@/router/room.names';
|
import {
|
||||||
|
NEW_ROOM_PAGE,
|
||||||
|
ROOMS_PAGE,
|
||||||
|
ADD_ROOM_ENTRY_PAGE,
|
||||||
|
ROOM_PAGE,
|
||||||
|
UPDATE_ROOM_ENTRY_PAGE,
|
||||||
|
ADD_MODULE_ROOM_ENTRY_PAGE,
|
||||||
|
MODULE_ROOM_PAGE,
|
||||||
|
} from '@/router/room.names';
|
||||||
|
|
||||||
const rooms = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/rooms');
|
const rooms = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/rooms');
|
||||||
const newRoom = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/newRoom');
|
const newRoom = () => import(/* webpackChunkName: "rooms" */ '@/pages/rooms/newRoom');
|
||||||
|
|
@ -17,9 +25,15 @@ export default [
|
||||||
{ path: '/room/:slug/edit/:entrySlug', name: UPDATE_ROOM_ENTRY_PAGE, component: editRoomEntry, props: true },
|
{ path: '/room/:slug/edit/:entrySlug', name: UPDATE_ROOM_ENTRY_PAGE, component: editRoomEntry, props: true },
|
||||||
{
|
{
|
||||||
path: '/module-room/:slug',
|
path: '/module-room/:slug',
|
||||||
name: 'moduleRoom',
|
name: MODULE_ROOM_PAGE,
|
||||||
component: moduleRoom,
|
component: moduleRoom,
|
||||||
props: true,
|
props: true,
|
||||||
meta: { layout: 'fullScreen' },
|
meta: { layout: 'fullScreen' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/module-room/:slug/add',
|
||||||
|
name: ADD_MODULE_ROOM_ENTRY_PAGE,
|
||||||
|
component: newRoomEntry,
|
||||||
|
props: (route) => ({ slug: route.params.slug, isModule: true }),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ class RoomEntryArgument(InputObjectType):
|
||||||
contents = graphene.List(ContentElementInput)
|
contents = graphene.List(ContentElementInput)
|
||||||
|
|
||||||
|
|
||||||
|
class AddModuleRoomEntryArgument(RoomEntryArgument):
|
||||||
|
room_slug = graphene.String(required=True)
|
||||||
|
school_class = graphene.String(required=True)
|
||||||
|
|
||||||
class AddRoomEntryArgument(RoomEntryArgument):
|
class AddRoomEntryArgument(RoomEntryArgument):
|
||||||
room_slug = graphene.String(required=True)
|
room_slug = graphene.String(required=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from graphene import relay
|
||||||
from graphql_relay import to_global_id
|
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, UpdateRoomEntryArgument
|
from rooms.inputs import UpdateRoomArgument, AddRoomArgument, AddRoomEntryArgument, UpdateRoomEntryArgument, AddModuleRoomEntryArgument
|
||||||
from rooms.models import Comment, Room, RoomEntry
|
from rooms.models import Comment, Room, RoomEntry
|
||||||
from rooms.schema import CommentNode, RoomNode, RoomEntryNode
|
from rooms.schema import CommentNode, RoomNode, RoomEntryNode
|
||||||
from rooms.serializers import RoomSerializer, RoomEntrySerializer
|
from rooms.serializers import RoomSerializer, RoomEntrySerializer
|
||||||
|
|
@ -87,9 +87,14 @@ class MutateRoomEntry(relay.ClientIDMutation):
|
||||||
room_entry_data = kwargs.get('room_entry')
|
room_entry_data = kwargs.get('room_entry')
|
||||||
room = None
|
room = None
|
||||||
room_slug = room_entry_data.get('room_slug')
|
room_slug = room_entry_data.get('room_slug')
|
||||||
|
school_class_id = room_entry_data.get('school_class')
|
||||||
|
|
||||||
if room_slug is not None:
|
if room_slug is not None:
|
||||||
room = Room.objects.get(slug=room_slug)
|
if school_class_id is not None:
|
||||||
|
school_class = get_object(SchoolClass, school_class_id)
|
||||||
|
room = Room.objects.get(slug=room_slug, school_class=school_class)
|
||||||
|
else:
|
||||||
|
room = Room.objects.get(slug=room_slug)
|
||||||
room_entry_data['room'] = room.id
|
room_entry_data['room'] = room.id
|
||||||
|
|
||||||
if room_entry_data.get('slug') is not None:
|
if room_entry_data.get('slug') is not None:
|
||||||
|
|
@ -125,6 +130,10 @@ class MutateRoomEntry(relay.ClientIDMutation):
|
||||||
return RoomEntrySerializer(data=room_entry_data)
|
return RoomEntrySerializer(data=room_entry_data)
|
||||||
|
|
||||||
|
|
||||||
|
class AddModuleRoomEntry(MutateRoomEntry):
|
||||||
|
class Input:
|
||||||
|
room_entry = graphene.Argument(AddModuleRoomEntryArgument)
|
||||||
|
|
||||||
class AddRoomEntry(MutateRoomEntry):
|
class AddRoomEntry(MutateRoomEntry):
|
||||||
class Input:
|
class Input:
|
||||||
room_entry = graphene.Argument(AddRoomEntryArgument)
|
room_entry = graphene.Argument(AddRoomEntryArgument)
|
||||||
|
|
@ -203,6 +212,7 @@ class RoomMutations:
|
||||||
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()
|
||||||
|
add_module_room_entry = AddModuleRoomEntry.Field()
|
||||||
delete_room_entry = DeleteRoomEntry.Field()
|
delete_room_entry = DeleteRoomEntry.Field()
|
||||||
update_room_entry = UpdateRoomEntry.Field()
|
update_room_entry = UpdateRoomEntry.Field()
|
||||||
add_comment = AddComment.Field()
|
add_comment = AddComment.Field()
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,11 @@ from graphql_relay import to_global_id
|
||||||
from api.schema import schema
|
from api.schema import schema
|
||||||
from core.factories import UserFactory
|
from core.factories import UserFactory
|
||||||
from rooms.factories import RoomFactory, ModuleRoomSlugFactory
|
from rooms.factories import RoomFactory, ModuleRoomSlugFactory
|
||||||
|
from core.tests.base_test import SkillboxTestCase
|
||||||
from users.factories import SchoolClassFactory
|
from users.factories import SchoolClassFactory
|
||||||
|
|
||||||
|
|
||||||
class AdminRoomQueryPermission(TestCase):
|
class AdminRoomQueryPermission(SkillboxTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user = UserFactory(username='aschi')
|
self.user = UserFactory(username='aschi')
|
||||||
|
|
@ -44,6 +45,17 @@ class AdminRoomQueryPermission(TestCase):
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
self.mutation = '''
|
||||||
|
mutation AddModuleRoomEntry($input: AddModuleRoomEntryInput!) {
|
||||||
|
addModuleRoomEntry(input: $input) {
|
||||||
|
roomEntry {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
def test_should_return_none_if_slug_does_not_exist(self):
|
def test_should_return_none_if_slug_does_not_exist(self):
|
||||||
|
|
||||||
result = self.client.execute(self.query, variables={
|
result = self.client.execute(self.query, variables={
|
||||||
|
|
@ -94,3 +106,63 @@ class AdminRoomQueryPermission(TestCase):
|
||||||
|
|
||||||
self.assertIsNone(result.get('errors'))
|
self.assertIsNone(result.get('errors'))
|
||||||
self.assertEqual(result.get('data').get('moduleRoom').get('title'), existing_room.title)
|
self.assertEqual(result.get('data').get('moduleRoom').get('title'), existing_room.title)
|
||||||
|
|
||||||
|
def test_should_work_with_two_existing_rooms(self):
|
||||||
|
result_1 = self.get_client(self.user).execute(self.query, variables={
|
||||||
|
'slug': self.module_room_slug.slug,
|
||||||
|
'classId': self.sc1_id
|
||||||
|
})
|
||||||
|
self.assertIsNone(result_1.errors)
|
||||||
|
self.assertEqual(result_1.data.get('moduleRoom').get('title'), self.module_room_slug.title)
|
||||||
|
result_2 = self.get_client(self.another_user).execute(self.query, variables={
|
||||||
|
'slug': self.module_room_slug.slug,
|
||||||
|
'classId': self.sc2_id
|
||||||
|
})
|
||||||
|
self.assertIsNone(result_2.errors)
|
||||||
|
self.assertEqual(result_2.data.get('moduleRoom').get('title'), self.module_room_slug.title)
|
||||||
|
result_3 = self.get_client(self.user).execute(self.query, variables={
|
||||||
|
'slug': self.module_room_slug.slug,
|
||||||
|
'classId': self.sc1_id
|
||||||
|
})
|
||||||
|
self.assertIsNone(result_3.errors)
|
||||||
|
self.assertEqual(result_3.data.get('moduleRoom').get('title'), self.module_room_slug.title)
|
||||||
|
|
||||||
|
def test_add_room_entry_to_module_room(self):
|
||||||
|
title = 'hello'
|
||||||
|
slug = self.module_room_slug.slug
|
||||||
|
result_1 = self.get_client(self.user).execute(self.query, variables={
|
||||||
|
'slug': slug,
|
||||||
|
'classId': self.sc1_id
|
||||||
|
})
|
||||||
|
self.assertIsNone(result_1.errors)
|
||||||
|
self.assertEqual(result_1.data.get('moduleRoom').get('title'), self.module_room_slug.title)
|
||||||
|
result_2 = self.get_client(self.another_user).execute(self.query, variables={
|
||||||
|
'slug': slug,
|
||||||
|
'classId': self.sc2_id
|
||||||
|
})
|
||||||
|
self.assertIsNone(result_2.errors)
|
||||||
|
self.assertEqual(result_2.data.get('moduleRoom').get('title'), self.module_room_slug.title)
|
||||||
|
mutation_result_1 = self.get_client(self.user).execute(self.mutation, variables={
|
||||||
|
'input': {
|
||||||
|
'roomEntry': {
|
||||||
|
'roomSlug': slug,
|
||||||
|
'schoolClass': self.sc1_id,
|
||||||
|
'title': title,
|
||||||
|
'contents': []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.assertIsNone(mutation_result_1.errors)
|
||||||
|
self.assertEqual(mutation_result_1.data.get('addModuleRoomEntry').get('roomEntry').get('title'), title)
|
||||||
|
mutation_result_2 = self.get_client(self.another_user).execute(self.mutation, variables={
|
||||||
|
'input': {
|
||||||
|
'roomEntry': {
|
||||||
|
'roomSlug': slug,
|
||||||
|
'schoolClass': self.sc2_id,
|
||||||
|
'title': title,
|
||||||
|
'contents': []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.assertIsNone(mutation_result_2.errors)
|
||||||
|
self.assertEqual(mutation_result_2.data.get('addModuleRoomEntry').get('roomEntry').get('title'), title)
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,24 @@ type AddContentBlockPayload {
|
||||||
clientMutationId: String
|
clientMutationId: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input AddModuleRoomEntryArgument {
|
||||||
|
title: String!
|
||||||
|
contents: [ContentElementInput]
|
||||||
|
roomSlug: String!
|
||||||
|
schoolClass: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
input AddModuleRoomEntryInput {
|
||||||
|
roomEntry: AddModuleRoomEntryArgument
|
||||||
|
clientMutationId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddModuleRoomEntryPayload {
|
||||||
|
roomEntry: RoomEntryNode
|
||||||
|
errors: [String]
|
||||||
|
clientMutationId: String
|
||||||
|
}
|
||||||
|
|
||||||
input AddNoteArgument {
|
input AddNoteArgument {
|
||||||
content: UUID
|
content: UUID
|
||||||
block: String
|
block: String
|
||||||
|
|
@ -701,6 +719,7 @@ type Mutation {
|
||||||
addRoom(input: AddRoomInput!): AddRoomPayload
|
addRoom(input: AddRoomInput!): AddRoomPayload
|
||||||
deleteRoom(input: DeleteRoomInput!): DeleteRoomPayload
|
deleteRoom(input: DeleteRoomInput!): DeleteRoomPayload
|
||||||
addRoomEntry(input: AddRoomEntryInput!): AddRoomEntryPayload
|
addRoomEntry(input: AddRoomEntryInput!): AddRoomEntryPayload
|
||||||
|
addModuleRoomEntry(input: AddModuleRoomEntryInput!): AddModuleRoomEntryPayload
|
||||||
deleteRoomEntry(input: DeleteRoomEntryInput!): DeleteRoomEntryPayload
|
deleteRoomEntry(input: DeleteRoomEntryInput!): DeleteRoomEntryPayload
|
||||||
updateRoomEntry(input: UpdateRoomEntryInput!): UpdateRoomEntryPayload
|
updateRoomEntry(input: UpdateRoomEntryInput!): UpdateRoomEntryPayload
|
||||||
addComment(input: AddCommentInput!): AddCommentPayload
|
addComment(input: AddCommentInput!): AddCommentPayload
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue