Add module visibility sync mutation

This commit is contained in:
Ramon Wenger 2021-03-05 17:21:53 +01:00
parent 209838dadb
commit 9490ffd443
16 changed files with 262 additions and 159 deletions

View File

@ -0,0 +1,5 @@
describe('Survey', () => {
it('needs to be implemented', () => {
expect(true).to.equal(false);
});
});

View File

@ -9,15 +9,6 @@
export default { export default {
mixins: [me], mixins: [me],
computed: {
currentClassName() {
let currentClass = this.me.schoolClasses.find(schoolClass => {
return schoolClass.id === this.me.selectedClass.id;
});
return currentClass ? currentClass.name : this.me.schoolClasses.length ? this.me.schoolClasses[0].name : '';
}
}
}; };
</script> </script>

View File

@ -0,0 +1,5 @@
mutation SyncModuleVisibility($input: SyncModuleVisibilityInput!) {
syncModuleVisibility(input: $input) {
success
}
}

View File

@ -5,13 +5,13 @@ export default {
return { return {
me: { me: {
selectedClass: { selectedClass: {
id: '' id: '',
}, },
permissions: [], permissions: [],
schoolClasses: [], schoolClasses: [],
isTeacher: false isTeacher: false,
}, },
showPopover: false showPopover: false,
}; };
}, },
@ -21,8 +21,8 @@ export default {
return { return {
name: 'topic', name: 'topic',
params: { params: {
topicSlug: this.me.lastTopic.slug topicSlug: this.me.lastTopic.slug,
} },
}; };
} }
return '/book/topic/berufliche-grundbildung'; return '/book/topic/berufliche-grundbildung';
@ -33,15 +33,21 @@ export default {
canManageContent() { canManageContent() {
return this.me.permissions.includes('users.can_manage_school_class_content'); return this.me.permissions.includes('users.can_manage_school_class_content');
}, },
currentClassName() {
let currentClass = this.me.schoolClasses.find(schoolClass => {
return schoolClass.id === this.me.selectedClass.id;
});
return currentClass ? currentClass.name : this.me.schoolClasses.length ? this.me.schoolClasses[0].name : '';
},
}, },
apollo: { apollo: {
me: { me: {
query: ME_QUERY, query: ME_QUERY,
update(data) { update({me}) {
return this.$getRidOfEdges(data).me; return this.$getRidOfEdges(me);
}, },
fetchPolicy: 'cache-first' fetchPolicy: 'cache-first',
}, },
}, },
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="module-page"> <div class="module-page">
<module-navigation/> <module-navigation v-if="showNavigation" />
<router-view/> <router-view/>
</div> </div>
</template> </template>
@ -11,6 +11,12 @@
export default { export default {
components: { components: {
ModuleNavigation ModuleNavigation
},
computed: {
showNavigation() {
return !this.$route.meta.hideNavigation;
}
} }
}; };
</script> </script>

View File

@ -12,16 +12,25 @@
<div class="module-visibility__form module-visibility__section"> <div class="module-visibility__form module-visibility__section">
Von Von
<select <select
:value="selectedClassId"
class="skillbox-input skillbox-dropdown module-visibility__dropdown" class="skillbox-input skillbox-dropdown module-visibility__dropdown"
placeholder="Hallo"> @change="select($event.target.value)">
<option <option
value value=""
selected>-</option> selected>-
</option>
<option
:key="schoolClass.id"
:value="schoolClass.id"
v-for="schoolClass in schoolClasses">{{ schoolClass.name }}
</option>
</select> </select>
für INF2019i übernehmen. für {{ currentClassName }} übernehmen.
</div> </div>
<div class="module-visibility__section"> <div class="module-visibility__section">
<a class="button button--primary">Anpassungen übernehmen</a> <a
class="button button--primary"
@click="sync">Anpassungen übernehmen</a>
</div> </div>
</div> </div>
</template> </template>
@ -29,11 +38,48 @@
<script> <script>
import EyeIcon from '@/components/icons/EyeIcon'; import EyeIcon from '@/components/icons/EyeIcon';
import me from '@/mixins/me';
import SYNC_VISIBILITY_MUTATION from '@/graphql/gql/mutations/syncModuleVisibility.gql';
export default { export default {
mixins: [me],
components: { components: {
EyeIcon EyeIcon,
}, },
data() {
return {
selectedClassId: '',
};
},
computed: {
schoolClasses() {
return this.me.schoolClasses.filter(schoolClass => schoolClass.id !== this.me.selectedClass.id);
},
},
methods: {
select(selectedClassId) {
this.selectedClassId = selectedClassId;
},
sync() {
if (this.selectedClassId) {
this.$apollo.mutate({
mutation: SYNC_VISIBILITY_MUTATION,
variables: {
input: {
module: this.$route.params.slug,
templateSchoolClass: this.selectedClassId,
schoolClass: this.me.selectedClass.id,
},
},
});
}
},
},
}; };
</script> </script>

