From 8bd6d51028a3a92253f095ed323a301a63c7ff3f Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 23 Jul 2019 15:59:25 +0200
Subject: [PATCH 01/15] Add new SVGs for icons
---
client/src/components/AddContentBlockButton.vue | 2 +-
client/src/components/icons/AddPointer.vue | 5 +++--
client/src/components/icons/EyeIcon.vue | 4 +---
.../{ => toggle-menu}/ToggleSolutionsForModule.vue | 0
4 files changed, 5 insertions(+), 6 deletions(-)
rename client/src/components/{ => toggle-menu}/ToggleSolutionsForModule.vue (100%)
diff --git a/client/src/components/AddContentBlockButton.vue b/client/src/components/AddContentBlockButton.vue
index 9af880d0..66efb655 100644
--- a/client/src/components/AddContentBlockButton.vue
+++ b/client/src/components/AddContentBlockButton.vue
@@ -46,7 +46,7 @@
}
&__icon {
- height: 57px;
+ width: 40px;
fill: $color-silver-dark;
}
}
diff --git a/client/src/components/icons/AddPointer.vue b/client/src/components/icons/AddPointer.vue
index a241a274..b878eccc 100644
--- a/client/src/components/icons/AddPointer.vue
+++ b/client/src/components/icons/AddPointer.vue
@@ -1,7 +1,8 @@
diff --git a/client/src/components/icons/EyeIcon.vue b/client/src/components/icons/EyeIcon.vue
index 20d557a6..05e7cb03 100644
--- a/client/src/components/icons/EyeIcon.vue
+++ b/client/src/components/icons/EyeIcon.vue
@@ -1,8 +1,6 @@
diff --git a/client/src/components/ToggleSolutionsForModule.vue b/client/src/components/toggle-menu/ToggleSolutionsForModule.vue
similarity index 100%
rename from client/src/components/ToggleSolutionsForModule.vue
rename to client/src/components/toggle-menu/ToggleSolutionsForModule.vue
From a4cf7a0d62fbb4b35e166d8a1b1b41e188a32a7f Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 23 Jul 2019 16:00:53 +0200
Subject: [PATCH 02/15] Add toggle for module editing
---
client/src/components/Chapter.vue | 5 +++-
client/src/components/ContentBlock.vue | 9 ++++--
client/src/components/modules/Module.vue | 4 +++
.../components/modules/ModuleNavigation.vue | 12 ++++++--
.../components/toggle-menu/ToggleEditing.vue | 28 +++++++++++++++++++
client/src/pages/module.vue | 5 ++--
client/src/store/index.js | 10 ++++++-
7 files changed, 63 insertions(+), 10 deletions(-)
create mode 100644 client/src/components/toggle-menu/ToggleEditing.vue
diff --git a/client/src/components/Chapter.vue b/client/src/components/Chapter.vue
index 8feee031..0ef57481 100644
--- a/client/src/components/Chapter.vue
+++ b/client/src/components/Chapter.vue
@@ -6,7 +6,7 @@
{{chapter.description}}
-
+
-
+
{{instrumentLabel}}
{{contentBlock.title}}
@@ -24,7 +24,7 @@
-
+
@@ -54,6 +54,8 @@
import CHAPTER_QUERY from '@/graphql/gql/chapterQuery.gql';
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
+ import {mapGetters} from 'vuex';
+
const instruments = {
base_communication: 'Sprache & Kommunikation',
base_society: 'Gesellschaft'
@@ -87,6 +89,7 @@
},
computed: {
+ ...mapGetters(['editModule']),
specialClass() {
return `content-block--${this.contentBlock.type.toLowerCase()}`
},
diff --git a/client/src/components/modules/Module.vue b/client/src/components/modules/Module.vue
index 07de26e0..dfb8b31c 100644
--- a/client/src/components/modules/Module.vue
+++ b/client/src/components/modules/Module.vue
@@ -46,6 +46,10 @@
module: {
required: true,
type: Object
+ },
+ edit: {
+ type: Boolean,
+ default: false
}
},
diff --git a/client/src/components/modules/ModuleNavigation.vue b/client/src/components/modules/ModuleNavigation.vue
index a8b10747..d922bb17 100644
--- a/client/src/components/modules/ModuleNavigation.vue
+++ b/client/src/components/modules/ModuleNavigation.vue
@@ -32,6 +32,10 @@
+
+
+
+
+
+
+
{{instrumentLabel}}
From c479d0f2bff1480d00a2b287dba5b0fd49d60ae9 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Wed, 24 Jul 2019 11:19:39 +0200
Subject: [PATCH 04/15] Only show module edit checkbox for teacher
---
client/src/components/modules/ModuleNavigation.vue | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/client/src/components/modules/ModuleNavigation.vue b/client/src/components/modules/ModuleNavigation.vue
index d922bb17..8f3ad3e0 100644
--- a/client/src/components/modules/ModuleNavigation.vue
+++ b/client/src/components/modules/ModuleNavigation.vue
@@ -32,7 +32,7 @@
-
@@ -64,6 +63,7 @@
diff --git a/client/src/graphql/gql/fragments/userParts.gql b/client/src/graphql/gql/fragments/userParts.gql
index 1ea3939c..befaf6f0 100644
--- a/client/src/graphql/gql/fragments/userParts.gql
+++ b/client/src/graphql/gql/fragments/userParts.gql
@@ -11,6 +11,9 @@ fragment UserParts on UserNode {
id
slug
}
+ selectedClass {
+ id
+ }
schoolClasses {
edges {
node {
diff --git a/client/src/graphql/gql/mutations/updateUserSetting.gql b/client/src/graphql/gql/mutations/updateUserSetting.gql
new file mode 100644
index 00000000..0e8190ee
--- /dev/null
+++ b/client/src/graphql/gql/mutations/updateUserSetting.gql
@@ -0,0 +1,8 @@
+mutation UpdateSettings($input: UpdateSettingInput!) {
+ updateSetting(input: $input) {
+ success
+ errors {
+ field
+ }
+ }
+}
diff --git a/client/src/pages/rooms.vue b/client/src/pages/rooms.vue
index 23fecf01..61479564 100644
--- a/client/src/pages/rooms.vue
+++ b/client/src/pages/rooms.vue
@@ -23,7 +23,7 @@
return this.rooms.filter(room => this.visibleFor(room, this.currentFilter));
},
currentFilter() {
- return this.$store.state.filterForSchoolClass;
+ return this.me.selectedClass.id;
},
canAddRoom() {
return this.me.permissions.includes('users.can_manage_school_class_content')
@@ -53,6 +53,9 @@
return {
rooms: [],
me: {
+ selectedClass: {
+ id: ''
+ },
permissions: []
}
}
diff --git a/client/src/store/index.js b/client/src/store/index.js
index 3bbe932a..6b6b41cb 100644
--- a/client/src/store/index.js
+++ b/client/src/store/index.js
@@ -12,7 +12,6 @@ export default new Vuex.Store({
showMobileNavigation: false,
contentBlockPosition: {},
scrollPosition: 0,
- filterForSchoolClass: '',
currentContentBlock: '',
currentRoomEntry: '',
parentRoom: null,
@@ -108,9 +107,6 @@ export default new Vuex.Store({
document.body.classList.add('no-scroll'); // won't get at the body any other way
commit('setModal', payload);
},
- setfilterForSchoolClass({commit}, payload) {
- commit('setfilterForSchoolClass', payload);
- },
addProjectEntry({commit, dispatch}, payload) {
commit('setParentProject', payload);
dispatch('showModal', 'new-project-entry-wizard');
@@ -174,9 +170,6 @@ export default new Vuex.Store({
setCurrentContentBlock(state, payload) {
state.currentContentBlock = payload;
},
- setfilterForSchoolClass(state, payload) {
- state.filterForSchoolClass = payload;
- },
setParentRoom(state, payload) {
state.parentRoom = payload;
},
diff --git a/server/users/admin.py b/server/users/admin.py
index c1f96794..9733310f 100644
--- a/server/users/admin.py
+++ b/server/users/admin.py
@@ -2,7 +2,7 @@ from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from users.forms import CustomUserCreationForm, CustomUserChangeForm
-from .models import User, SchoolClass, Role, UserRole
+from .models import User, SchoolClass, Role, UserRole, UserSetting
class SchoolClassInline(admin.TabularInline):
@@ -53,3 +53,9 @@ class CustomUserAdmin(UserAdmin):
admin.site.register(User, CustomUserAdmin)
+
+
+@admin.register(UserSetting)
+class UserSettingAdmin(admin.ModelAdmin):
+ list_display = ('user', 'selected_class')
+ raw_id_fields = ('user', 'selected_class')
diff --git a/server/users/mutations.py b/server/users/mutations.py
index 29200972..bbaae8c0 100644
--- a/server/users/mutations.py
+++ b/server/users/mutations.py
@@ -5,7 +5,7 @@ from graphene import relay
from api.utils import get_object
from users.inputs import PasswordUpdateInput
-from users.models import SchoolClass
+from users.models import SchoolClass, UserSetting
from users.serializers import PasswordSerialzer, AvatarUrlSerializer
@@ -89,11 +89,13 @@ class UpdateSetting(relay.ClientIDMutation):
class_id = kwargs.get('id')
school_class = get_object(SchoolClass, class_id)
user = info.context.user
- if school_class not in user.school_classes.all():
+
+ if school_class and school_class not in user.school_classes.all():
raise PermissionDenied('Permission denied: Incorrect school class')
- user.user_setting.selected_class = school_class
- user.user_setting.save()
+ user_settings, created = UserSetting.objects.get_or_create(user=user)
+ user_settings.selected_class = school_class
+ user_settings.save()
return cls(success=True)
success = graphene.Boolean()
diff --git a/server/users/tests/test_usersettings.py b/server/users/tests/test_usersettings.py
index 963273be..147bd223 100644
--- a/server/users/tests/test_usersettings.py
+++ b/server/users/tests/test_usersettings.py
@@ -94,3 +94,25 @@ class UserSettingTests(TestCase):
self.assertIsNone(query_result.get('errors'))
self.assertEqual(query_result.get('data').get('me').get('selectedClass').get('name'),
selected_class.name)
+
+ def test_user_can_select_class_even_no_settings_exist(self):
+
+ selected_class = self.user.school_classes.all()[1]
+ mutation_result = self.make_mutation(selected_class.pk)
+ self.assertIsNone(mutation_result.get('errors'))
+ query_result = self.make_query()
+ self.assertIsNone(query_result.get('errors'))
+ self.assertEqual(query_result.get('data').get('me').get('selectedClass').get('name'),
+ selected_class.name)
+
+
+ def test_user_cannot_select_class_shes_not_part_of(self):
+
+ default_class = self.user.school_classes.first()
+ setting = UserSetting.objects.create(user=self.user, selected_class=default_class)
+ setting.save()
+
+ mutation_result = self.make_mutation(self.class3.pk)
+ self.assertIsNotNone(mutation_result.get('errors'))
+
+
From 780602dfd2077bda54b95b4eded1a0bd163dab64 Mon Sep 17 00:00:00 2001
From: Christian Cueni
Date: Thu, 25 Jul 2019 11:39:01 +0200
Subject: [PATCH 14/15] Add option for mobile
---
.../src/components/ClassSelectionWidget.vue | 8 ++
client/src/components/FilterBar.vue | 76 -------------------
client/src/components/MobileNavigation.vue | 4 +-
client/src/components/UserWidget.vue | 17 ++++-
client/src/components/WidgetPopover.vue | 11 ++-
client/src/layouts/DefaultLayout.vue | 4 -
6 files changed, 34 insertions(+), 86 deletions(-)
delete mode 100644 client/src/components/FilterBar.vue
diff --git a/client/src/components/ClassSelectionWidget.vue b/client/src/components/ClassSelectionWidget.vue
index b72d33e8..214d345a 100644
--- a/client/src/components/ClassSelectionWidget.vue
+++ b/client/src/components/ClassSelectionWidget.vue
@@ -5,6 +5,7 @@
-
-
-
-
-
-
-
-
-
diff --git a/client/src/components/MobileNavigation.vue b/client/src/components/MobileNavigation.vue
index 8ddb17ac..2a69c4a3 100644
--- a/client/src/components/MobileNavigation.vue
+++ b/client/src/components/MobileNavigation.vue
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/client/src/components/UserWidget.vue b/client/src/components/UserWidget.vue
index ac17bdb5..36c582f3 100644
--- a/client/src/components/UserWidget.vue
+++ b/client/src/components/UserWidget.vue
@@ -5,6 +5,7 @@
{{firstName}} {{lastName}}
@@ -29,7 +30,21 @@
import WidgetPopover from '@/components/WidgetPopover';
export default {
- props: ['firstName', 'lastName', 'avatarUrl', 'date'],
+ props: {
+ firstName: {
+ type: String
+ },
+ lastName: {
+ type: String
+ },
+ avatarUrl: {
+ type: String
+ },
+ mobile: {
+ type: Boolean,
+ default: false
+ }
+ },
data() {
return {
diff --git a/client/src/components/WidgetPopover.vue b/client/src/components/WidgetPopover.vue
index 932aa9b5..418390ed 100644
--- a/client/src/components/WidgetPopover.vue
+++ b/client/src/components/WidgetPopover.vue
@@ -1,5 +1,5 @@
-
@@ -25,7 +25,7 @@
import ROOM_ENTRIES_QUERY from '@/graphql/gql/roomEntriesQuery.gql';
import ME_QUERY from '@/graphql/gql/meQuery.gql';
- import UserWidget from '@/components/UserWidget';
+ import UserMetaWidget from '@/components/UserMetaWidget';
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
import teaser from '@/helpers/teaser';
@@ -34,7 +34,7 @@
components: {
MoreOptionsWidget,
- UserWidget
+ UserMetaWidget
},
methods: {
diff --git a/client/src/pages/article.vue b/client/src/pages/article.vue
index ddcf48ad..490c278e 100644
--- a/client/src/pages/article.vue
+++ b/client/src/pages/article.vue
@@ -2,7 +2,7 @@
@@ -24,7 +24,7 @@
import VideoBlock from '@/components/content-blocks/VideoBlock';
import LinkBlock from '@/components/content-blocks/LinkBlock';
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
- import UserWidget from '@/components/UserWidget';
+ import UserMetaWidget from '@/components/UserMetaWidget';
import ROOM_ENTRY_QUERY from '@/graphql/gql/roomEntryQuery.gql';
@@ -36,7 +36,7 @@
'video_block': VideoBlock,
'link_block': LinkBlock,
'document_block': DocumentBlock,
- UserWidget
+ UserMetaWidget
},
apollo: {