Rename block, update frontend

This commit is contained in:
Christian Cueni 2019-08-08 12:58:37 +02:00
parent 8e0f9fd377
commit 2fa006d790
27 changed files with 410 additions and 210 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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>

View File

@ -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 : ''
}
}
}

View File

@ -25,8 +25,10 @@
mounted () {
if (this.avatarUrl !== '') {
this.$refs.fakeImage.addEventListener('load', () => {
if (this.$refs.fakeImage) {
this.$refs.fakeImage.remove();
this.isAvatarLoaded = true;
}
});
};
}

View File

@ -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
}
}
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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',

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -6,6 +6,7 @@
@import "reset";
@import "typography";
@import "variables";
@import "default-layout";
@import "buttons";
@import "forms";
@import "uploadcare_overwrite";

View File

@ -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, AdminRoomsQuery
from rooms.schema import RoomsQuery, ModuleRoomsQuery
from users.schema import UsersQuery
from users.mutations import ProfileMutations
class Query(UsersQuery, AdminRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, StudentSubmissionQuery,
class Query(UsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQuery, BookQuery, AssignmentsQuery, StudentSubmissionQuery,
BasicKnowledgeQuery, PortfolioQuery, MyActivityQuery, SurveysQuery, graphene.ObjectType):
node = relay.Node.Field()

View File

@ -99,7 +99,7 @@ class InstrumentTextBlock(blocks.StructBlock):
text = blocks.RichTextBlock(features=INSTRUMENTS_RICH_TEXT_FEATURES)
class AdminRoomSlugBlock(blocks.StructBlock):
class ModuleRoomSlugBlock(blocks.StructBlock):
class Meta:
icon = 'link'

View File

@ -1,4 +1,4 @@
# Generated by Django 2.0.6 on 2019-08-07 13:40
# Generated by Django 2.0.6 on 2019-08-08 06:49
import assignments.models
from django.db import migrations
@ -19,6 +19,6 @@ class Migration(migrations.Migration):
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())])), ('admin_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())])), ('admin_room_slug', wagtail.core.blocks.StructBlock([('title', wagtail.core.blocks.TextBlock())]))]))], blank=True, null=True),
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),
),
]

View File

@ -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, AdminRoomSlugBlock
ImageUrlBlock, AssignmentBlock, InfogramBlock, GeniallyBlock, SubtitleBlock, SurveyBlock, ModuleRoomSlugBlock
from core.wagtail_utils import StrictHierarchyPage
from users.models import SchoolClass
@ -49,7 +49,7 @@ class ContentBlock(StrictHierarchyPage):
('infogram_block', InfogramBlock()),
('genially_block', GeniallyBlock()),
('subtitle', SubtitleBlock()),
('admin_room_slug', AdminRoomSlugBlock())
('module_room_slug', ModuleRoomSlugBlock())
]
content_list_item = StreamBlock(content_blocks)

View File

@ -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

View File

@ -1,6 +1,6 @@
from django.contrib import admin
from rooms.models import Room, RoomEntry, AdminGeneratedRoomSlug
from rooms.models import Room, RoomEntry, ModuleRoomSlug
@admin.register(Room)
@ -15,7 +15,7 @@ class RoomEntryAdmin(admin.ModelAdmin):
list_filter = ('room', 'author')
@admin.register(AdminGeneratedRoomSlug)
@admin.register(ModuleRoomSlug)
class AdminGeneratedRoomSlugAdmin(admin.ModelAdmin):
list_display = ('id', 'slug', 'title')
list_filter = ('slug', 'title')

View File

@ -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, AdminGeneratedRoomSlug
from rooms.models import Room, RoomEntry, ModuleRoomSlug
from users.models import SchoolClass
@ -79,9 +79,9 @@ class RoomEntryFactory(factory.django.DjangoModelFactory):
return cls._generate(CREATE_STRATEGY, kwargs)
class AdminGeneratedRoomSlugFactory(factory.django.DjangoModelFactory):
class ModuleRoomSlugFactory(factory.django.DjangoModelFactory):
class Meta:
model = AdminGeneratedRoomSlug
model = ModuleRoomSlug
slug = factory.Sequence(lambda n: u'slug-{:d}'.format(n))
title = factory.Sequence(lambda n: u'Title {:d}'.format(n))

View File

@ -1,4 +1,4 @@
# Generated by Django 2.0.6 on 2019-08-07 13:23
# Generated by Django 2.0.6 on 2019-08-08 06:49
from django.db import migrations, models
import django_extensions.db.fields
@ -12,7 +12,7 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='AdminGeneratedRoomSlug',
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')),

View File

@ -44,7 +44,7 @@ class RoomEntry(TitleSlugDescriptionModel):
return user.is_superuser or self.room.school_class.is_user_in_schoolclass(user)
class AdminGeneratedRoomSlug(TitleSlugDescriptionModel):
class ModuleRoomSlug(TitleSlugDescriptionModel):
def __str__(self):
return 'AdmimSlug {}-{}'.format(self.id, self.title)
return 'ModuleRoomSlug {}-{}'.format(self.id, self.title)

View File