View File

@ -1,8 +1,5 @@
import Vue from 'vue'; import Vue from 'vue';
// import index from '@/pages/index'
import topic from '@/pages/topic'; import topic from '@/pages/topic';
import moduleBase from '@/pages/module-base';
import module from '@/pages/module';
import rooms from '@/pages/rooms'; import rooms from '@/pages/rooms';
import room from '@/pages/room'; import room from '@/pages/room';
import newRoom from '@/pages/newRoom'; import newRoom from '@/pages/newRoom';
@ -10,7 +7,6 @@ import editRoom from '@/pages/editRoom';
import article from '@/pages/article'; import article from '@/pages/article';
import instrument from '@/pages/instrument'; import instrument from '@/pages/instrument';
import instrumentOverview from '@/pages/instrumentOverview'; import instrumentOverview from '@/pages/instrumentOverview';
import submissions from '@/pages/submissions';
import p404 from '@/pages/p404'; import p404 from '@/pages/p404';
import start from '@/pages/start'; import start from '@/pages/start';
import submission from '@/pages/studentSubmission'; import submission from '@/pages/studentSubmission';
@ -41,10 +37,11 @@ import onboardingStep1 from '@/pages/onboarding/step1';
import onboardingStep2 from '@/pages/onboarding/step2'; import onboardingStep2 from '@/pages/onboarding/step2';
import onboardingStep3 from '@/pages/onboarding/step3'; import onboardingStep3 from '@/pages/onboarding/step3';
import settingsPage from '@/pages/moduleSettings'; import settingsPage from '@/pages/moduleSettings';
import moduleRoutes from './module.routes';
import portfolioRoutes from './portfolio.routes'; import portfolioRoutes from './portfolio.routes';
import store from '@/store/index'; import store from '@/store/index';
import moduleVisibility from '@/pages/moduleVisibility';
const ONBOARDING_STEP_1 = 'onboarding-step-1'; const ONBOARDING_STEP_1 = 'onboarding-step-1';
const ONBOARDING_STEP_2 = 'onboarding-step-2'; const ONBOARDING_STEP_2 = 'onboarding-step-2';
@ -54,7 +51,7 @@ const routes = [
{ {
path: '/', path: '/',
name: 'home', name: 'home',
component: start component: start,
}, },
{ {
path: '/login', path: '/login',
@ -62,8 +59,8 @@ const routes = [
component: login, component: login,
meta: { meta: {
layout: 'public', layout: 'public',
public: true public: true,
} },
}, },
{ {
path: '/hello', path: '/hello',
@ -71,8 +68,8 @@ const routes = [
component: hello, component: hello,
meta: { meta: {
layout: 'public', layout: 'public',
public: true public: true,
} },
}, },
{ {
path: '/beta-login', path: '/beta-login',
@ -80,27 +77,10 @@ const routes = [
component: betaLogin, component: betaLogin,
meta: { meta: {
layout: 'public', layout: 'public',
public: true public: true,
} },
},
{
path: '/module/:slug',
component: moduleBase,
children: [
{
path: '',
name: 'module',
component: module,
meta: {filter: true}
},
{
path: 'submissions/:id',
name: 'submissions',
component: submissions,
meta: {filter: true}
}
]
}, },
...moduleRoutes,
{path: '/rooms', name: 'rooms', component: rooms, meta: {filter: true}}, {path: '/rooms', name: 'rooms', component: rooms, meta: {filter: true}},
{path: '/new-room/', name: 'new-room', component: newRoom}, {path: '/new-room/', name: 'new-room', component: newRoom},
{path: '/edit-room/:id', name: 'edit-room', component: editRoom, props: true}, {path: '/edit-room/:id', name: 'edit-room', component: editRoom, props: true},
@ -110,13 +90,13 @@ const routes = [
name: 'moduleRoom', name: 'moduleRoom',
component: moduleRoom, component: moduleRoom,
props: true, props: true,
meta: {layout: 'fullScreen'} meta: {layout: 'fullScreen'},
}, },
{path: '/article/:slug', name: 'article', component: article, meta: {layout: 'simple'}}, {path: '/article/:slug', name: 'article', component: article, meta: {layout: 'simple'}},
{ {
path: '/instruments/', path: '/instruments/',
name: 'instrument-overview', name: 'instrument-overview',
component: instrumentOverview component: instrumentOverview,
}, },
{path: '/instrument/:slug', name: 'instrument', component: instrument, meta: {layout: 'simple'}}, {path: '/instrument/:slug', name: 'instrument', component: instrument, meta: {layout: 'simple'}},
{path: '/submission/:id', name: 'submission', component: submission, meta: {layout: 'simple'}}, {path: '/submission/:id', name: 'submission', component: submission, meta: {layout: 'simple'}},
@ -134,11 +114,11 @@ const routes = [
path: 'old-classes', path: 'old-classes',
name: 'old-classes', name: 'old-classes',
component: oldClasses, component: oldClasses,
meta: {isProfile: true} meta: {isProfile: true},
}, },
{path: 'create-class', name: 'create-class', component: createClass, meta: {layout: 'simple'}}, {path: 'create-class', name: 'create-class', component: createClass, meta: {layout: 'simple'}},
{path: 'show-code', name: 'show-code', component: showCode, meta: {layout: 'simple'}}, {path: 'show-code', name: 'show-code', component: showCode, meta: {layout: 'simple'}},
] ],
}, },
{path: 'join-class', name: 'join-class', component: joinClass, meta: {layout: 'public'}}, {path: 'join-class', name: 'join-class', component: joinClass, meta: {layout: 'public'}},
{ {
@ -146,7 +126,7 @@ const routes = [
component: surveyPage, component: surveyPage,
name: 'survey', name: 'survey',
props: true, props: true,
meta: {layout: 'simple'} meta: {layout: 'simple'},
}, },
{ {
path: '/register', path: '/register',
@ -155,7 +135,7 @@ const routes = [
meta: { meta: {
public: true, public: true,
layout: 'public', layout: 'public',
} },
}, },
{ {
path: '/check-email', path: '/check-email',
@ -163,8 +143,8 @@ const routes = [
name: 'checkEmail', name: 'checkEmail',
meta: { meta: {
public: true, public: true,
layout: 'public' layout: 'public',
} },
}, },
{ {
path: '/verify-email', path: '/verify-email',
@ -172,16 +152,16 @@ const routes = [
name: 'emailVerification', name: 'emailVerification',
meta: { meta: {
public: true, public: true,
layout: 'public' layout: 'public',
} },
}, },
{ {
path: '/license-activation', path: '/license-activation',
component: licenseActivation, component: licenseActivation,
name: 'licenseActivation', name: 'licenseActivation',
meta: { meta: {
layout: 'public' layout: 'public',
} },
}, },
{ {
path: '/forgot-password', path: '/forgot-password',
@ -189,13 +169,13 @@ const routes = [
name: 'forgotPassword', name: 'forgotPassword',
meta: { meta: {
layout: 'public', layout: 'public',
public: true public: true,
} },
}, },
{ {
path: '/news', path: '/news',
component: news, component: news,
name: 'news' name: 'news',
}, },
{ {
path: '/onboarding', path: '/onboarding',
@ -207,7 +187,7 @@ const routes = [
name: 'onboarding-start', name: 'onboarding-start',
meta: { meta: {
layout: 'blank', layout: 'blank',
next: ONBOARDING_STEP_1 next: ONBOARDING_STEP_1,
}, },
}, },
{ {
@ -217,7 +197,7 @@ const routes = [
meta: { meta: {
layout: 'blank', layout: 'blank',
next: ONBOARDING_STEP_2, next: ONBOARDING_STEP_2,
illustration: 'contents' illustration: 'contents',
}, },
}, },
{ {
@ -227,7 +207,7 @@ const routes = [
meta: { meta: {
layout: 'blank', layout: 'blank',
next: ONBOARDING_STEP_3, next: ONBOARDING_STEP_3,
illustration: 'rooms' illustration: 'rooms',
}, },
}, },
{ {
@ -237,30 +217,23 @@ const routes = [
meta: { meta: {
layout: 'blank', layout: 'blank',
next: 'home', next: 'home',
illustration: 'portfolio' illustration: 'portfolio',
}, },
}, },
] ],
}, },
{ {
path: '/settings', path: '/settings',
component: settingsPage component: settingsPage,
},
{
path: '/visibility',
component: moduleVisibility,
meta: {
layout: 'simple'
}
}, },
{path: '/styleguide', component: styleGuidePage}, {path: '/styleguide', component: styleGuidePage},
{ {
path: '*', path: '*',
component: p404, component: p404,
meta: { meta: {
layout: 'blank' layout: 'blank',
} },
} },
]; ];
Vue.use(Router); Vue.use(Router);
@ -273,7 +246,7 @@ const router = new Router({
return savedPosition; return savedPosition;
} }
return {x: 0, y: 0}; return {x: 0, y: 0};
} },
}); });
router.afterEach((to, from) => { router.afterEach((to, from) => {

View File

@ -0,0 +1,3 @@
export const SUBMISSIONS_PAGE = 'submissions';
export const MODULE_PAGE = 'module';
export const VISIBILITY_PAGE = 'visibility';

View File

@ -0,0 +1,35 @@
import moduleBase from '@/pages/module-base';
import module from '@/pages/module';
import submissions from '@/pages/submissions';
import moduleVisibility from '@/pages/moduleVisibility';
import {MODULE_PAGE, SUBMISSIONS_PAGE, VISIBILITY_PAGE} from '@/router/module.names';
export default [
{
path: '/module/:slug',
component: moduleBase,
children: [
{
path: '',
name: MODULE_PAGE,
component: module,
meta: {filter: true},
},
{
path: 'submissions/:id',
name: SUBMISSIONS_PAGE,
component: submissions,
meta: {filter: true},
},
{
path: 'visibility',
name: VISIBILITY_PAGE,
component: moduleVisibility,
meta: {
layout: 'simple',
hideNavigation: true
},
},
],
}
];

View File

@ -24,7 +24,6 @@ from rooms.mutations import RoomMutations
from rooms.schema import RoomsQuery, ModuleRoomsQuery from rooms.schema import RoomsQuery, ModuleRoomsQuery
from users.schema import AllUsersQuery, UsersQuery from users.schema import AllUsersQuery, UsersQuery
from users.mutations import ProfileMutations from users.mutations import ProfileMutations
from registration.mutations_public import RegistrationMutations
class CustomQuery(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, class CustomQuery(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery,
@ -36,7 +35,7 @@ class CustomQuery(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, Objec
class CustomMutation(BookMutations, RoomMutations, AssignmentMutations, ObjectiveMutations, CoreMutations, PortfolioMutations, class CustomMutation(BookMutations, RoomMutations, AssignmentMutations, ObjectiveMutations, CoreMutations, PortfolioMutations,
ProfileMutations, SurveyMutations, NoteMutations, RegistrationMutations, SpellCheckMutations, ProfileMutations, SurveyMutations, NoteMutations, SpellCheckMutations,
CouponMutations, graphene.ObjectType): CouponMutations, graphene.ObjectType):
if settings.DEBUG: if settings.DEBUG:
debug = graphene.Field(DjangoDebug, name='_debug') debug = graphene.Field(DjangoDebug, name='_debug')

View File

@ -58,7 +58,7 @@ class Module(StrictHierarchyPage):
def get_child_ids(self): def get_child_ids(self):
return self.get_children().values_list('id', flat=True) return self.get_children().values_list('id', flat=True)
def sync_from_school_class(self, school_class_pattern, school_class_to_sync): def sync_from_school_class(self, school_class_template, school_class_to_sync):
# import here so we don't get a circular import error # import here so we don't get a circular import error
from books.models import Chapter, ContentBlock from books.models import Chapter, ContentBlock
@ -77,12 +77,12 @@ class Module(StrictHierarchyPage):
content_block.visible_for.remove(school_class_to_sync) content_block.visible_for.remove(school_class_to_sync)
# get all content blocks with `hidden for` for class `school_class_pattern` # get all content blocks with `hidden for` for class `school_class_pattern`
for content_block in school_class_pattern.hidden_content_blocks.intersection(content_block_query): for content_block in school_class_template.hidden_content_blocks.intersection(content_block_query):
# add `school_class_to_sync` to these blocks' `hidden for` # add `school_class_to_sync` to these blocks' `hidden for`
content_block.hidden_for.add(school_class_to_sync) content_block.hidden_for.add(school_class_to_sync)
# get all content blocks with `visible for` for class `school_class_pattern` # get all content blocks with `visible for` for class `school_class_pattern`
for content_block in school_class_pattern.visible_content_blocks.intersection(content_block_query): for content_block in school_class_template.visible_content_blocks.intersection(content_block_query):
# add `school_class_to_sync` to these blocks' `visible for` # add `school_class_to_sync` to these blocks' `visible for`
content_block.visible_for.add(school_class_to_sync) content_block.visible_for.add(school_class_to_sync)

View File

@ -1,6 +1,7 @@
from books.schema.mutations.chapter import UpdateChapterVisibility from books.schema.mutations.chapter import UpdateChapterVisibility
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, UpdateLastTopic from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, SyncModuleVisibility
from books.schema.mutations.topic import UpdateLastTopic
class BookMutations(object): class BookMutations(object):
@ -11,3 +12,4 @@ class BookMutations(object):
update_last_module = UpdateLastModule.Field() update_last_module = UpdateLastModule.Field()
update_last_topic = UpdateLastTopic.Field() update_last_topic = UpdateLastTopic.Field()
update_chapter_visibility = UpdateChapterVisibility.Field() update_chapter_visibility = UpdateChapterVisibility.Field()
sync_module_visibility = SyncModuleVisibility.Field()

View File

@ -3,9 +3,10 @@ from datetime import datetime
import graphene import graphene
from graphene import relay from graphene import relay
from api.utils import get_errors, get_object from api.utils import get_object
from books.models import Module, Topic, RecentModule from books.models import Module, RecentModule
from books.schema.queries import ModuleNode, TopicNode from books.schema.queries import ModuleNode
from users.models import SchoolClass
class UpdateSolutionVisibility(relay.ClientIDMutation): class UpdateSolutionVisibility(relay.ClientIDMutation):
@ -75,23 +76,30 @@ class UpdateLastModule(relay.ClientIDMutation):
return cls(last_module=last_module.module) return cls(last_module=last_module.module)
class UpdateLastTopic(relay.ClientIDMutation): class SyncModuleVisibility(relay.ClientIDMutation):
class Input: class Input:
# todo: use slug here too module = graphene.String(required=True)
id = graphene.ID() template_school_class = graphene.ID(required=True)
school_class = graphene.ID(required=True)
topic = graphene.Field(TopicNode) success = graphene.Boolean()
@classmethod @classmethod
def mutate_and_get_payload(cls, root, info, **args): def mutate_and_get_payload(cls, root, info, **args):
user = info.context.user user = info.context.user
id = args.get('id') if not user.is_teacher():
raise Exception('Permission denied')
topic = get_object(Topic, id) module_slug = args.get('module')
if not topic: template_id = args.get('template_school_class')
raise Topic.DoesNotExist school_class_id = args.get('school_class')
user.last_topic = topic module = Module.objects.get(slug=module_slug)
user.save() template = get_object(SchoolClass, template_id)
school_class = get_object(SchoolClass, school_class_id)
if not template.is_user_in_schoolclass(user) or not school_class.is_user_in_schoolclass(user):
raise Exception('Permission denied')
return cls(topic=topic) module.sync_from_school_class(template, school_class)
return cls(success=True)

View File

@ -0,0 +1,28 @@
import graphene
from graphene import relay
from api.utils import get_object
from books.models import Topic
from books.schema.queries import TopicNode
class UpdateLastTopic(relay.ClientIDMutation):
class Input:
# todo: use slug here too
id = graphene.ID()
topic = graphene.Field(TopicNode)
@classmethod
def mutate_and_get_payload(cls, root, info, **args):
user = info.context.user
id = args.get('id')
topic = get_object(Topic, id)
if not topic:
raise Topic.DoesNotExist
user.last_topic = topic
user.save()
return cls(topic=topic)

View File

@ -34,6 +34,14 @@ CONTENT_BLOCK_QUERY = """
} }
""" """
SYNC_MUTATION = """
mutation SyncMutationVisibility($input: SyncModuleVisibilityInput!) {
syncModuleVisibility(input: $input) {
success
}
}
"""
class CopyVisibilityForClassesTestCase(TestCase): class CopyVisibilityForClassesTestCase(TestCase):
""" """
@ -52,7 +60,7 @@ class CopyVisibilityForClassesTestCase(TestCase):
""" """
def setUp(self): def setUp(self):
module = ModuleFactory() module = ModuleFactory(slug='some-module')
chapter = Chapter(title='Some Chapter') chapter = Chapter(title='Some Chapter')
module.add_child(instance=chapter) module.add_child(instance=chapter)
create_users() create_users()
@ -110,6 +118,36 @@ class CopyVisibilityForClassesTestCase(TestCase):
}) })
return result return result
def _test_in_sync(self):
# the hidden block is hidden for both now
hidden_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.hidden_content_block)
hidden_for = hidden_result.get('data').get('contentBlock').get('hiddenFor').get('edges')
self.assertTrue('template-class' in map(lambda x: x['node']['name'], hidden_for))
self.assertTrue('class-to-be-synced' in map(lambda x: x['node']['name'], hidden_for))
# the other hidden block is hidden for no one now
other_hidden_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client,
self.other_hidden_content_block)
hidden_for = other_hidden_result.get('data').get('contentBlock').get('hiddenFor').get('edges')
self.assertEqual(len(hidden_for), 0)
# the default block is still hidden for no one
default_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.default_content_block)
hidden_for = default_result.get('data').get('contentBlock').get('hiddenFor').get('edges')
self.assertEqual(len(hidden_for), 0)
# the custom block is visible for both
custom_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.custom_content_block)
visible_for = custom_result.get('data').get('contentBlock').get('visibleFor').get('edges')
self.assertTrue('template-class' in map(lambda x: x['node']['name'], visible_for))
self.assertTrue('class-to-be-synced' in map(lambda x: x['node']['name'], visible_for))
# the other custom block is visible for no one
other_custom_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client,
self.other_custom_content_block)
visible_for = other_custom_result.get('data').get('contentBlock').get('visibleFor').get('edges')
self.assertEqual(len(visible_for), 0)
def test_hidden_for_and_visible_for_set_correctly(self): def test_hidden_for_and_visible_for_set_correctly(self):
self.assertEqual(ContentBlock.objects.count(), 5) self.assertEqual(ContentBlock.objects.count(), 5)
@ -142,31 +180,14 @@ class CopyVisibilityForClassesTestCase(TestCase):
def test_syncs_correctly(self): def test_syncs_correctly(self):
self.module.sync_from_school_class(self.template_school_class, self.school_class_to_be_synced) self.module.sync_from_school_class(self.template_school_class, self.school_class_to_be_synced)
# the hidden block is hidden for both now self._test_in_sync()
hidden_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.hidden_content_block)
hidden_for = hidden_result.get('data').get('contentBlock').get('hiddenFor').get('edges')
self.assertTrue('template-class' in map(lambda x: x['node']['name'], hidden_for))
self.assertTrue('class-to-be-synced' in map(lambda x: x['node']['name'], hidden_for))
# the other hidden block is hidden for no one now def test_mutation(self):
other_hidden_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.teacher_client.execute(SYNC_MUTATION, variables={
self.other_hidden_content_block) 'input': {
hidden_for = other_hidden_result.get('data').get('contentBlock').get('hiddenFor').get('edges') 'module': self.module.slug,
self.assertEqual(len(hidden_for), 0) 'templateSchoolClass': to_global_id('SchoolClassNode', self.template_school_class.pk),
'schoolClass': to_global_id('SchoolClassNode', self.school_class_to_be_synced.pk)
# the default block is still hidden for no one }
default_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.default_content_block) })
hidden_for = default_result.get('data').get('contentBlock').get('hiddenFor').get('edges') self._test_in_sync()
self.assertEqual(len(hidden_for), 0)
# the custom block is visible for both
custom_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client, self.custom_content_block)
visible_for = custom_result.get('data').get('contentBlock').get('visibleFor').get('edges')
self.assertTrue('template-class' in map(lambda x: x['node']['name'], visible_for))
self.assertTrue('class-to-be-synced' in map(lambda x: x['node']['name'], visible_for))
# the other custom block is visible for no one
other_custom_result = self._get_result(CONTENT_BLOCK_QUERY, self.teacher_client,
self.other_custom_content_block)
visible_for = other_custom_result.get('data').get('contentBlock').get('visibleFor').get('edges')
self.assertEqual(len(visible_for), 0)

View File

@ -1,25 +0,0 @@
{
"schema": {
"request": {
"url": "http://localhost:8000/graphql",
"method": "POST",
"postIntrospectionQuery": true,
"options": {
"headers": {
"user-agent": "JS GraphQL"
}
}
}
},
"endpoints": [
{
"name": "Default (http://localhost:8000/graphql",
"url": "http://localhost:8000/graphql",
"options": {
"headers": {
"user-agent": "JS GraphQL"
}
}
}
]
}