From 58be5a14673d8e5a359e2f5e69c77dfd3f210fd1 Mon Sep 17 00:00:00 2001 From: Jonathan Weth <git@jonathanweth.de> Date: Thu, 23 May 2024 21:43:08 +0200 Subject: [PATCH 1/2] Use preferences to set group types for school structure Instead of managed, hard-coded group types --- aleksis/apps/cursus/apps.py | 9 ------ aleksis/apps/cursus/preferences.py | 37 +++++++++++++++++++++++++ aleksis/apps/cursus/rules.py | 8 +++++- aleksis/apps/cursus/schema.py | 32 ++++++++++++--------- aleksis/apps/cursus/settings.py | 2 -- aleksis/apps/cursus/util/group_types.py | 17 ------------ 6 files changed, 63 insertions(+), 42 deletions(-) create mode 100644 aleksis/apps/cursus/preferences.py delete mode 100644 aleksis/apps/cursus/settings.py delete mode 100644 aleksis/apps/cursus/util/group_types.py diff --git a/aleksis/apps/cursus/apps.py b/aleksis/apps/cursus/apps.py index ba7bf20..2100153 100644 --- a/aleksis/apps/cursus/apps.py +++ b/aleksis/apps/cursus/apps.py @@ -11,12 +11,3 @@ class DefaultConfig(AppConfig): } licence = "EUPL-1.2+" copyright_info = (([2023], "Jonathan Weth", "dev@jonathanweth.de"),) - - def _maintain_default_data(self): - super()._maintain_default_data() - - # Ensure that default group types for school structure exist - from .util.group_types import get_school_class_group_type, get_school_grade_group_type - - get_school_grade_group_type() - get_school_class_group_type() diff --git a/aleksis/apps/cursus/preferences.py b/aleksis/apps/cursus/preferences.py new file mode 100644 index 0000000..49044e6 --- /dev/null +++ b/aleksis/apps/cursus/preferences.py @@ -0,0 +1,37 @@ +from django.utils.translation import gettext_lazy as _ + +from dynamic_preferences.preferences import Section +from dynamic_preferences.types import ModelChoicePreference + +from aleksis.core.models import GroupType +from aleksis.core.registries import site_preferences_registry + +cursus = Section("cursus", verbose_name=_("Course management")) + + +@site_preferences_registry.register +class SchoolGradeGroupType(ModelChoicePreference): + section = cursus + name = "school_grade_group_type" + required = False + default = None + model = GroupType + verbose_name = _("Group type for school grades") + help_text = _( + "You have to set this and the group type for " + "school classes to use the school structure tool." + ) + + +@site_preferences_registry.register +class SchoolClassGroupType(ModelChoicePreference): + section = cursus + name = "school_class_group_type" + required = False + default = None + model = GroupType + verbose_name = _("Group type for school classes") + help_text = _( + "You have to set this and the group type for " + "school grades to use the school structure tool." + ) diff --git a/aleksis/apps/cursus/rules.py b/aleksis/apps/cursus/rules.py index 5944379..1bf3e6c 100644 --- a/aleksis/apps/cursus/rules.py +++ b/aleksis/apps/cursus/rules.py @@ -5,6 +5,7 @@ from aleksis.core.util.predicates import ( has_global_perm, has_object_perm, has_person, + is_site_preference_set, ) from .models import Course, Subject @@ -59,7 +60,12 @@ delete_course_predicate = view_course_predicate & ( ) add_perm("cursus.delete_course_rule", delete_course_predicate) -manage_school_structure_predicate = has_person & has_global_perm("cursus.manage_school_structure") +manage_school_structure_predicate = ( + has_person + & is_site_preference_set("cursus", "school_grade_group_type") + & is_site_preference_set("cursus", "school_class_group_type") + & has_global_perm("cursus.manage_school_structure") +) add_perm("cursus.manage_school_structure_rule", manage_school_structure_predicate) view_cursus_menu_predicate = ( diff --git a/aleksis/apps/cursus/schema.py b/aleksis/apps/cursus/schema.py index 6d40775..32bb557 100644 --- a/aleksis/apps/cursus/schema.py +++ b/aleksis/apps/cursus/schema.py @@ -10,11 +10,6 @@ from graphene_django_cud.mutations import ( ) from guardian.shortcuts import get_objects_for_user -from aleksis.apps.cursus.settings import SCHOOL_CLASS_GROUP_TYPE_NAME, SCHOOL_GRADE_GROUP_TYPE_NAME -from aleksis.apps.cursus.util.group_types import ( - get_school_class_group_type, - get_school_grade_group_type, -) from aleksis.core.models import Group, Person from aleksis.core.schema.base import ( DjangoFilterMixin, @@ -25,7 +20,7 @@ from aleksis.core.schema.base import ( ) from aleksis.core.schema.group import GroupType as GraphQLGroupType from aleksis.core.schema.person import PersonType as GraphQLPersonType -from aleksis.core.util.core_helpers import has_person +from aleksis.core.util.core_helpers import get_site_preferences, has_person from .models import Course, Subject @@ -206,7 +201,9 @@ class CreateSchoolClassMutation(DjangoBatchCreateMutation): @classmethod def before_mutate(cls, root, info, input): # noqa - group_type = get_school_class_group_type() + group_type = get_site_preferences()["cursus__school_class_group_type"] + if not group_type: + raise PermissionDenied() for school_class in input: school_class["group_type"] = group_type.pk return input @@ -220,7 +217,9 @@ class CreateSchoolGradeMutation(DjangoBatchCreateMutation): @classmethod def before_mutate(cls, root, info, input): # noqa - group_type = get_school_grade_group_type() + group_type = get_site_preferences()["cursus__school_grade_group_type"] + if not group_type: + raise PermissionDenied() for school_grade in input: school_grade["group_type"] = group_type.pk return input @@ -247,28 +246,35 @@ class Query(graphene.ObjectType): @staticmethod def resolve_school_classes(root, info, **kwargs): + group_type = get_site_preferences()["cursus__school_class_group_type"] + if not group_type: + return [] return get_objects_for_user( info.context.user, "core.view_group", - Group.objects.filter(group_type__name=SCHOOL_CLASS_GROUP_TYPE_NAME), + Group.objects.filter(group_type=group_type), ) @staticmethod def resolve_school_grades(root, info, **kwargs): + group_type = get_site_preferences()["cursus__school_grade_group_type"] + if not group_type: + return [] return get_objects_for_user( info.context.user, "core.view_group", - Group.objects.filter(group_type__name=SCHOOL_GRADE_GROUP_TYPE_NAME), + Group.objects.filter(group_type=group_type), ) @staticmethod def resolve_school_grades_by_term(root, info, school_term): + group_type = get_site_preferences()["cursus__school_grade_group_type"] + if not group_type: + return [] return get_objects_for_user( info.context.user, "core.view_group", - Group.objects.filter(school_term__id=school_term).filter( - group_type__name=SCHOOL_GRADE_GROUP_TYPE_NAME - ), + Group.objects.filter(school_term__id=school_term).filter(group_type=group_type), ) @staticmethod diff --git a/aleksis/apps/cursus/settings.py b/aleksis/apps/cursus/settings.py deleted file mode 100644 index 1065c8c..0000000 --- a/aleksis/apps/cursus/settings.py +++ /dev/null @@ -1,2 +0,0 @@ -SCHOOL_GRADE_GROUP_TYPE_NAME = "School grade" -SCHOOL_CLASS_GROUP_TYPE_NAME = "School class" diff --git a/aleksis/apps/cursus/util/group_types.py b/aleksis/apps/cursus/util/group_types.py deleted file mode 100644 index 71f1ebb..0000000 --- a/aleksis/apps/cursus/util/group_types.py +++ /dev/null @@ -1,17 +0,0 @@ -from aleksis.core.models import GroupType - -from ..settings import SCHOOL_CLASS_GROUP_TYPE_NAME, SCHOOL_GRADE_GROUP_TYPE_NAME - - -def get_school_grade_group_type(): - group_type, __ = GroupType.objects.managed_by_app("cursus").get_or_create( - name=SCHOOL_GRADE_GROUP_TYPE_NAME, managed_by_app_label="cursus" - ) - return group_type - - -def get_school_class_group_type(): - group_type, __ = GroupType.objects.managed_by_app("cursus").get_or_create( - name=SCHOOL_CLASS_GROUP_TYPE_NAME, managed_by_app_label="cursus" - ) - return group_type -- GitLab From f00f99ce89bf3effa0437b67c94ada98ca09bf87 Mon Sep 17 00:00:00 2001 From: Jonathan Weth <git@jonathanweth.de> Date: Mon, 10 Jun 2024 11:14:35 +0200 Subject: [PATCH 2/2] Use first and second level group types for school structure (instead of hard-coded school grades and classes) --- .../frontend/components/SchoolStructure.vue | 156 +++++++++++------- .../components/schoolStructure.graphql | 35 ++-- aleksis/apps/cursus/frontend/messages/de.json | 11 +- aleksis/apps/cursus/frontend/messages/en.json | 11 +- aleksis/apps/cursus/preferences.py | 18 +- aleksis/apps/cursus/rules.py | 4 +- aleksis/apps/cursus/schema.py | 89 ++++++---- graphql.config.yml | 1 + 8 files changed, 188 insertions(+), 137 deletions(-) create mode 100644 graphql.config.yml diff --git a/aleksis/apps/cursus/frontend/components/SchoolStructure.vue b/aleksis/apps/cursus/frontend/components/SchoolStructure.vue index 4ebb93e..37dfe21 100644 --- a/aleksis/apps/cursus/frontend/components/SchoolStructure.vue +++ b/aleksis/apps/cursus/frontend/components/SchoolStructure.vue @@ -7,31 +7,48 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <template> <v-card> - <!-- Create grade form --> + <!-- Create first level group form --> <dialog-object-form - v-model="createGradeForm" - :fields="createGradeFields" - :default-item="createGradeDefaultItem" + v-model="createFirstLevelGroupForm" + :fields="firstLevelGroupFields" + :default-item="firstLevelGroupDefaultItem" :is-create="true" - create-item-i18n-key="cursus.school_structure.add_grade" - :gql-create-mutation="gqlCreateGrades" - :get-create-data="transformCreateGradeItem" - @cancel="createGradeForm = false" + :gql-create-mutation="gqlCreateFirstLevelGroup" + :get-create-data="transformFirstLevelGroupItem" + @cancel="createFirstLevelGroupForm = false" @save="updateSchoolStructure" - /> - <!-- Create class form --> + > + <template #title> + <span class="text-h5"> + {{ + $t("cursus.school_structure.add_title", { + name: schoolStructure.firstLevelType.name, + }) + }} + </span> + </template> + </dialog-object-form> + <!-- Create second level group form --> <dialog-object-form - v-model="createClassForm" - :fields="createClassFields" - :default-item="createClassDefaultItem" + v-model="createSecondLevelGroupForm" + :fields="secondLevelGroupFields" + :default-item="secondLevelGroupDefaultItem" :is-create="true" - create-item-i18n-key="cursus.school_structure.add_class" - :gql-create-mutation="gqlCreateClasses" - :get-create-data="transformCreateClassItemForGrade" - @cancel="createClassForm = false" + :gql-create-mutation="gqlCreateSecondLevelGroup" + :get-create-data="transformSecondLevelGroupItem" + @cancel="createFirstLevelGroupForm = false" @save="updateSchoolStructure" > - <!-- Hide parentGroups field - it is set on grade --> + <template #title> + <span class="text-h5"> + {{ + $t("cursus.school_structure.add_title", { + name: schoolStructure.secondLevelType.name, + }) + }} + </span> + </template> + <!-- Hide parentGroups field - it is set on first level group --> <!-- eslint-disable-next-line vue/valid-v-slot --> <template #parentGroups.field="{ on, attrs }"> <input type="hidden" v-bind="attrs" v-on="on" /> @@ -52,19 +69,27 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <v-card-actions> <create-button v-if="this.$data.currentTerm" - i18n-key="cursus.school_structure.add_grade" - @click="createGrade" - /> + @click="createFirstLevelGroup" + > + <v-icon left>$plus</v-icon> + {{ + $t("cursus.school_structure.add", { + name: schoolStructure.firstLevelType.name, + }) + }} + </create-button> </v-card-actions> </div> </div> - <!-- Grades --> + <!-- First level groups --> <v-container v-if="this.$data.currentTerm"> <v-row class="overflow-x-auto flex-nowrap slide-n-snap-x-container"> <!-- responsive 1, 2, 3, 4 col layout --> <v-col - v-for="grade in grades" - :key="grade.id" + v-for="firstGroup in schoolStructure + ? schoolStructure.firstLevelGroupsByTerm + : []" + :key="firstGroup.id" class="slide-n-snap-contained" cols="12" sm="6" @@ -74,27 +99,26 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField > <v-card> <v-card-title class="justify-end"> - {{ $t("cursus.school_structure.grade") }} - <span class="ml-3 text-h4">{{ grade.shortName }}</span> + {{ schoolStructure.firstLevelType.name }} + <span class="ml-3 text-h4">{{ firstGroup.shortName }}</span> </v-card-title> <v-list :max-height="$vuetify.breakpoint.height - 333" class="overflow-y-auto slide-n-snap-y-container" > - <!-- class is a "forbidden" name in v-for --> <v-list-item - v-for="clas in grade.childGroups" - :key="clas.id" + v-for="secondGroup in firstGroup.childGroups" + :key="secondGroup.id" class="slide-n-snap-contained" > <v-card class="mx-3 my-2"> <div class="d-flex flex-nowrap justify-space-between"> <div> <v-card-title class="text-h4"> - {{ clas.shortName }} + {{ secondGroup.shortName }} </v-card-title> <v-card-subtitle> - {{ clas.name }} + {{ secondGroup.name }} </v-card-subtitle> </div> <div> @@ -104,15 +128,15 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField class="px-2" > <v-chip - v-for="teacher in clas.owners" + v-for="teacher in secondGroup.owners" :key="teacher.id" :to="{ name: 'core.personById', params: { id: teacher.id }, }" - :outlined="true" + outlined > - {{ teacher.shortName }} + {{ teacher.shortName || teacher.lastName }} </v-chip> </v-chip-group> <v-card-actions> @@ -120,7 +144,7 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField i18n-key="cursus.school_structure.timetable" :to="{ name: 'lesrooster.timetable_management', - params: { id: clas.id }, + params: { id: secondGroup.id }, }" /> </v-card-actions> @@ -133,10 +157,16 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <v-spacer /> <!-- MAYBE: ADD PLAN COURSES LINK --> <create-button - i18n-key="cursus.school_structure.add_class" color="secondary" - @click="createClass(grade.id)" - /> + @click="createSecondLevelGroup(firstGroup.id)" + > + <v-icon left>$plus</v-icon> + {{ + $t("cursus.school_structure.add", { + name: schoolStructure.secondLevelType.name, + }) + }} + </create-button> </v-card-actions> </v-card> </v-col> @@ -147,38 +177,38 @@ import SchoolTermField from "aleksis.core/components/school_term/SchoolTermField <script> import { - gqlSchoolGrades, - gqlCreateGrades, - gqlCreateClasses, + gqlFirstLevelGroups, + gqlCreateFirstLevelGroup, + gqlCreateSecondLevelGroup, } from "./schoolStructure.graphql"; export default { name: "SchoolStructure", data() { return { - createGradeForm: false, - createGradeFields: [ + createFirstLevelGroupForm: false, + firstLevelGroupFields: [ { - text: this.$t("cursus.school_structure.grade_fields.name"), + text: this.$t("cursus.school_structure.fields.name"), value: "name", }, { - text: this.$t("cursus.school_structure.grade_fields.short_name"), + text: this.$t("cursus.school_structure.fields.short_name"), value: "shortName", }, ], - createGradeDefaultItem: { + firstLevelGroupDefaultItem: { name: "", shortName: "", }, - createClassForm: false, - createClassFields: [ + createSecondLevelGroupForm: false, + secondLevelGroupFields: [ { - text: this.$t("cursus.school_structure.class_fields.name"), + text: this.$t("cursus.school_structure.fields.name"), value: "name", }, { - text: this.$t("cursus.school_structure.class_fields.short_name"), + text: this.$t("cursus.school_structure.fields.short_name"), value: "shortName", }, { @@ -186,18 +216,18 @@ export default { value: "parentGroups", }, ], - createClassDefaultItem: { + secondLevelGroupDefaultItem: { name: "", shortName: "", parentGroups: [], }, - createClassCurrentGradeID: 0, + createSecondLevelGroupFirstLevelGroupId: 0, currentTerm: null, }; }, apollo: { - grades: { - query: gqlSchoolGrades, + schoolStructure: { + query: gqlFirstLevelGroups, variables() { return { schoolTerm: this.$data.currentTerm.id, @@ -209,28 +239,28 @@ export default { }, }, methods: { - createGrade() { - this.$data.createGradeForm = true; + createFirstLevelGroup() { + this.$data.createFirstLevelGroupForm = true; }, - createClass(id) { - this.$data.createClassCurrentGradeID = id; - this.$data.createClassForm = true; + createSecondLevelGroup(id) { + this.$data.createSecondLevelGroupFirstLevelGroupId = id; + this.$data.createSecondLevelGroupForm = true; }, - transformCreateGradeItem(item) { + transformFirstLevelGroupItem(item) { return { ...item, schoolTerm: this.$data.currentTerm.id, }; }, - transformCreateClassItemForGrade(item) { + transformSecondLevelGroupItem(item) { return { ...item, schoolTerm: this.$data.currentTerm.id, - parentGroups: this.$data.createClassCurrentGradeID, + parentGroups: this.$data.createSecondLevelGroupFirstLevelGroupId, }; }, updateSchoolStructure() { - this.$apollo.queries.grades.refetch(); + this.$apollo.queries.schoolStructure.refetch(); }, }, }; diff --git a/aleksis/apps/cursus/frontend/components/schoolStructure.graphql b/aleksis/apps/cursus/frontend/components/schoolStructure.graphql index 269bee1..4c88e65 100644 --- a/aleksis/apps/cursus/frontend/components/schoolStructure.graphql +++ b/aleksis/apps/cursus/frontend/components/schoolStructure.graphql @@ -1,23 +1,32 @@ -query gqlSchoolGrades($schoolTerm: ID!) { - grades: schoolGradesByTerm(schoolTerm: $schoolTerm) { - id - name - shortName - childGroups { +query gqlFirstLevelGroups($schoolTerm: ID!) { + schoolStructure { + firstLevelType { + name + } + secondLevelType { + name + } + firstLevelGroupsByTerm(schoolTerm: $schoolTerm) { id name shortName - owners { + childGroups { id + name shortName + owners { + id + shortName + lastName + } } } } } -mutation gqlCreateGrades($input: [BatchCreateGroupInput]!) { - createGrades(input: $input) { - grades: groups { +mutation gqlCreateFirstLevelGroup($input: [BatchCreateGroupInput]!) { + createFirstLevelGroups(input: $input) { + firstLevelGroups: groups { id name shortName @@ -28,9 +37,9 @@ mutation gqlCreateGrades($input: [BatchCreateGroupInput]!) { } } -mutation gqlCreateClasses($input: [BatchCreateGroupInput]!) { - createClasses(input: $input) { - classes: groups { +mutation gqlCreateSecondLevelGroup($input: [BatchCreateGroupInput]!) { + createSecondLevelGroups(input: $input) { + secondLevelGroups: groups { id name shortName diff --git a/aleksis/apps/cursus/frontend/messages/de.json b/aleksis/apps/cursus/frontend/messages/de.json index 6e955ba..eb98427 100644 --- a/aleksis/apps/cursus/frontend/messages/de.json +++ b/aleksis/apps/cursus/frontend/messages/de.json @@ -30,17 +30,12 @@ "school_structure": { "menu_title": "Schulstruktur", "title": "Meine Schulstruktur aus", - "grade": "Jahrgang", - "add_grade": "Jahrgang hinzufügen", - "grade_fields": { - "short_name": "Kurzname", - "name": "Name" - }, - "add_class": "Klasse hinzufügen", - "class_fields": { + "fields": { "short_name": "Kurzname", "name": "Name" }, + "add": "{name} hinzufügen", + "add_title": "{name} hinzufügen", "timetable": "Stundenplan" }, "errors": { diff --git a/aleksis/apps/cursus/frontend/messages/en.json b/aleksis/apps/cursus/frontend/messages/en.json index 9e257d3..45081f4 100644 --- a/aleksis/apps/cursus/frontend/messages/en.json +++ b/aleksis/apps/cursus/frontend/messages/en.json @@ -30,17 +30,12 @@ "school_structure": { "menu_title": "School Structure", "title": "My School Structure in", - "grade": "Grade", - "add_grade": "Add grade", - "grade_fields": { - "short_name": "Short Name", - "name": "Name" - }, - "add_class": "Add class", - "class_fields": { + "fields": { "short_name": "Short Name", "name": "Name" }, + "add": "Add {name}", + "add_title": "Add {name}", "timetable": "Timetable" }, "errors": { diff --git a/aleksis/apps/cursus/preferences.py b/aleksis/apps/cursus/preferences.py index 49044e6..b356b42 100644 --- a/aleksis/apps/cursus/preferences.py +++ b/aleksis/apps/cursus/preferences.py @@ -10,28 +10,26 @@ cursus = Section("cursus", verbose_name=_("Course management")) @site_preferences_registry.register -class SchoolGradeGroupType(ModelChoicePreference): +class SchoolStructureFirstLevelGroupType(ModelChoicePreference): section = cursus - name = "school_grade_group_type" + name = "school_structure_first_level_group_type" required = False default = None model = GroupType - verbose_name = _("Group type for school grades") + verbose_name = _("School structure: Group type for first level (e. g. grades)") help_text = _( - "You have to set this and the group type for " - "school classes to use the school structure tool." + "You have to set this and the second level group type to use the school structure tool." ) @site_preferences_registry.register -class SchoolClassGroupType(ModelChoicePreference): +class SchoolStructureSecondLevelGroupType(ModelChoicePreference): section = cursus - name = "school_class_group_type" + name = "school_structure_second_level_group_type" required = False default = None model = GroupType - verbose_name = _("Group type for school classes") + verbose_name = _("School structure: Group type for second level (e. g. classes)") help_text = _( - "You have to set this and the group type for " - "school grades to use the school structure tool." + "You have to set this and the first level group type to use the school structure tool." ) diff --git a/aleksis/apps/cursus/rules.py b/aleksis/apps/cursus/rules.py index 1bf3e6c..c7f6540 100644 --- a/aleksis/apps/cursus/rules.py +++ b/aleksis/apps/cursus/rules.py @@ -62,8 +62,8 @@ add_perm("cursus.delete_course_rule", delete_course_predicate) manage_school_structure_predicate = ( has_person - & is_site_preference_set("cursus", "school_grade_group_type") - & is_site_preference_set("cursus", "school_class_group_type") + & is_site_preference_set("cursus", "school_structure_first_level_group_type") + & is_site_preference_set("cursus", "school_structure_second_level_group_type") & has_global_perm("cursus.manage_school_structure") ) add_perm("cursus.manage_school_structure_rule", manage_school_structure_predicate) diff --git a/aleksis/apps/cursus/schema.py b/aleksis/apps/cursus/schema.py index 32bb557..2fb6090 100644 --- a/aleksis/apps/cursus/schema.py +++ b/aleksis/apps/cursus/schema.py @@ -19,6 +19,7 @@ from aleksis.core.schema.base import ( PermissionsTypeMixin, ) from aleksis.core.schema.group import GroupType as GraphQLGroupType +from aleksis.core.schema.group_type import GroupTypeType from aleksis.core.schema.person import PersonType as GraphQLPersonType from aleksis.core.util.core_helpers import get_site_preferences, has_person @@ -193,7 +194,7 @@ class CourseBatchPatchMutation(PermissionBatchPatchMixin, DjangoBatchPatchMutati only_fields = ("id", "name", "subject", "teachers", "groups", "lesson_quota") -class CreateSchoolClassMutation(DjangoBatchCreateMutation): +class CreateSchoolStructureSecondLevelGroupsMutation(DjangoBatchCreateMutation): class Meta: model = Group permissions = ("core.add_group",) @@ -201,15 +202,15 @@ class CreateSchoolClassMutation(DjangoBatchCreateMutation): @classmethod def before_mutate(cls, root, info, input): # noqa - group_type = get_site_preferences()["cursus__school_class_group_type"] + group_type = get_site_preferences()["cursus__school_structure_second_level_group_type"] if not group_type: raise PermissionDenied() - for school_class in input: - school_class["group_type"] = group_type.pk + for group in input: + group["group_type"] = group_type.pk return input -class CreateSchoolGradeMutation(DjangoBatchCreateMutation): +class CreateSchoolStructureFirstLevelGroupsMutation(DjangoBatchCreateMutation): class Meta: model = Group permissions = ("core.add_group",) @@ -217,36 +218,32 @@ class CreateSchoolGradeMutation(DjangoBatchCreateMutation): @classmethod def before_mutate(cls, root, info, input): # noqa - group_type = get_site_preferences()["cursus__school_grade_group_type"] + group_type = get_site_preferences()["cursus__school_structure_first_level_group_type"] if not group_type: raise PermissionDenied() - for school_grade in input: - school_grade["group_type"] = group_type.pk + for group in input: + group["group_type"] = group_type.pk return input -class Query(graphene.ObjectType): - subjects = FilterOrderList(SubjectType) - courses = FilterOrderList(CourseType) +class SchoolStructureQuery(graphene.ObjectType): + first_level_type = graphene.Field(GroupTypeType) + second_level_type = graphene.Field(GroupTypeType) + first_level_groups = FilterOrderList(GraphQLGroupType) + second_level_groups = FilterOrderList(GraphQLGroupType) + first_level_groups_by_term = FilterOrderList(GraphQLGroupType, school_term=graphene.ID()) - school_classes = FilterOrderList(GraphQLGroupType) - school_grades = FilterOrderList(GraphQLGroupType) - school_grades_by_term = FilterOrderList(GraphQLGroupType, school_term=graphene.ID()) - - teachers = FilterOrderList(TeacherType) - - course_by_id = graphene.Field(CourseType, id=graphene.ID()) - courses_of_teacher = FilterOrderList(CourseType, teacher=graphene.ID()) + @staticmethod + def resolve_first_level_type(root, info, **kwargs): + return get_site_preferences()["cursus__school_structure_first_level_group_type"] - def resolve_course_by_id(root, info, id): # noqa - course = Course.objects.get(pk=id) - if not info.context.user.has_perm("cursus.view_course_rule", course): - raise PermissionDenied() - return course + @staticmethod + def resolve_second_level_type(root, info, **kwargs): + return get_site_preferences()["cursus__school_structure_second_level_group_type"] @staticmethod - def resolve_school_classes(root, info, **kwargs): - group_type = get_site_preferences()["cursus__school_class_group_type"] + def resolve_first_level_groups(root, info, **kwargs): + group_type = get_site_preferences()["cursus__school_structure_first_level_group_type"] if not group_type: return [] return get_objects_for_user( @@ -256,8 +253,8 @@ class Query(graphene.ObjectType): ) @staticmethod - def resolve_school_grades(root, info, **kwargs): - group_type = get_site_preferences()["cursus__school_grade_group_type"] + def resolve_second_level_groups(root, info, **kwargs): + group_type = get_site_preferences()["cursus__school_structure_second_level_group_type"] if not group_type: return [] return get_objects_for_user( @@ -267,16 +264,38 @@ class Query(graphene.ObjectType): ) @staticmethod - def resolve_school_grades_by_term(root, info, school_term): - group_type = get_site_preferences()["cursus__school_grade_group_type"] + def resolve_first_level_groups_by_term(root, info, school_term): + group_type = get_site_preferences()["cursus__school_structure_first_level_group_type"] + print( + group_type, + Group.objects.filter(school_term=school_term).filter(group_type=group_type), + ) if not group_type: return [] return get_objects_for_user( info.context.user, "core.view_group", - Group.objects.filter(school_term__id=school_term).filter(group_type=group_type), + Group.objects.filter(school_term=school_term).filter(group_type=group_type), ) + +class Query(graphene.ObjectType): + subjects = FilterOrderList(SubjectType) + courses = FilterOrderList(CourseType) + + school_structure = graphene.Field(SchoolStructureQuery) + + teachers = FilterOrderList(TeacherType) + + course_by_id = graphene.Field(CourseType, id=graphene.ID()) + courses_of_teacher = FilterOrderList(CourseType, teacher=graphene.ID()) + + def resolve_course_by_id(root, info, id): # noqa + course = Course.objects.get(pk=id) + if not info.context.user.has_perm("cursus.view_course_rule", course): + raise PermissionDenied() + return course + @staticmethod def resolve_teachers(root, info): return get_objects_for_user( @@ -295,6 +314,10 @@ class Query(graphene.ObjectType): # FIXME: Permission checking. But maybe it's done in get_queryset return teacher.courses_as_teacher.all() + @staticmethod + def resolve_school_structure(root, info): + return True + class Mutation(graphene.ObjectType): create_subjects = SubjectBatchCreateMutation.Field() @@ -305,5 +328,5 @@ class Mutation(graphene.ObjectType): delete_courses = CourseBatchDeleteMutation.Field() update_courses = CourseBatchPatchMutation.Field() - create_grades = CreateSchoolGradeMutation.Field() - create_classes = CreateSchoolClassMutation.Field() + create_first_level_groups = CreateSchoolStructureFirstLevelGroupsMutation.Field() + create_second_level_groups = CreateSchoolStructureSecondLevelGroupsMutation.Field() diff --git a/graphql.config.yml b/graphql.config.yml new file mode 100644 index 0000000..385050a --- /dev/null +++ b/graphql.config.yml @@ -0,0 +1 @@ +schema: http://localhost:8000/graphql/ -- GitLab