@ -6,7 +6,7 @@ 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, AdminGeneratedRoomSlug
from rooms.models import Room, RoomEntry, ModuleRoomSlug
from users.models import SchoolClass
from users.schema import UserNode
@ -85,25 +85,27 @@ class RoomsQuery(object):
return RoomEntry.objects.all()
class AdminRoomsQuery(object):
class ModuleRoomsQuery(object):
admin_room = graphene.Field(RoomNode, slug=graphene.String(), class_id=graphene.ID())
module_room = graphene.Field(RoomNode, slug=graphene.String(), class_id=graphene.ID())
def resolve_admin_room(self, info, **kwargs):
slug = kwargs.get('slug')
def resolve_module_room(self, info, **kwargs):
schoolclass = get_object(SchoolClass, kwargs.get('class_id'))
try:
slug = AdminGeneratedRoomSlug.objects.get(slug=slug)
except AdminGeneratedRoomSlug.DoesNotExist:
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,
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:

View File

@ -13,7 +13,7 @@ from graphql_relay import to_global_id
from api.schema import schema
from core.factories import UserFactory
from rooms.factories import RoomFactory, AdminGeneratedRoomSlugFactory
from rooms.factories import RoomFactory, ModuleRoomSlugFactory
from users.factories import SchoolClassFactory
@ -27,7 +27,7 @@ class AdminRoomQueryPermission(TestCase):
self.room1 = RoomFactory(school_class=self.sc1)
self.room2 = RoomFactory(school_class=sc2)
self.admin_slug = AdminGeneratedRoomSlugFactory(title='some title')
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)
@ -37,8 +37,8 @@ class AdminRoomQueryPermission(TestCase):
self.client = Client(schema=schema, context_value=request)
self.query = '''
query AdminRoomQuery($slug: String, $classId: ID!) {
adminRoom(slug: $slug, classId: $classId) {
query ModuleRoomEntriesQuery($slug: String, $classId: ID!) {
moduleRoom(slug: $slug, classId: $classId) {
title
}
}
@ -51,7 +51,7 @@ class AdminRoomQueryPermission(TestCase):
'classId': 'norealId'
})
self.assertIsNone(result.get('errors'))
self.assertIsNone(result.get('data').get('adminRoom'))
self.assertIsNone(result.get('data').get('moduleRoom'))
def test_should_return_none_if_class_id_does_not_exist(self):
@ -60,32 +60,32 @@ class AdminRoomQueryPermission(TestCase):
'classId': 'norealId'
})
self.assertIsNone(result.get('errors'))
self.assertIsNone(result.get('data').get('adminRoom'))
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.admin_slug.slug,
'slug': self.module_room_slug.slug,
'classId': self.sc2_id
})
self.assertIsNone(result.get('errors'))
self.assertIsNone(result.get('data').get('adminRoom'))
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.admin_slug.slug,
'slug': self.module_room_slug.slug,
'classId': self.sc1_id
})
self.assertIsNone(result.get('errors'))
self.assertEqual(result.get('data').get('adminRoom').get('title'), self.admin_slug.title)
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 = AdminGeneratedRoomSlugFactory(slug=existing_room.slug, title=existing_room.title)
admin_slug = ModuleRoomSlugFactory(slug=existing_room.slug, title=existing_room.title)
result = self.client.execute(self.query, variables={
'slug': admin_slug.slug,
@ -93,4 +93,4 @@ class AdminRoomQueryPermission(TestCase):
})
self.assertIsNone(result.get('errors'))
self.assertEqual(result.get('data').get('adminRoom').get('title'), existing_room.title)
self.assertEqual(result.get('data').get('moduleRoom').get('title'), existing_room.title)

View File

@ -63,7 +63,7 @@ class RoomQueryPermission(TestCase):
def test_student_should_only_user_created_rooms(self):
admin_room = RoomFactory(school_class=self.room1.school_class, user_created=False)
modlue_room = RoomFactory(school_class=self.room1.school_class, user_created=False)
query = '''
query {
@ -80,7 +80,7 @@ class RoomQueryPermission(TestCase):
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'), admin_room.title)
self.assertNotEqual(result.get('data').get('rooms').get('edges')[0].get('node').get('title'), modlue_room.title)
class RoomEntryQueryPermissions(TestCase):

View File

@ -9,7 +9,7 @@
# @author: chrigu <christian.cueni@iterativ.ch>
from wagtail.core import hooks
from rooms.models import AdminGeneratedRoomSlug
from rooms.models import ModuleRoomSlug
@hooks.register('after_edit_page')
@ -21,13 +21,13 @@ def do_after_page_edit(request, page):
title = block[1]['title']
if isinstance(block, dict):
title = block['value']['title']
AdminGeneratedRoomSlug.objects.get_or_create(title=title)
ModuleRoomSlug.objects.get_or_create(title=title)
def get_room_blocks(page):
top_level_admin_slug_blocks = get_block_from_stream_data(page.contents.stream_data, 'admin_room_slug')
content_list_admin_slug_blocks = get_admin_slugs_from_content_list(page.contents.stream_data)
return top_level_admin_slug_blocks + content_list_admin_slug_blocks
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):
@ -39,9 +39,9 @@ def get_block_from_stream_data(stream_data, block_name):
def get_admin_slugs_from_content_list(stream_data):
admin_slug_blocks = []
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:
admin_slug_blocks = admin_slug_blocks + get_block_from_stream_data(content_list_item[1].stream_data,
'admin_room_slug')
return admin_slug_blocks
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