diff --git a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py index 23392429..df652341 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py @@ -1,6 +1,6 @@ import graphene -from vbv_lernwelt.course.models import CourseSession +from vbv_lernwelt.course.models import CourseSession, CourseSessionUser from vbv_lernwelt.dashboard.graphql.types.assignment import Assignments, assignments from vbv_lernwelt.dashboard.graphql.types.attendance import ( attendance_day_presences, @@ -25,6 +25,12 @@ class CircleData(graphene.ObjectType): experts = graphene.List(graphene.String) +class CourseSessionsSelectionMetrics(graphene.ObjectType): + session_count = graphene.Int(required=True) + participant_count = graphene.Int(required=True) + expert_count = graphene.Int(required=True) + + class CourseSessionProperties(graphene.ObjectType): sessions = graphene.List(CourseSessionData) generations = graphene.List(graphene.String) @@ -40,8 +46,9 @@ class DashboardConfigType(graphene.ObjectType): class CourseStatisticsType(graphene.ObjectType): course_id = graphene.ID() course_title = graphene.String() - course_session_selection_ids = graphene.List(graphene.ID) course_session_properties = graphene.Field(CourseSessionProperties) + course_session_selection_ids = graphene.List(graphene.ID) + course_session_selection_metrics = graphene.Field(CourseSessionsSelectionMetrics) attendance_day_presences = graphene.Field(AttendanceDayPresences) feedback_responses = graphene.Field(FeedbackResponses) assignments = graphene.Field(Assignments) @@ -59,15 +66,39 @@ class CourseStatisticsType(graphene.ObjectType): def resolve_assignments(root, info) -> Assignments: return assignments(root.course_session_selection_ids) + def resolve_course_session_selection_metrics( + root, info + ) -> CourseSessionsSelectionMetrics: + course_session_count = CourseSession.objects.filter( + id__in=root.course_session_selection_ids, + course_id=root.course_id, + ).count() + + expert_count = CourseSession.objects.filter( + id__in=root.course_session_selection_ids, + course_id=root.course_id, + coursesessionuser__role=CourseSessionUser.Role.EXPERT, + ).count() + + participant_count = CourseSession.objects.filter( + id__in=root.course_session_selection_ids, + course_id=root.course_id, + coursesessionuser__role=CourseSessionUser.Role.MEMBER, + ).count() + + return CourseSessionsSelectionMetrics( + session_count=course_session_count, # noqa + participant_count=participant_count, # noqa + expert_count=expert_count, # noqa + ) + def resolve_course_session_properties(root, info): course_session_data = [] circle_data = [] generations = set() - # TODO: Use course session group app to get all - # relevant course sessions for info.context.user - course_sessions = CourseSession.objects.filter( + id__in=root.course_session_selection_ids, course_id=root.course_id, ) diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_assignment.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_assignment.py index f82ae426..1dede516 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/test_assignment.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_assignment.py @@ -21,6 +21,7 @@ from vbv_lernwelt.dashboard.tests.graphql.utils import ( create_course_session_edoniq_test, create_user, create_course_session_group, + add_course_session_group_supervisor, ) from vbv_lernwelt.learnpath.models import Circle @@ -62,9 +63,8 @@ class AssignmentTestCase(GraphQLTestCase): self.supervisor = create_user("supervisor") - create_course_session_group( - course_session=self.course_session, user=self.supervisor - ) + group = create_course_session_group(course_session=self.course_session) + add_course_session_group_supervisor(group=group, user=self.supervisor) self.m1 = create_user("member_1") add_course_session_user( diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_attendance.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_attendance.py index 6c0a9eca..17fce53a 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/test_attendance.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_attendance.py @@ -13,6 +13,7 @@ from vbv_lernwelt.dashboard.tests.graphql.utils import ( create_course_session, create_user, create_course_session_group, + add_course_session_group_supervisor, ) @@ -25,7 +26,9 @@ class DashboardAttendanceTestCase(GraphQLTestCase): course_session = create_course_session(course=course, title="Test Bern 2022 a") supervisor = create_user("supervisor") - create_course_session_group(course_session=course_session, user=supervisor) + + group = create_course_session_group(course_session=course_session) + add_course_session_group_supervisor(group=group, user=supervisor) circle, _ = create_circle(title="Test Circle", course_page=course_page) diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_competence.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_competence.py index c12d1392..0dc423d1 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/test_competence.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_competence.py @@ -10,6 +10,7 @@ from vbv_lernwelt.dashboard.tests.graphql.utils import ( create_performance_criteria_page, create_user, create_course_session_group, + add_course_session_group_supervisor, ) @@ -22,7 +23,8 @@ class DashboardCompetenceTestCase(GraphQLTestCase): course_session = create_course_session(course=course, title="Test Bern 2022 a") supervisor = create_user("supervisor") - create_course_session_group(course_session=course_session, user=supervisor) + group = create_course_session_group(course_session=course_session) + add_course_session_group_supervisor(group=group, user=supervisor) member_one = create_user("member one") add_course_session_user( diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py index 09fe9309..238f11c9 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_dashboard.py @@ -7,6 +7,7 @@ from vbv_lernwelt.dashboard.tests.graphql.utils import ( create_user, add_course_session_user, create_course_session_group, + add_course_session_group_supervisor, ) @@ -29,7 +30,8 @@ class DashboardTestCase(GraphQLTestCase): course_session=cs_1, user=supervisor, role=CourseSessionUser.Role.MEMBER ) - create_course_session_group(course_session=cs_2, user=supervisor) + group = create_course_session_group(course_session=cs_2) + add_course_session_group_supervisor(group=group, user=supervisor) self.client.force_login(supervisor) @@ -65,7 +67,7 @@ class DashboardTestCase(GraphQLTestCase): self.assertEqual(course_2_config["title"], course_2.title) self.assertEqual(course_2_config["dashboard_type"], "StatisticsDashboard") - def test_course_statistics_deny_not_allowed_users(self): + def test_course_statistics_deny_not_allowed_user(self): # GIVEN disallowed_user = create_user("1337_hacker_schorsch") course, _ = create_course("Test Course") @@ -90,7 +92,7 @@ class DashboardTestCase(GraphQLTestCase): course_statistics = response.json()["data"]["course_statistics"] self.assertEqual(course_statistics, None) - def test_course_statistics_id(self): + def test_course_statistics_data(self): # GIVEN supervisor = create_user("supervisor") course_1, _ = create_course("Test Course 1") @@ -99,14 +101,18 @@ class DashboardTestCase(GraphQLTestCase): cs_1 = create_course_session(course=course_1, title="Test Course 1 Session") cs_2 = create_course_session(course=course_2, title="Test Course 2 Session") - create_course_session_group(course_session=cs_1, user=supervisor) - create_course_session_group(course_session=cs_2, user=supervisor) + cs_group_1 = create_course_session_group(course_session=cs_1) + add_course_session_group_supervisor(group=cs_group_1, user=supervisor) + + cs_group_2 = create_course_session_group(course_session=cs_2) + add_course_session_group_supervisor(group=cs_group_2, user=supervisor) self.client.force_login(supervisor) query = f"""query($course_id: ID!) {{ course_statistics(course_id: $course_id) {{ course_id + course_title }} }} """ @@ -119,7 +125,9 @@ class DashboardTestCase(GraphQLTestCase): self.assertResponseNoErrors(response) course_statistics = response.json()["data"]["course_statistics"] + self.assertEqual(course_statistics["course_id"], str(course_2.id)) + self.assertEqual(course_statistics["course_title"], course_2.title) def find_dashboard_config_by_course_id(dashboard_configs, course_id): diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_feedback.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_feedback.py index 475376b0..5ab9c9dd 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/test_feedback.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_feedback.py @@ -8,6 +8,7 @@ from vbv_lernwelt.dashboard.tests.graphql.utils import ( create_course_session, create_user, create_course_session_group, + add_course_session_group_supervisor, ) from vbv_lernwelt.feedback.models import FeedbackResponse @@ -21,7 +22,9 @@ class DashboardFeedbackTestCase(GraphQLTestCase): course_session = create_course_session(course=course, title="Test Bern 2022 a") supervisor = create_user("supervisor") - create_course_session_group(course_session=course_session, user=supervisor) + + group = create_course_session_group(course_session=course_session) + add_course_session_group_supervisor(group=group, user=supervisor) member = create_user("member") add_course_session_user( diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/test_selection_metrics.py b/server/vbv_lernwelt/dashboard/tests/graphql/test_selection_metrics.py new file mode 100644 index 00000000..bd2665da --- /dev/null +++ b/server/vbv_lernwelt/dashboard/tests/graphql/test_selection_metrics.py @@ -0,0 +1,101 @@ +from graphene_django.utils import GraphQLTestCase + +from vbv_lernwelt.course.models import CourseSessionUser +from vbv_lernwelt.dashboard.tests.graphql.utils import ( + create_course, + create_course_session, + create_user, + add_course_session_user, + create_course_session_group, + add_course_session_group_supervisor, + add_course_session_group_course_session, +) + + +class DashboardTestCase(GraphQLTestCase): + GRAPHQL_URL = "/server/graphql/" + + def test_selection_metrics(self): + # GIVEN + course_1, _ = create_course("Test Course 1") + course_2, _ = create_course("Dummy Course 2") + + cs_1_a = create_course_session(course=course_1, title="Zug", generation="1984") + cs_1_b = create_course_session(course=course_1, title="Bern", generation="1984") + cs_1_c = create_course_session(course=course_1, title="Wil", generation="1984") + cs_2_a = create_course_session(course=course_2, title="Baar", generation="1984") + + member_1 = create_user("member_1") + member_2 = create_user("member_2") + member_3 = create_user("member_3") + member_4 = create_user("member_4") + + expert_1 = create_user("expert_1") + expert_2 = create_user("expert_2") + expert_3 = create_user("expert_3") + expert_4 = create_user("expert_4") + + # CS 1 A + add_course_session_user( + course_session=cs_1_a, user=member_1, role=CourseSessionUser.Role.MEMBER + ) + add_course_session_user( + course_session=cs_1_b, user=member_2, role=CourseSessionUser.Role.MEMBER + ) + + # CS 1 B + add_course_session_user( + course_session=cs_1_a, user=expert_1, role=CourseSessionUser.Role.EXPERT + ) + add_course_session_user( + course_session=cs_1_b, user=expert_2, role=CourseSessionUser.Role.EXPERT + ) + + # CS 1 C + add_course_session_user( + course_session=cs_1_c, user=member_3, role=CourseSessionUser.Role.MEMBER + ) + add_course_session_user( + course_session=cs_1_c, user=expert_3, role=CourseSessionUser.Role.EXPERT + ) + + # CS 2 A + add_course_session_user( + course_session=cs_2_a, user=member_4, role=CourseSessionUser.Role.MEMBER + ) + add_course_session_user( + course_session=cs_2_a, user=expert_4, role=CourseSessionUser.Role.EXPERT + ) + + # SUPERVISOR of course 1, session a and b BUT NOT + # of course 1, session c or course 2, session a + cs_1_ab_supervisor = create_user("supervisor") + group = create_course_session_group(course_session=cs_1_a) + add_course_session_group_course_session(course_session=cs_1_b, group=group) + add_course_session_group_supervisor(group=group, user=cs_1_ab_supervisor) + + self.client.force_login(cs_1_ab_supervisor) + + # WHEN + query = f"""query($course_id: ID!) {{ + course_statistics(course_id: $course_id) {{ + course_session_selection_metrics {{ + expert_count + participant_count + session_count + }} + }} + }}""" + + variables = {"course_id": str(course_1.id)} + response = self.query(query, variables=variables) + + # THEN + self.assertResponseNoErrors(response) + + metrics = response.json()["data"]["course_statistics"][ + "course_session_selection_metrics" + ] + self.assertEqual(metrics["expert_count"], 2) + self.assertEqual(metrics["participant_count"], 2) + self.assertEqual(metrics["session_count"], 2) diff --git a/server/vbv_lernwelt/dashboard/tests/graphql/utils.py b/server/vbv_lernwelt/dashboard/tests/graphql/utils.py index c1625e25..65a5901f 100644 --- a/server/vbv_lernwelt/dashboard/tests/graphql/utils.py +++ b/server/vbv_lernwelt/dashboard/tests/graphql/utils.py @@ -80,12 +80,14 @@ def create_user(username: str) -> User: ) -def create_course_session(course: Course, title: str) -> CourseSession: +def create_course_session( + course: Course, title: str, generation: str = "2023" +) -> CourseSession: return CourseSession.objects.create( course=course, title=title, import_id=title, - generation="2023", + generation=generation, start_date=timezone.now(), ) @@ -100,17 +102,24 @@ def add_course_session_user( ) -def create_course_session_group( - course_session: CourseSession, user: User -) -> CourseSessionGroup: - g = CourseSessionGroup.objects.create( +def create_course_session_group(course_session: CourseSession) -> CourseSessionGroup: + group = CourseSessionGroup.objects.create( course=course_session.course, ) - g.course_session.add(course_session) - g.supervisor.add(user) + group.course_session.add(course_session) - return g + return group + + +def add_course_session_group_supervisor(group: CourseSessionGroup, user: User): + group.supervisor.add(user) + + +def add_course_session_group_course_session( + group: CourseSessionGroup, course_session: CourseSession +): + group.course_session.add(course_session) def create_circle(