Add module visibility sync mutation
This commit is contained in:
parent
209838dadb
commit
9490ffd443
|
|
@ -0,0 +1,5 @@
|
||||||
|
describe('Survey', () => {
|
||||||
|
it('needs to be implemented', () => {
|
||||||
|
expect(true).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
mutation SyncModuleVisibility($input: SyncModuleVisibilityInput!) {
|
||||||
|
syncModuleVisibility(input: $input) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const SUBMISSIONS_PAGE = 'submissions';
|
||||||
|
export const MODULE_PAGE = 'module';
|
||||||
|
export const VISIBILITY_PAGE = 'visibility';
|
||||||
|
|
@ -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
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
@ -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')
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue