From 2989085a4217835a0472c2afd961420c02abbcfa Mon Sep 17 00:00:00 2001 From: Livio Bieri Date: Mon, 11 Mar 2024 11:28:10 +0100 Subject: [PATCH] feat: adds mentor dashboard type --- client/src/gql/graphql.ts | 1 + client/src/gql/schema.graphql | 1 + client/src/pages/dashboard/DashboardPage.vue | 2 + client/src/pages/dashboard/MentorPage.vue | 25 ++++++++++ client/src/stores/courseSessions.ts | 2 +- .../vbv_lernwelt/dashboard/graphql/queries.py | 37 ++++++++++---- .../dashboard/graphql/types/dashboard.py | 1 + .../dashboard/tests/graphql/test_dashboard.py | 50 ++++++++++++++++++- 8 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 client/src/pages/dashboard/MentorPage.vue diff --git a/client/src/gql/graphql.ts b/client/src/gql/graphql.ts index 6dd7d5a5..e6086ccb 100644 --- a/client/src/gql/graphql.ts +++ b/client/src/gql/graphql.ts @@ -464,6 +464,7 @@ export type DashboardConfigType = { }; export type DashboardType = + | 'MENTOR_DASHBOARD' | 'PROGRESS_DASHBOARD' | 'SIMPLE_DASHBOARD' | 'STATISTICS_DASHBOARD'; diff --git a/client/src/gql/schema.graphql b/client/src/gql/schema.graphql index bd098504..4c421b9b 100644 --- a/client/src/gql/schema.graphql +++ b/client/src/gql/schema.graphql @@ -207,6 +207,7 @@ enum DashboardType { STATISTICS_DASHBOARD PROGRESS_DASHBOARD SIMPLE_DASHBOARD + MENTOR_DASHBOARD } type CourseConfigurationObjectType { diff --git a/client/src/pages/dashboard/DashboardPage.vue b/client/src/pages/dashboard/DashboardPage.vue index 704de32c..a882818e 100644 --- a/client/src/pages/dashboard/DashboardPage.vue +++ b/client/src/pages/dashboard/DashboardPage.vue @@ -11,6 +11,7 @@ import SimpleCoursePage from "@/pages/dashboard/SimpleCoursePage.vue"; import LoadingSpinner from "@/components/ui/LoadingSpinner.vue"; import CourseDetailDates from "@/components/dashboard/CourseDetailDates.vue"; import NoCourseSession from "@/components/dashboard/NoCourseSession.vue"; +import MentorPage from "@/pages/dashboard/MentorPage.vue"; const dashboardStore = useDashboardStore(); @@ -23,6 +24,7 @@ const boards: Record = { PROGRESS_DASHBOARD: { main: ProgressPage, aside: SimpleDates }, SIMPLE_DASHBOARD: { main: SimpleCoursePage, aside: SimpleDates }, STATISTICS_DASHBOARD: { main: StatisticPage, aside: CourseDetailDates }, + MENTOR_DASHBOARD: { main: MentorPage, aside: SimpleDates }, }; onMounted(dashboardStore.loadDashboardDetails); diff --git a/client/src/pages/dashboard/MentorPage.vue b/client/src/pages/dashboard/MentorPage.vue new file mode 100644 index 00000000..d44a5f0e --- /dev/null +++ b/client/src/pages/dashboard/MentorPage.vue @@ -0,0 +1,25 @@ + + + diff --git a/client/src/stores/courseSessions.ts b/client/src/stores/courseSessions.ts index 9894e2da..0310af45 100644 --- a/client/src/stores/courseSessions.ts +++ b/client/src/stores/courseSessions.ts @@ -58,7 +58,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => { function selectedCourseSessionForCourse(courseSlug: string) { // Wir wollen pro Kurs wissen, welche Durchführung der User zuletzt ausgewählt hat. - // Die letzte Durchführung wird im localStorage via `selectedCoruseSessionMap` + // Die letzte Durchführung wird im localStorage via `selectedCourseSessionMap` // gespeichert und hier geladen. // Wenn noch keine Durchführung ausgewählt wurde, wird die erste Durchführung // in `courseSessionForCourse` zurückgegeben. diff --git a/server/vbv_lernwelt/dashboard/graphql/queries.py b/server/vbv_lernwelt/dashboard/graphql/queries.py index 34d6b194..69ced737 100644 --- a/server/vbv_lernwelt/dashboard/graphql/queries.py +++ b/server/vbv_lernwelt/dashboard/graphql/queries.py @@ -83,11 +83,16 @@ class DashboardQuery(graphene.ObjectType): statistics_dashboard_course_ids, ) = get_user_statistics_dashboards(user=user) - course_session_dashboards = get_user_course_session_dashboards( + ( + course_session_dashboards, + course_session_dashboard_course_ids, + ) = get_user_course_session_dashboards( user=user, exclude_course_ids=statistics_dashboard_course_ids ) - learning_mentor_dashboards = get_learning_mentor_dashboards(user=user) + learning_mentor_dashboards, _ = get_learning_mentor_dashboards( + user=user, exclude_course_ids=course_session_dashboard_course_ids + ) return ( statistic_dashboards @@ -163,13 +168,13 @@ class DashboardQuery(graphene.ObjectType): def get_user_statistics_dashboards(user: User) -> Tuple[List[Dict[str, str]], Set[int]]: - course_index = set() + course_ids = set() dashboards = [] for group in CourseSessionGroup.objects.all(): if can_view_course_session_group_statistics(user=user, group=group): course = group.course - course_index.add(course) + course_ids.add(course) dashboards.append( { "id": str(course.id), @@ -180,31 +185,38 @@ def get_user_statistics_dashboards(user: User) -> Tuple[List[Dict[str, str]], Se } ) - return dashboards, course_index + return dashboards, course_ids -def get_learning_mentor_dashboards(user: User) -> List[Dict[str, str]]: - learning_mentor = LearningMentor.objects.filter(mentor=user) +def get_learning_mentor_dashboards( + user: User, exclude_course_ids: Set[int] +) -> Tuple[List[Dict[str, str]], Set[int]]: + learning_mentor = LearningMentor.objects.filter(mentor=user).exclude( + course_id__in=exclude_course_ids + ) + dashboards = [] + course_ids = set() for mentor in learning_mentor: course = mentor.course + course_ids.add(course.id) dashboards.append( { "id": str(course.id), "name": course.title, "slug": course.slug, - "dashboard_type": DashboardType.SIMPLE_DASHBOARD, + "dashboard_type": DashboardType.MENTOR_DASHBOARD, "course_configuration": course.configuration, } ) - return dashboards + return dashboards, course_ids def get_user_course_session_dashboards( user: User, exclude_course_ids: Set[int] -) -> List[Dict[str, str]]: +) -> Tuple[List[Dict[str, str]], Set[int]]: """ Edge case: what do we show to users with access to multiple sessions of a course, but with varying permissions? @@ -212,6 +224,7 @@ def get_user_course_session_dashboards( """ dashboards = [] + course_ids = set() course_sessions = CourseSession.objects.exclude(course__in=exclude_course_ids) roles_by_course: Dict[Course, Set[DashboardType]] = {} @@ -237,6 +250,8 @@ def get_user_course_session_dashboards( # fallback: just go with simple list dashboard resolved_dashboard_type = DashboardType.SIMPLE_DASHBOARD + course_ids.add(course.id) + dashboards.append( { "id": str(course.id), @@ -247,4 +262,4 @@ def get_user_course_session_dashboards( } ) - return dashboards + return dashboards, course_ids diff --git a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py index d2e71f0d..2ad4d5de 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py @@ -53,6 +53,7 @@ class DashboardType(Enum): STATISTICS_DASHBOARD = "StatisticsDashboard" PROGRESS_DASHBOARD = "ProgressDashboard" SIMPLE_DASHBOARD = "SimpleDashboard" + MENTOR_DASHBOARD = "MentorDashboard" class DashboardConfigType(graphene.ObjectType): diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py index 1e45a3ba..08ae6d7d 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py @@ -291,7 +291,55 @@ class DashboardTestCase(GraphQLTestCase): self.assertEqual(len(response.json()["data"]["dashboard_config"]), 1) self.assertEqual( response.json()["data"]["dashboard_config"][0]["dashboard_type"], - "SIMPLE_DASHBOARD", + "MENTOR_DASHBOARD", + ) + + def test_mentor_and_member_mixed(self): + # GIVEN + course, _ = create_course("Test Course") + cs = create_course_session(course=course, title="Test Course Session 1") + + # in same course session + mentor_and_member = create_user("mentor_and_member") + + mentee = add_course_session_user( + course_session=cs, + user=create_user("mentee"), + role=CourseSessionUser.Role.MEMBER, + ) + + add_course_session_user( + course_session=cs, + user=mentor_and_member, + role=CourseSessionUser.Role.MEMBER, + ) + + add_learning_mentor(course=course, mentor=mentor_and_member, mentee=mentee) + + # WHEN + self.client.force_login(mentor_and_member) + + query = """query { + dashboard_config { + id + name + slug + dashboard_type + } + } + """ + + response = self.query(query) + + # THEN + self.assertResponseNoErrors(response) + + # given mentor + member -> should see the PROGRESS_DASHBOARD, + # not the MENTOR_DASHBOARD which is only for "pure" mentors. + self.assertEqual(len(response.json()["data"]["dashboard_config"]), 1) + self.assertEqual( + response.json()["data"]["dashboard_config"][0]["dashboard_type"], + "PROGRESS_DASHBOARD", ) def test_course_statistics_deny_not_allowed_user(self):