diff --git a/client/src/components/ClassSelectionWidget.vue b/client/src/components/ClassSelectionWidget.vue index 33593744..b72d33e8 100644 --- a/client/src/components/ClassSelectionWidget.vue +++ b/client/src/components/ClassSelectionWidget.vue @@ -1,15 +1,16 @@ diff --git a/client/src/components/MobileNavigation.vue b/client/src/components/MobileNavigation.vue index 8e229990..8ddb17ac 100644 --- a/client/src/components/MobileNavigation.vue +++ b/client/src/components/MobileNavigation.vue @@ -6,10 +6,8 @@
- - - - + +
@@ -19,6 +17,7 @@ import UserWidget from '@/components/UserWidget'; import LogoutWidget from '@/components/LogoutWidget'; import TopNavigation from '@/components/TopNavigation'; + import ClassSelectionWidget from '@/components/ClassSelectionWidget'; import {meQuery} from '@/graphql/queries'; @@ -27,7 +26,8 @@ TopNavigation, Cross, UserWidget, - LogoutWidget + LogoutWidget, + ClassSelectionWidget }, methods: { diff --git a/client/src/components/UserWidget.vue b/client/src/components/UserWidget.vue index 2eceefa2..ac17bdb5 100644 --- a/client/src/components/UserWidget.vue +++ b/client/src/components/UserWidget.vue @@ -3,22 +3,21 @@
- - - + - - - @@ -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')) + +