Merge branch 'develop'
This commit is contained in:
commit
1774921dca
|
|
@ -10,6 +10,7 @@
|
|||
import DefaultLayout from '@/layouts/DefaultLayout';
|
||||
import SimpleLayout from '@/layouts/SimpleLayout';
|
||||
import BlankLayout from '@/layouts/BlankLayout';
|
||||
import FullScreenLayout from '@/layouts/FullScreenLayout';
|
||||
import Modal from '@/components/Modal';
|
||||
import MobileNavigation from '@/components/MobileNavigation';
|
||||
import NewContentBlockWizard from '@/components/content-block-form/NewContentBlockWizard';
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
DefaultLayout,
|
||||
SimpleLayout,
|
||||
BlankLayout,
|
||||
FullScreenLayout,
|
||||
Modal,
|
||||
MobileNavigation,
|
||||
NewContentBlockWizard,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
import EyeIcon from '@/components/icons/EyeIcon';
|
||||
import PenIcon from '@/components/icons/PenIcon';
|
||||
import TrashIcon from '@/components/icons/TrashIcon';
|
||||
import ModuleRoomSlug from '@/components/content-blocks/ModuleRoomSlug'
|
||||
|
||||
import CHAPTER_QUERY from '@/graphql/gql/chapterQuery.gql';
|
||||
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
|
||||
|
|
@ -93,6 +94,7 @@
|
|||
'genially_block': GeniallyBlock,
|
||||
'subtitle': SubtitleBlock,
|
||||
'content_list': ContentListBlock,
|
||||
'module_room_slug': ModuleRoomSlug,
|
||||
Survey,
|
||||
Solution,
|
||||
Assignment,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<div class="module-slug">
|
||||
<router-link class="button button--primary" :to="{name: 'moduleRoom', params: { slug: value.slug }}">Raum anzeigen
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['value']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
|
||||
.module-slug {
|
||||
margin-bottom: $large-spacing;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import AddRoomEntryButton from '@/components/rooms/AddRoomEntryButton.vue';
|
||||
import RoomEntry from '@/components/rooms/RoomEntry.vue';
|
||||
import RoomGroupWidget from '@/components/rooms/RoomGroupWidget';
|
||||
import EntryCountWidget from '@/components/rooms/EntryCountWidget';
|
||||
import RoomActions from '@/components/rooms/RoomActions';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EntryCountWidget,
|
||||
RoomGroupWidget,
|
||||
AddRoomEntryButton,
|
||||
RoomEntry,
|
||||
RoomActions
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.$store.dispatch('setSpecialContainerClass', '');
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
room: [],
|
||||
entries: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
roomEntryCount() {
|
||||
return (this.room && this.room.roomEntries) ? this.room.roomEntries.length : 0
|
||||
},
|
||||
roomAppearance() {
|
||||
return this.room ? this.room.appearance : ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
:key="assignment.id"
|
||||
class="module-navigation__anchor sub-navigation-item__link"
|
||||
exact-active-class="module-navigation__anchor--active"
|
||||
>{{assignmentTitle(assignment)}}
|
||||
>{{assignment.value.assignment}}
|
||||
</router-link>
|
||||
</sub-navigation-item>
|
||||
<div class="module-navigation__module-content" v-if="false"> <!-- Do not display this for now, might be used later again though -->
|
||||
|
|
@ -41,8 +41,6 @@
|
|||
class="module-navigation__solution-toggle"
|
||||
data-cy="toggle-enable-solutions"></toggle-solutions-for-module>
|
||||
</div>
|
||||
|
||||
|
||||
</nav>
|
||||
|
||||
</template>
|
||||
|
|
@ -79,13 +77,14 @@
|
|||
showResults() {
|
||||
return this.me.permissions.includes('users.can_manage_school_class_content');
|
||||
},
|
||||
assignments() {
|
||||
return [...this.module.assignments].sort((a, b) => {
|
||||
return a.title.toLowerCase() > b.title.toLowerCase() ? 1 : -1;
|
||||
})
|
||||
},
|
||||
canManageContent() {
|
||||
return this.me.permissions.includes('users.can_manage_school_class_content');
|
||||
},
|
||||
assignments() {
|
||||
if (!this.module.chapters) {
|
||||
return [];
|
||||
}
|
||||
return this.extractAssignmentsFromChapters(this.module.chapters, []);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -105,10 +104,47 @@
|
|||
return `#chapter-${index}`
|
||||
},
|
||||
submissionsLink(assignment) {
|
||||
return `/module/${this.module.slug}/submissions/${assignment.id}`;
|
||||
return `/module/${this.module.slug}/submissions/${assignment.value.id}`;
|
||||
},
|
||||
assignmentTitle(assignment) {
|
||||
return assignment.assignment.length > 25 ? assignment.assignment.substring(0, 22) + '...' : assignment.assignment;
|
||||
extractAssignmentsFromChapters(chapters, assignments) {
|
||||
chapters.forEach(node => {
|
||||
if (node.contentBlocks) { // in chapter node
|
||||
// if chapter information is required then do it here like so:
|
||||
// assignments.push({
|
||||
// chapterTitle: node.title
|
||||
// });
|
||||
// return this.extractAssignmentsFromChapters(node.contentBlocks, assignments);
|
||||
assignments = this.extractAssignmentsFromChapters(node.contentBlocks, assignments);
|
||||
} else if (node.contents) {
|
||||
let foundAssignments = [];
|
||||
node.contents.forEach(contentNode => {
|
||||
foundAssignments = this.concatAssignments(foundAssignments, contentNode);
|
||||
});
|
||||
assignments = [...assignments, ...foundAssignments];
|
||||
}
|
||||
});
|
||||
return assignments;
|
||||
},
|
||||
concatAssignments(foundAssignments, node) {
|
||||
let foundAssignment = this.findAssignment(node);
|
||||
return foundAssignment ? [...foundAssignments, ...foundAssignment] : foundAssignments;
|
||||
},
|
||||
findAssignment(node) {
|
||||
if (node.type && node.type === 'assignment') {
|
||||
return [node];
|
||||
} else if (node.type && node.type === 'content_list_item') {
|
||||
let foundAssignments = [];
|
||||
node.value.forEach(contentNode => {
|
||||
foundAssignments = this.concatAssignments(foundAssignments, contentNode);
|
||||
});
|
||||
return this.flattenArray(foundAssignments)
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
flattenArray(arrayToFlatten) {
|
||||
// https://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays
|
||||
return [].concat.apply([], arrayToFlatten);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -156,6 +192,9 @@
|
|||
font-size: 0.875rem;
|
||||
line-height: 1.2rem;
|
||||
margin-bottom: .6875rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
&--active {
|
||||
color: $color-brand;
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@
|
|||
display: grid;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
grid-template-rows: 150px 1fr;
|
||||
-ms-grid-rows: 150px 48px;
|
||||
grid-template-rows: 175px 1fr;
|
||||
-ms-grid-rows: 175px 48px;
|
||||
-ms-grid-columns: 1fr;
|
||||
|
||||
&__content {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@
|
|||
mounted () {
|
||||
if (this.avatarUrl !== '') {
|
||||
this.$refs.fakeImage.addEventListener('load', () => {
|
||||
this.$refs.fakeImage.remove();
|
||||
this.isAvatarLoaded = true;
|
||||
if (this.$refs.fakeImage) {
|
||||
this.$refs.fakeImage.remove();
|
||||
this.isAvatarLoaded = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<checkbox v-if="canToggleSolutions" label="Lösungen für Schüler anzeigen" :checked="enabled"
|
||||
<checkbox v-if="canToggleSolutions" label="Lösungen für Lernende anzeigen" :checked="enabled"
|
||||
@input="toggleSolutions"></checkbox>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
#import "./fragments/roomParts.gql"
|
||||
#import "./fragments/roomEntryParts.gql"
|
||||
query ModuleRoomEntriesQuery($slug: String, $classId: ID!) {
|
||||
moduleRoom(slug: $slug, classId: $classId) {
|
||||
...RoomParts
|
||||
roomEntries {
|
||||
edges {
|
||||
node {
|
||||
...RoomEntryParts
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,74 +35,6 @@
|
|||
<style lang="scss" scoped>
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
@import "@/styles/_default-layout.scss";
|
||||
|
||||
.skillbox {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
grid-template-rows: auto 1fr;
|
||||
min-height: 100vh;
|
||||
grid-auto-rows: 1fr;
|
||||
|
||||
grid-template-areas: "h" "c";
|
||||
padding-bottom: 50px;
|
||||
|
||||
&--show-filter {
|
||||
grid-template-rows: auto auto 1fr;
|
||||
-ms-grid-rows: 50px 50px 30px 1fr; // 1 extra row for gap
|
||||
grid-template-areas: "h" "." "c";
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
|
||||
&--show-filter &__content {
|
||||
-ms-grid-row: 4;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
|
||||
&--show-filter &__filter-bar {
|
||||
-ms-grid-row: 2;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
display: -ms-grid;
|
||||
-ms-grid-rows: 50px 30px auto; // 1 extra row for gap
|
||||
-ms-grid-columns: 1fr;
|
||||
|
||||
@include skillbox-colors;
|
||||
|
||||
&__header {
|
||||
grid-area: h;
|
||||
-ms-grid-row: 1;
|
||||
}
|
||||
|
||||
&__content {
|
||||
-ms-grid-row: 3;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-area: f;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
& > :nth-child(2) {
|
||||
|
||||
}
|
||||
|
||||
& > :nth-child(3) {
|
||||
-ms-grid-row: 4;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="container skillbox" :class="specialContainerClass">
|
||||
<div class="close-button" v-on:click="back">
|
||||
<cross class="close-button__icon"></cross>
|
||||
</div>
|
||||
|
||||
<router-view class="skillbox__content"></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Cross from '@/components/icons/Cross';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Cross
|
||||
},
|
||||
|
||||
computed: {
|
||||
specialContainerClass() {
|
||||
let cls = this.$store.state.specialContainerClass;
|
||||
return [cls ? `skillbox--${cls}` : '']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
this.$router.go(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/_default-layout.scss";
|
||||
|
||||
.close-button {
|
||||
margin-top: $medium-spacing;
|
||||
margin-right: $medium-spacing;
|
||||
justify-self: end;
|
||||
cursor: pointer;
|
||||
|
||||
display:flex;
|
||||
justify-content:end;
|
||||
|
||||
&__icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/_mixins.scss";
|
||||
|
||||
.layout {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="room">
|
||||
<div class="room__header">
|
||||
<h1 class="room__title">{{room.title}}</h1>
|
||||
<p class="room__intro">
|
||||
{{room.description}}
|
||||
</p>
|
||||
<div class="room__meta">
|
||||
<room-group-widget v-bind="room.schoolClass"></room-group-widget>
|
||||
<entry-count-widget :entry-count="roomEntryCount"></entry-count-widget>
|
||||
</div>
|
||||
</div>
|
||||
<div class="room__content">
|
||||
<add-room-entry-button :parent="room" v-if="room.id">
|
||||
<!--
|
||||
the v-if is there for the case where the room hasn't loaded yet, but there is already an attempt to create
|
||||
a new room entry. mainly happens during cypress testing, but could also happen on a very slow connection
|
||||
-->
|
||||
</add-room-entry-button>
|
||||
<room-entry v-for="entry in room.roomEntries" v-bind="entry" :key="entry.id"></room-entry>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MODULE_ROOM_ENTRIES_QUERY from '@/graphql/gql/moduleRoomEntryQuery.gql';
|
||||
import ME_QUERY from '@/graphql/gql/meQuery.gql';
|
||||
import roomMixin from '@/components/mixins/room'
|
||||
|
||||
export default {
|
||||
props: ['slug'],
|
||||
mixins: [roomMixin],
|
||||
|
||||
data() {
|
||||
return {
|
||||
room: [],
|
||||
entries: [],
|
||||
me: {
|
||||
selectedClass: {
|
||||
id: ''
|
||||
},
|
||||
permissions: []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
apollo: {
|
||||
moduleRoom: {
|
||||
query: MODULE_ROOM_ENTRIES_QUERY,
|
||||
variables() {
|
||||
return {
|
||||
slug: this.slug,
|
||||
classId: this.me.selectedClass.id
|
||||
}
|
||||
},
|
||||
// manual: true,
|
||||
// todo: do we really need manual here? update should do the trick too
|
||||
result({data, loading, networkStatus}) {
|
||||
if (!loading) {
|
||||
this.room = Object.assign({}, this.$getRidOfEdges(data).moduleRoom);
|
||||
this.$store.dispatch('setSpecialContainerClass', this.room.appearance);
|
||||
}
|
||||
},
|
||||
pollInterval: 5000,
|
||||
},
|
||||
me: {
|
||||
query: ME_QUERY,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_room.scss";
|
||||
</style>
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
grid-template-columns: minmax(max-content, 840px);
|
||||
}
|
||||
grid-row-gap: 30px;
|
||||
grid-auto-rows: 200px;
|
||||
grid-auto-rows: 225px;
|
||||
max-width: 840px;
|
||||
width: 100vw;
|
||||
/*justify-self: center;*/
|
||||
|
|
|
|||
|
|
@ -25,46 +25,11 @@
|
|||
|
||||
<script>
|
||||
import ROOM_ENTRIES_QUERY from '@/graphql/gql/roomEntriesQuery.gql';
|
||||
|
||||
import AddRoomEntryButton from '@/components/rooms/AddRoomEntryButton.vue';
|
||||
import RoomEntry from '@/components/rooms/RoomEntry.vue';
|
||||
import RoomGroupWidget from '@/components/rooms/RoomGroupWidget';
|
||||
import EntryCountWidget from '@/components/rooms/EntryCountWidget';
|
||||
import RoomActions from '@/components/rooms/RoomActions';
|
||||
import roomMixin from '@/components/mixins/room'
|
||||
|
||||
export default {
|
||||
props: ['slug'],
|
||||
|
||||
components: {
|
||||
EntryCountWidget,
|
||||
RoomGroupWidget,
|
||||
AddRoomEntryButton,
|
||||
RoomEntry,
|
||||
RoomActions
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.$store.dispatch('setSpecialContainerClass', '');
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
room: [],
|
||||
entries: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
roomEntryCount() {
|
||||
return (this.room && this.room.roomEntries) ? this.room.roomEntries.length : 0
|
||||
},
|
||||
roomAppearance() {
|
||||
return this.room ? this.room.appearance : ''
|
||||
}
|
||||
},
|
||||
mixins: [roomMixin],
|
||||
|
||||
apollo: {
|
||||
modules: {
|
||||
|
|
@ -89,54 +54,5 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_functions.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
|
||||
.room {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
margin-bottom: -50px;
|
||||
|
||||
&__header {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
&__intro {
|
||||
font-family: $sans-serif-font-family;
|
||||
font-weight: $font-weight-regular;
|
||||
font-size: toRem(17px);
|
||||
max-width: 900px;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@include desktop {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
justify-content: start;
|
||||
position: relative;
|
||||
|
||||
& > :first-child {
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 50px 15px;
|
||||
background-color: rgba($color-charcoal-dark, 0.18);
|
||||
@include desktop {
|
||||
columns: 4;
|
||||
padding: 50px 60px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@import "@/styles/_room.scss";
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -35,16 +35,16 @@
|
|||
<portfolio-illustration></portfolio-illustration>
|
||||
</section-block>
|
||||
</div>
|
||||
<div class="start-page__news news">
|
||||
<h2 class="news__title">News</h2>
|
||||
<news-teaser date="19. Dezember 2018" title="Bilder eines Jahres"
|
||||
url="https://www.brennpunkt-welt.ch/jahresrückblick-2018/"></news-teaser>
|
||||
<news-teaser date="20. November 2018" title="100 Jahre Erster Weltkrieg"
|
||||
url="http://abunews-1f178193a10edaabff3ab828e30af44.webflow.io/"></news-teaser>
|
||||
<news-teaser date="31. Oktober 2018" title="Sommerzeit - Festivalzeit"
|
||||
url="https://abunews.webflow.io/"></news-teaser>
|
||||
<div class="news__more">Mehr...</div>
|
||||
</div>
|
||||
<!-- <div class="start-page__news news">-->
|
||||
<!-- <h2 class="news__title">News</h2>-->
|
||||
<!-- <news-teaser date="19. Dezember 2018" title="Bilder eines Jahres"-->
|
||||
<!-- url="https://www.brennpunkt-welt.ch/jahresrückblick-2018/"></news-teaser>-->
|
||||
<!-- <news-teaser date="20. November 2018" title="100 Jahre Erster Weltkrieg"-->
|
||||
<!-- url="http://abunews-1f178193a10edaabff3ab828e30af44.webflow.io/"></news-teaser>-->
|
||||
<!-- <news-teaser date="31. Oktober 2018" title="Sommerzeit - Festivalzeit"-->
|
||||
<!-- url="https://abunews.webflow.io/"></news-teaser>-->
|
||||
<!-- <div class="news__more">Mehr...</div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import editProject from '@/pages/editProject'
|
|||
import newProject from '@/pages/newProject'
|
||||
import surveyPage from '@/pages/survey'
|
||||
import styleGuidePage from '@/pages/styleguide'
|
||||
import moduleRoom from '@/pages/moduleRoom'
|
||||
|
||||
import store from '@/store/index';
|
||||
|
||||
|
|
@ -46,13 +47,20 @@ const routes = [
|
|||
name: 'submissions',
|
||||
component: submissions,
|
||||
meta: {filter: true}
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
{path: '/rooms', name: 'rooms', component: rooms, meta: {filter: true}},
|
||||
{path: '/new-room/', name: 'new-room', component: newRoom},
|
||||
{path: '/edit-room/:id', name: 'edit-room', component: editRoom, props: true},
|
||||
{path: '/room/:slug', name: 'room', component: room, props: true},
|
||||
{
|
||||
path: '/module-room/:slug',
|
||||
name: 'moduleRoom',
|
||||
component: moduleRoom,
|
||||
props: true,
|
||||
meta: {layout: 'fullScreen'}
|
||||
},
|
||||
{path: '/article/:slug', name: 'article', component: article, meta: {layout: 'simple'}},
|
||||
{
|
||||
path: '/instruments/:slug',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
|
||||
.skillbox {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
}
|
||||
grid-template-rows: auto 1fr;
|
||||
min-height: 100vh;
|
||||
grid-auto-rows: 1fr;
|
||||
|
||||
grid-template-areas: "h" "c";
|
||||
padding-bottom: 50px;
|
||||
|
||||
&--show-filter {
|
||||
grid-template-rows: auto auto 1fr;
|
||||
-ms-grid-rows: 50px 50px 30px 1fr; // 1 extra row for gap
|
||||
grid-template-areas: "h" "." "c";
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
|
||||
&--show-filter &__content {
|
||||
-ms-grid-row: 4;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
|
||||
&--show-filter &__filter-bar {
|
||||
-ms-grid-row: 2;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
display: -ms-grid;
|
||||
-ms-grid-rows: 50px 30px auto; // 1 extra row for gap
|
||||
-ms-grid-columns: 1fr;
|
||||
|
||||
@include skillbox-colors;
|
||||
|
||||
&__header {
|
||||
grid-area: h;
|
||||
-ms-grid-row: 1;
|
||||
}
|
||||
|
||||
&__content {
|
||||
-ms-grid-row: 3;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-area: f;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* For IE10+
|
||||
*/
|
||||
& > :nth-child(2) {
|
||||
|
||||
}
|
||||
|
||||
& > :nth-child(3) {
|
||||
-ms-grid-row: 4;
|
||||
-ms-grid-column: 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_functions.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
|
||||
.room {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
margin-bottom: -50px;
|
||||
|
||||
&__header {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
&__intro {
|
||||
font-family: $sans-serif-font-family;
|
||||
font-weight: $font-weight-regular;
|
||||
font-size: toRem(17px);
|
||||
max-width: 900px;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@include desktop {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
justify-content: start;
|
||||
position: relative;
|
||||
|
||||
& > :first-child {
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 50px 15px;
|
||||
background-color: rgba($color-charcoal-dark, 0.18);
|
||||
@include desktop {
|
||||
columns: 4;
|
||||
padding: 50px 60px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
@import "reset";
|
||||
@import "typography";
|
||||
@import "variables";
|
||||
@import "default-layout";
|
||||
@import "buttons";
|
||||
@import "forms";
|
||||
@import "uploadcare_overwrite";
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ from portfolio.schema import PortfolioQuery
|
|||
from surveys.schema import SurveysQuery
|
||||
from surveys.mutations import SurveysMutations
|
||||
from rooms.mutations import RoomMutations
|
||||
from rooms.schema import RoomsQuery
|
||||
from rooms.schema import RoomsQuery, ModuleRoomsQuery
|
||||
from users.schema import UsersQuery
|
||||
from users.mutations import ProfileMutations
|
||||
|
||||
|
||||
class Query(UsersQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, StudentSubmissionQuery,
|
||||
class Query(UsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, StudentSubmissionQuery,
|
||||
BasicKnowledgeQuery, PortfolioQuery, MyActivityQuery, SurveysQuery, graphene.ObjectType):
|
||||
node = relay.Node.Field()
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,13 @@ class InstrumentTextBlock(blocks.StructBlock):
|
|||
|
||||
text = blocks.RichTextBlock(features=INSTRUMENTS_RICH_TEXT_FEATURES)
|
||||
|
||||
|
||||
class ModuleRoomSlugBlock(blocks.StructBlock):
|
||||
class Meta:
|
||||
icon = 'link'
|
||||
|
||||
title = blocks.TextBlock()
|
||||
|
||||
# 'text_block' 'task' 'basic_knowledge' 'student_entry' 'image_block'
|
||||
#
|
||||
# url = blocks.URLBlock()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.0.6 on 2019-08-08 06:49
|
||||
|
||||
import assignments.models
|
||||
from django.db import migrations
|
||||
import surveys.models
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
import wagtail.images.blocks
|
||||
import wagtail.snippets.blocks
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('books', '0012_auto_20190722_0932'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contentblock',
|
||||
name='contents',
|
||||
field=wagtail.core.fields.StreamField([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())])), ('content_list_item', wagtail.core.blocks.StreamBlock([('text_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))])), ('basic_knowledge', wagtail.core.blocks.StructBlock([('description', wagtail.core.blocks.RichTextBlock(required=False)), ('basic_knowledge', wagtail.core.blocks.PageChooserBlock(required=True, target_model=['basicknowledge.BasicKnowledge']))])), ('assignment', wagtail.core.blocks.StructBlock([('assignment_id', wagtail.snippets.blocks.SnippetChooserBlock(assignments.models.Assignment))])), ('survey', wagtail.core.blocks.StructBlock([('survey_id', wagtail.snippets.blocks.SnippetChooserBlock(surveys.models.Survey))])), ('image_block', wagtail.images.blocks.ImageChooserBlock()), ('image_url_block', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('link_block', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock()), ('url', wagtail.core.blocks.URLBlock())])), ('solution', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.RichTextBlock(features=['ul']))], icon='tick')), ('video_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('document_block', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('infogram_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock()), ('title', wagtail.core.blocks.TextBlock())])), ('genially_block', wagtail.core.blocks.StructBlock([('id', wagtail.core.blocks.TextBlock())])), ('subtitle', wagtail.core.blocks.StructBlock([('text', wagtail.core.blocks.TextBlock())])), ('module_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -7,7 +7,7 @@ from wagtail.core.fields import StreamField
|
|||
from wagtail.images.blocks import ImageChooserBlock
|
||||
|
||||
from books.blocks import TextBlock, BasicKnowledgeBlock, LinkBlock, VideoBlock, DocumentBlock, \
|
||||
ImageUrlBlock, AssignmentBlock, InfogramBlock, GeniallyBlock, SubtitleBlock, SurveyBlock
|
||||
ImageUrlBlock, AssignmentBlock, InfogramBlock, GeniallyBlock, SubtitleBlock, SurveyBlock, ModuleRoomSlugBlock
|
||||
from core.wagtail_utils import StrictHierarchyPage
|
||||
from users.models import SchoolClass
|
||||
|
||||
|
|
@ -48,7 +48,8 @@ class ContentBlock(StrictHierarchyPage):
|
|||
('document_block', DocumentBlock()),
|
||||
('infogram_block', InfogramBlock()),
|
||||
('genially_block', GeniallyBlock()),
|
||||
('subtitle', SubtitleBlock())
|
||||
('subtitle', SubtitleBlock()),
|
||||
('module_room_slug', ModuleRoomSlugBlock())
|
||||
]
|
||||
|
||||
content_list_item = StreamBlock(content_blocks)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from graphene_django.filter import DjangoFilterConnectionField
|
|||
|
||||
from api.utils import get_object
|
||||
from books.utils import are_solutions_enabled_for
|
||||
from rooms.models import ModuleRoomSlug
|
||||
from ..models import Book, Topic, Module, Chapter, ContentBlock
|
||||
|
||||
|
||||
|
|
@ -25,9 +26,23 @@ class ContentBlockNode(DjangoObjectType):
|
|||
return self.owner is not None and self.owner.pk == info.context.user.pk
|
||||
|
||||
def resolve_contents(self, info, **kwargs):
|
||||
if not are_solutions_enabled_for(info.context.user, self.module):
|
||||
self.contents.stream_data = [content for content in self.contents.stream_data if
|
||||
content['type'] != 'solution']
|
||||
updated_stream_data = []
|
||||
for content in self.contents.stream_data:
|
||||
if not are_solutions_enabled_for(info.context.user, self.module) and content['type'] == 'solution':
|
||||
continue
|
||||
|
||||
if content['type'] == 'module_room_slug':
|
||||
try:
|
||||
module_room_slug = ModuleRoomSlug.objects.get(title=content['value']['title'])
|
||||
content['value'] = {
|
||||
'title': content['value']['title'],
|
||||
'slug': module_room_slug.slug
|
||||
}
|
||||
except ModuleRoomSlug.DoesNotExist:
|
||||
pass
|
||||
updated_stream_data.append(content)
|
||||
|
||||
self.contents.stream_data = updated_stream_data
|
||||
return self.contents
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from rooms.models import Room, RoomEntry
|
||||
from rooms.models import Room, RoomEntry, ModuleRoomSlug
|
||||
|
||||
|
||||
@admin.register(Room)
|
||||
|
|
@ -13,3 +13,9 @@ class RoomAdmin(admin.ModelAdmin):
|
|||
class RoomEntryAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'slug', 'title', 'room', 'author')
|
||||
list_filter = ('room', 'author')
|
||||
|
||||
|
||||
@admin.register(ModuleRoomSlug)
|
||||
class AdminGeneratedRoomSlugAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'slug', 'title')
|
||||
list_filter = ('slug', 'title')
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from wagtail.core.rich_text import RichText
|
|||
|
||||
from books.factories import TextBlockFactory, ImageUrlBlockFactory, LinkBlockFactory
|
||||
from core.factories import fake, fake_paragraph
|
||||
from rooms.models import Room, RoomEntry
|
||||
from rooms.models import Room, RoomEntry, ModuleRoomSlug
|
||||
from users.models import SchoolClass
|
||||
|
||||
|
||||
|
|
@ -77,3 +77,12 @@ class RoomEntryFactory(factory.django.DjangoModelFactory):
|
|||
def create(cls, **kwargs):
|
||||
cls.stream_field_magic(kwargs, 'contents')
|
||||
return cls._generate(CREATE_STRATEGY, kwargs)
|
||||
|
||||
|
||||
class ModuleRoomSlugFactory(factory.django.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = ModuleRoomSlug
|
||||
|
||||
slug = factory.Sequence(lambda n: u'slug-{:d}'.format(n))
|
||||
title = factory.Sequence(lambda n: u'Title {:d}'.format(n))
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 2.0.6 on 2019-08-08 06:49
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_extensions.db.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rooms', '0006_auto_20190722_0932'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ModuleRoomSlug',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255, verbose_name='title')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='description')),
|
||||
('slug', django_extensions.db.fields.AutoSlugField(blank=True, editable=False, populate_from='title', verbose_name='slug')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='user_created',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -15,6 +15,7 @@ class Room(TitleSlugDescriptionModel):
|
|||
|
||||
school_class = models.ForeignKey(SchoolClass, blank=False, null=False, on_delete=models.CASCADE, related_name='rooms')
|
||||
appearance = models.CharField(blank=True, null=False, max_length=255)
|
||||
user_created = models.BooleanField(blank=False, null=False, default=True)
|
||||
|
||||
def __str__(self):
|
||||
return 'Room {}-{}-{}'.format(self.id, self.title, self.school_class)
|
||||
|
|
@ -41,3 +42,9 @@ class RoomEntry(TitleSlugDescriptionModel):
|
|||
|
||||
def can_user_see_entry(self, user):
|
||||
return user.is_superuser or self.room.school_class.is_user_in_schoolclass(user)
|
||||
|
||||
|
||||
class ModuleRoomSlug(TitleSlugDescriptionModel):
|
||||
|
||||
def __str__(self):
|
||||
return 'ModuleRoomSlug {}-{}'.format(self.id, self.title)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ from graphene_django import DjangoObjectType
|
|||
from graphene_django.filter import DjangoFilterConnectionField
|
||||
|
||||
from api.utils import get_object, get_by_id_or_slug
|
||||
from rooms.models import Room, RoomEntry
|
||||
from rooms.models import Room, RoomEntry, ModuleRoomSlug
|
||||
from users.models import SchoolClass
|
||||
from users.schema import UserNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -53,7 +54,7 @@ class RoomsQuery(object):
|
|||
user = info.context.user
|
||||
if user.is_superuser:
|
||||
return Room.objects.all()
|
||||
return Room.objects.filter(school_class__in=user.school_classes.all())
|
||||
return Room.objects.filter(school_class__in=user.school_classes.all()).exclude(user_created=False)
|
||||
|
||||
def resolve_room(self, info, **kwargs):
|
||||
room = get_by_id_or_slug(Room, **kwargs)
|
||||
|
|
@ -82,3 +83,30 @@ class RoomsQuery(object):
|
|||
return RoomEntry.objects.none()
|
||||
else:
|
||||
return RoomEntry.objects.all()
|
||||
|
||||
|
||||
class ModuleRoomsQuery(object):
|
||||
|
||||
module_room = graphene.Field(RoomNode, slug=graphene.String(), class_id=graphene.ID())
|
||||
|
||||
def resolve_module_room(self, info, **kwargs):
|
||||
schoolclass = get_object(SchoolClass, kwargs.get('class_id'))
|
||||
|
||||
try:
|
||||
slug = ModuleRoomSlug.objects.get(slug=kwargs.get('slug'))
|
||||
except ModuleRoomSlug.DoesNotExist:
|
||||
return None
|
||||
|
||||
if schoolclass is None or not schoolclass.is_user_in_schoolclass(info.context.user):
|
||||
return None
|
||||
|
||||
room, created = Room.objects.get_or_create(school_class=schoolclass, user_created=False, slug=slug.slug,
|
||||
title=slug.title, appearance='blue')
|
||||
if created:
|
||||
room.slug = slug.slug
|
||||
room.save()
|
||||
|
||||
if not room.user_created and room.school_class.is_user_in_schoolclass(info.context.user):
|
||||
return room
|
||||
else:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# ITerativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2019 ITerativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 2019-08-07
|
||||
# @author: chrigu <christian.cueni@iterativ.ch>
|
||||
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 RoomFactory, ModuleRoomSlugFactory
|
||||
from users.factories import SchoolClassFactory
|
||||
|
||||
|
||||
class AdminRoomQueryPermission(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user = UserFactory(username='aschi')
|
||||
self.another_user = UserFactory(username='pesche')
|
||||
self.sc1 = SchoolClassFactory(users=[self.user])
|
||||
sc2 = SchoolClassFactory(users=[self.another_user])
|
||||
self.room1 = RoomFactory(school_class=self.sc1)
|
||||
self.room2 = RoomFactory(school_class=sc2)
|
||||
|
||||
self.module_room_slug = ModuleRoomSlugFactory(title='some title')
|
||||
|
||||
self.sc1_id = to_global_id('SchoolClass', self.sc1.pk)
|
||||
self.sc2_id = to_global_id('SchoolClass', sc2.pk)
|
||||
|
||||
request = RequestFactory().get('/')
|
||||
request.user = self.user
|
||||
self.client = Client(schema=schema, context_value=request)
|
||||
|
||||
self.query = '''
|
||||
query ModuleRoomEntriesQuery($slug: String, $classId: ID!) {
|
||||
moduleRoom(slug: $slug, classId: $classId) {
|
||||
title
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
def test_should_return_none_if_slug_does_not_exist(self):
|
||||
|
||||
result = self.client.execute(self.query, variables={
|
||||
'slug': 'no-slug',
|
||||
'classId': 'norealId'
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.get('data').get('moduleRoom'))
|
||||
|
||||
def test_should_return_none_if_class_id_does_not_exist(self):
|
||||
|
||||
result = self.client.execute(self.query, variables={
|
||||
'slug': 'no-slug',
|
||||
'classId': 'norealId'
|
||||
})
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.get('data').get('moduleRoom'))
|
||||
|
||||
def test_user_should_not_be_able_to_create_room_for_other_class(self):
|
||||
|
||||
result = self.client.execute(self.query, variables={
|
||||
'slug': self.module_room_slug.slug,
|
||||
'classId': self.sc2_id
|
||||
})
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertIsNone(result.get('data').get('moduleRoom'))
|
||||
|
||||
def test_should_create_room_if_none_exists(self):
|
||||
|
||||
result = self.client.execute(self.query, variables={
|
||||
'slug': self.module_room_slug.slug,
|
||||
'classId': self.sc1_id
|
||||
})
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('moduleRoom').get('title'), self.module_room_slug.title)
|
||||
|
||||
def test_should_return_room_if_one_exists(self):
|
||||
|
||||
existing_room = RoomFactory(school_class=self.sc1, user_created=False)
|
||||
admin_slug = ModuleRoomSlugFactory(slug=existing_room.slug, title=existing_room.title)
|
||||
|
||||
result = self.client.execute(self.query, variables={
|
||||
'slug': admin_slug.slug,
|
||||
'classId': self.sc1_id
|
||||
})
|
||||
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('moduleRoom').get('title'), existing_room.title)
|
||||
|
|
@ -61,6 +61,27 @@ class RoomQueryPermission(TestCase):
|
|||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(result.get('data').get('room'), None)
|
||||
|
||||
def test_student_should_only_user_created_rooms(self):
|
||||
|
||||
modlue_room = RoomFactory(school_class=self.room1.school_class, user_created=False)
|
||||
|
||||
query = '''
|
||||
query {
|
||||
rooms {
|
||||
edges {
|
||||
node {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
result = self.client.execute(query)
|
||||
self.assertIsNone(result.get('errors'))
|
||||
self.assertEqual(len(result.get('data').get('rooms').get('edges')), 1)
|
||||
self.assertNotEqual(result.get('data').get('rooms').get('edges')[0].get('node').get('title'), modlue_room.title)
|
||||
|
||||
|
||||
class RoomEntryQueryPermissions(TestCase):
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# ITerativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2019 ITerativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 2019-08-05
|
||||
# @author: chrigu <christian.cueni@iterativ.ch>
|
||||
from wagtail.core import hooks
|
||||
|
||||
from rooms.models import ModuleRoomSlug
|
||||
|
||||
|
||||
@hooks.register('after_edit_page')
|
||||
@hooks.register('after_create_page')
|
||||
def do_after_page_edit(request, page):
|
||||
blocks = get_room_blocks(page)
|
||||
for block in blocks:
|
||||
if isinstance(block, tuple):
|
||||
title = block[1]['title']
|
||||
if isinstance(block, dict):
|
||||
title = block['value']['title']
|
||||
ModuleRoomSlug.objects.get_or_create(title=title)
|
||||
|
||||
|
||||
def get_room_blocks(page):
|
||||
top_level_module_room_slug_blocks = get_block_from_stream_data(page.contents.stream_data, 'module_room_slug')
|
||||
content_list_module_room_slug_blocks = get_admin_slugs_from_content_list(page.contents.stream_data)
|
||||
return top_level_module_room_slug_blocks + content_list_module_room_slug_blocks
|
||||
|
||||
|
||||
def get_block_from_stream_data(stream_data, block_name):
|
||||
if isinstance(stream_data[0], tuple):
|
||||
return [block for block in stream_data if block[0] in [block_name]]
|
||||
if isinstance(stream_data[0], dict):
|
||||
return [block for block in stream_data if block['type'] in [block_name]]
|
||||
return []
|
||||
|
||||
|
||||
def get_admin_slugs_from_content_list(stream_data):
|
||||
module_room_slug_blocks = []
|
||||
content_list_items = get_block_from_stream_data(stream_data, 'content_list_item')
|
||||
for content_list_item in content_list_items:
|
||||
module_room_slug_blocks = module_room_slug_blocks + get_block_from_stream_data(content_list_item[1].stream_data,
|
||||
'module_room_slug')
|
||||
return module_room_slug_blocks
|
||||
Loading…
Reference in New Issue