diff --git a/client/src/App.vue b/client/src/App.vue index 35725e99..8e26ed22 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -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, diff --git a/client/src/components/ContentBlock.vue b/client/src/components/ContentBlock.vue index 1be89d92..f15b1161 100644 --- a/client/src/components/ContentBlock.vue +++ b/client/src/components/ContentBlock.vue @@ -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, diff --git a/client/src/components/content-blocks/ModuleRoomSlug.vue b/client/src/components/content-blocks/ModuleRoomSlug.vue new file mode 100644 index 00000000..b5f2f686 --- /dev/null +++ b/client/src/components/content-blocks/ModuleRoomSlug.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/client/src/components/mixins/room.js b/client/src/components/mixins/room.js new file mode 100644 index 00000000..6059b87e --- /dev/null +++ b/client/src/components/mixins/room.js @@ -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 : '' + } + } +} diff --git a/client/src/components/profile/Avatar.vue b/client/src/components/profile/Avatar.vue index 8e781a7e..7d19d570 100644 --- a/client/src/components/profile/Avatar.vue +++ b/client/src/components/profile/Avatar.vue @@ -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; + } }); }; } diff --git a/client/src/graphql/gql/moduleRoomEntryQuery.gql b/client/src/graphql/gql/moduleRoomEntryQuery.gql new file mode 100644 index 00000000..5f0d275d --- /dev/null +++ b/client/src/graphql/gql/moduleRoomEntryQuery.gql @@ -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 + } + } + } + } +} diff --git a/client/src/layouts/DefaultLayout.vue b/client/src/layouts/DefaultLayout.vue index d9e05517..b29dabc7 100644 --- a/client/src/layouts/DefaultLayout.vue +++ b/client/src/layouts/DefaultLayout.vue @@ -35,74 +35,6 @@ diff --git a/client/src/layouts/FullScreenLayout.vue b/client/src/layouts/FullScreenLayout.vue new file mode 100644 index 00000000..446edf75 --- /dev/null +++ b/client/src/layouts/FullScreenLayout.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/client/src/pages/moduleRoom.vue b/client/src/pages/moduleRoom.vue new file mode 100644 index 00000000..556f85de --- /dev/null +++ b/client/src/pages/moduleRoom.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/client/src/pages/room.vue b/client/src/pages/room.vue index 9b781af1..bc527133 100644 --- a/client/src/pages/room.vue +++ b/client/src/pages/room.vue @@ -25,46 +25,11 @@ diff --git a/client/src/router/index.js b/client/src/router/index.js index dc9384eb..fac2196a 100644 --- a/client/src/router/index.js +++ b/client/src/router/index.js @@ -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', diff --git a/client/src/styles/_default-layout.scss b/client/src/styles/_default-layout.scss new file mode 100644 index 00000000..d6fd7f87 --- /dev/null +++ b/client/src/styles/_default-layout.scss @@ -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; + } +} diff --git a/client/src/styles/_room.scss b/client/src/styles/_room.scss new file mode 100644 index 00000000..abb484af --- /dev/null +++ b/client/src/styles/_room.scss @@ -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; + } + + } +} diff --git a/client/src/styles/main.scss b/client/src/styles/main.scss index 92f46300..74e4914d 100644 --- a/client/src/styles/main.scss +++ b/client/src/styles/main.scss @@ -6,6 +6,7 @@ @import "reset"; @import "typography"; @import "variables"; +@import "default-layout"; @import "buttons"; @import "forms"; @import "uploadcare_overwrite"; diff --git a/server/api/schema.py b/server/api/schema.py index b4800f09..68436053 100644 --- a/server/api/schema.py +++ b/server/api/schema.py @@ -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() diff --git a/server/books/blocks.py b/server/books/blocks.py index d2f8f560..fb7b6df7 100644 --- a/server/books/blocks.py +++ b/server/books/blocks.py @@ -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' diff --git a/server/books/migrations/0013_auto_20190807_1340.py b/server/books/migrations/0013_auto_20190808_0649.py similarity index 52% rename from server/books/migrations/0013_auto_20190807_1340.py rename to server/books/migrations/0013_auto_20190808_0649.py index 34bc13f8..41454741 100644 --- a/server/books/migrations/0013_auto_20190807_1340.py +++ b/server/books/migrations/0013_auto_20190808_0649.py @@ -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), ), ] diff --git a/server/books/models/contentblock.py b/server/books/models/contentblock.py index a4bab50f..0551635c 100644 --- a/server/books/models/contentblock.py +++ b/server/books/models/contentblock.py @@ -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) diff --git a/server/books/schema/queries.py b/server/books/schema/queries.py index 478dc614..2eae1eab 100644 --- a/server/books/schema/queries.py +++ b/server/books/schema/queries.py @@ -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 diff --git a/server/rooms/admin.py b/server/rooms/admin.py index c1c4a702..128859ef 100644 --- a/server/rooms/admin.py +++ b/server/rooms/admin.py @@ -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') diff --git a/server/rooms/factories.py b/server/rooms/factories.py index d34e1532..9a33f956 100644 --- a/server/rooms/factories.py +++ b/server/rooms/factories.py @@ -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)) diff --git a/server/rooms/migrations/0007_auto_20190807_1323.py b/server/rooms/migrations/0007_auto_20190808_0649.py similarity index 91% rename from server/rooms/migrations/0007_auto_20190807_1323.py rename to server/rooms/migrations/0007_auto_20190808_0649.py index 59e7e654..a3d7283e 100644 --- a/server/rooms/migrations/0007_auto_20190807_1323.py +++ b/server/rooms/migrations/0007_auto_20190808_0649.py @@ -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')), diff --git a/server/rooms/models.py b/server/rooms/models.py index 44e43659..097638db 100644 --- a/server/rooms/models.py +++ b/server/rooms/models.py @@ -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) diff --git a/server/rooms/schema.py b/server/rooms/schema.py index 5f5a506c..e9bc1306 100644 --- a/server/rooms/schema.py +++ b/server/rooms/schema.py @@ -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: diff --git a/server/rooms/tests/test_admin_room_query.py b/server/rooms/tests/test_module_room_query.py similarity index 74% rename from server/rooms/tests/test_admin_room_query.py rename to server/rooms/tests/test_module_room_query.py index e64b23ab..fd451f5c 100644 --- a/server/rooms/tests/test_admin_room_query.py +++ b/server/rooms/tests/test_module_room_query.py @@ -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) diff --git a/server/rooms/tests/test_room_query_permission.py b/server/rooms/tests/test_room_query_permission.py index a4b35b6e..f20490f8 100644 --- a/server/rooms/tests/test_room_query_permission.py +++ b/server/rooms/tests/test_room_query_permission.py @@ -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): diff --git a/server/rooms/wagtail_hooks.py b/server/rooms/wagtail_hooks.py index cc28d9aa..22db624a 100644 --- a/server/rooms/wagtail_hooks.py +++ b/server/rooms/wagtail_hooks.py @@ -9,7 +9,7 @@ # @author: chrigu 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