From 128c8da2e6fac99f2013f9817145d8b9b41fe85f Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 22 Jul 2024 11:49:55 +0200 Subject: [PATCH 01/10] Optimize competences queries --- .../dashboard/graphql/types/competence.py | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/competence.py b/server/vbv_lernwelt/dashboard/graphql/types/competence.py index 28dbae75..bc682ca2 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/competence.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/competence.py @@ -1,10 +1,13 @@ from typing import List, Tuple import graphene +import structlog from wagtail.models import Page from vbv_lernwelt.course.models import CourseCompletion, CourseCompletionStatus +logger = structlog.get_logger(__name__) + class CompetencePerformanceStatisticsSummaryType(graphene.ObjectType): _id = graphene.ID(required=True) @@ -41,25 +44,23 @@ def competences( completions = CourseCompletion.objects.filter( course_session_id__in=course_session_selection_ids, page_type="competence.PerformanceCriteria", - ).prefetch_related("course_session", "page") + ).select_related("course_session", "page") if user_selection_ids is not None: completions = completions.filter(user_id__in=user_selection_ids) - competence_records = {} + page_ids = completions.values_list("page_id", flat=True).distinct() + pages = Page.objects.filter(id__in=page_ids) + learning_units = {page.id: page.specific.learning_unit for page in pages} - unique_page_ids = {completion.page.id for completion in completions} - learning_units = { - page_id: Page.objects.get(id=page_id).specific.learning_unit - for page_id in unique_page_ids - } circles = { lu.id: c for lu in learning_units.values() - if (lu is not None and (c := lu.get_circle()) is not None) - and (circle_ids is None or c.id in circle_ids) + if lu and (c := lu.get_circle()) and (circle_ids is None or c.id in circle_ids) } + competence_records = {} + for completion in completions: learning_unit = learning_units.get(completion.page.id) @@ -73,20 +74,23 @@ def competences( combined_id = f"{circle.id}-{completion.course_session.id}@{urql_id_postfix}" - competence_records.setdefault(combined_id, {}).setdefault( - learning_unit, - CompetenceRecordStatisticsType( - _id=combined_id, # noqa - title=learning_unit.title, # noqa - course_session_id=completion.course_session.id, # noqa - generation=completion.course_session.generation, # noqa - circle_id=circle.id, # noqa - success_count=0, # noqa - fail_count=0, # noqa + if combined_id not in competence_records: + competence_records[combined_id] = {} + + if learning_unit not in competence_records[combined_id]: + competence_records[combined_id][ + learning_unit + ] = CompetenceRecordStatisticsType( + _id=combined_id, + title=learning_unit.title, + course_session_id=completion.course_session.id, + generation=completion.course_session.generation, + circle_id=circle.id, + success_count=0, + fail_count=0, details_url=f"/course/{course_slug}/cockpit?courseSessionId={completion.course_session.id}", # noqa - ), - ) + ) if completion.completion_status == CourseCompletionStatus.SUCCESS.value: competence_records[combined_id][learning_unit].success_count += 1 @@ -99,7 +103,7 @@ def competences( for record in circle_records.values() ] - success_count = sum([c.success_count for c in values]) - fail_count = sum([c.fail_count for c in values]) + success_count = sum(c.success_count for c in values) + fail_count = sum(c.fail_count for c in values) return values, success_count, fail_count From 69ea3c8c17620460051afb9a4a97264159005b07 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 22 Jul 2024 14:41:53 +0200 Subject: [PATCH 02/10] Use specific --- server/vbv_lernwelt/dashboard/graphql/types/competence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/competence.py b/server/vbv_lernwelt/dashboard/graphql/types/competence.py index bc682ca2..dc00f167 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/competence.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/competence.py @@ -50,7 +50,7 @@ def competences( completions = completions.filter(user_id__in=user_selection_ids) page_ids = completions.values_list("page_id", flat=True).distinct() - pages = Page.objects.filter(id__in=page_ids) + pages = Page.objects.filter(id__in=page_ids).specific() learning_units = {page.id: page.specific.learning_unit for page in pages} circles = { From 9424979bef1d3220fc4c82f275619343d17f8675 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 22 Jul 2024 14:59:53 +0200 Subject: [PATCH 03/10] Select related data --- server/vbv_lernwelt/competence/services.py | 4 +-- .../dashboard/graphql/types/assignment.py | 33 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/server/vbv_lernwelt/competence/services.py b/server/vbv_lernwelt/competence/services.py index 0ef4d306..977ea2dc 100644 --- a/server/vbv_lernwelt/competence/services.py +++ b/server/vbv_lernwelt/competence/services.py @@ -17,7 +17,7 @@ def query_competence_course_session_assignments(course_session_ids, circle_ids=N AssignmentType.CASEWORK.value, ], learning_content__content_assignment__competence_certificate__isnull=False, - ): + ).select_related("submission_deadline", "learning_content"): if circle_ids and csa.learning_content.get_circle().id not in circle_ids: continue result.append(csa) @@ -34,7 +34,7 @@ def query_competence_course_session_edoniq_tests(course_session_ids, circle_ids= for cset in CourseSessionEdoniqTest.objects.filter( course_session_id__in=course_session_ids, learning_content__content_assignment__competence_certificate__isnull=False, - ): + ).select_related("deadline", "learning_content"): if circle_ids and cset.learning_content.get_circle().id not in circle_ids: continue result.append(cset) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py index 8199bc72..d09d5d36 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py @@ -2,12 +2,12 @@ import math from typing import List import graphene +from django.db import connection, reset_queries import vbv_lernwelt.assignment.models from vbv_lernwelt.assignment.models import ( AssignmentCompletion, AssignmentCompletionStatus, - AssignmentType, ) from vbv_lernwelt.competence.services import ( query_competence_course_session_assignments, @@ -176,6 +176,9 @@ def assignments( circle_ids: List[graphene.ID] | None = None, urql_id: str = None, ) -> AssignmentsStatisticsType: + import structlog + + logger = structlog.get_logger() if urql_id is None: urql_id = str(course_id) @@ -184,22 +187,20 @@ def assignments( ) records: List[AssignmentStatisticsRecordType] = [] - for course_session in course_sessions: - for csa in query_competence_course_session_assignments( - [course_session.id], circle_ids - ): - record = create_record(csa, user_selection_ids, urql_id_postfix=urql_id) - records.append(record) + reset_queries() + csas = query_competence_course_session_assignments(course_sessions, circle_ids) + csets = query_competence_course_session_edoniq_tests(course_sessions, circle_ids) - for cset in query_competence_course_session_edoniq_tests( - [course_session.id], circle_ids - ): - record = create_record( - course_session_assignment=cset, - user_selection_ids=user_selection_ids, - urql_id_postfix=urql_id, - ) - records.append(record) + for csa in csas: + record = create_record(csa, user_selection_ids, urql_id_postfix=urql_id) + records.append(record) + + for cset in csets: + record = create_record(cset, user_selection_ids, urql_id_postfix=urql_id) + records.append(record) + + num_queries = len(connection.queries) + logger.info(f"cset number of queries executed: {num_queries}") return AssignmentsStatisticsType( _id=urql_id, # noqa From 8e7f805067eb85f19d17b3cbf8fb680cc90cd370 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 22 Jul 2024 15:28:28 +0200 Subject: [PATCH 04/10] Add context --- server/vbv_lernwelt/competence/services.py | 5 +- .../dashboard/graphql/types/assignment.py | 46 +++++++++++-------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/server/vbv_lernwelt/competence/services.py b/server/vbv_lernwelt/competence/services.py index 977ea2dc..168e938f 100644 --- a/server/vbv_lernwelt/competence/services.py +++ b/server/vbv_lernwelt/competence/services.py @@ -17,7 +17,8 @@ def query_competence_course_session_assignments(course_session_ids, circle_ids=N AssignmentType.CASEWORK.value, ], learning_content__content_assignment__competence_certificate__isnull=False, - ).select_related("submission_deadline", "learning_content"): + ).select_related("submission_deadline", "learning_content", "course_session", + "learning_content__content_assignment"): if circle_ids and csa.learning_content.get_circle().id not in circle_ids: continue result.append(csa) @@ -34,7 +35,7 @@ def query_competence_course_session_edoniq_tests(course_session_ids, circle_ids= for cset in CourseSessionEdoniqTest.objects.filter( course_session_id__in=course_session_ids, learning_content__content_assignment__competence_certificate__isnull=False, - ).select_related("deadline", "learning_content"): + ).select_related("deadline", "learning_content", "course_session", "learning_content__content_assignment"): if circle_ids and cset.learning_content.get_circle().id not in circle_ids: continue result.append(cset) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py index d09d5d36..766fb8af 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py @@ -1,8 +1,9 @@ import math -from typing import List +from typing import List, Dict, Tuple import graphene -from django.db import connection, reset_queries +import structlog +from django.db import connections, reset_queries import vbv_lernwelt.assignment.models from vbv_lernwelt.assignment.models import ( @@ -19,6 +20,8 @@ from vbv_lernwelt.course_session.models import ( CourseSessionEdoniqTest, ) +logger = structlog.get_logger() + class AssignmentCompletionMetricsType(graphene.ObjectType): _id = graphene.ID(required=True) @@ -139,11 +142,21 @@ def create_record( course_session_assignment: CourseSessionAssignment | CourseSessionEdoniqTest, user_selection_ids: List[str] | None, urql_id_postfix: str = "", -) -> AssignmentStatisticsRecordType: - if isinstance(course_session_assignment, CourseSessionAssignment): - due_date = course_session_assignment.submission_deadline - else: - due_date = course_session_assignment.deadline + context=None, +) -> Tuple[AssignmentStatisticsRecordType, Dict]: + if not context: + context = {} + + assignment_type = "CourseSessionAssignment" if isinstance(course_session_assignment, + CourseSessionAssignment) else "CourseSessionEdoniqTest" + due_date = course_session_assignment.submission_deadline if assignment_type == "CourseSessionAssignment" else course_session_assignment.deadline + + key = f"{assignment_type}_{course_session_assignment.learning_content.id}" + + if not key in context: + context[key] = course_session_assignment.learning_content.get_circle().id + + circle_id = context[key] learning_content = course_session_assignment.learning_content @@ -152,7 +165,7 @@ def create_record( _id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}", # noqa course_session_id=str(course_session_assignment.course_session.id), # noqa - circle_id=learning_content.get_circle().id, # noqa + circle_id=circle_id, # noqa course_session_assignment_id=str(course_session_assignment.id), # noqa generation=course_session_assignment.course_session.generation, # noqa assignment_type_translation_key=due_date.assignment_type_translation_key, @@ -166,7 +179,7 @@ def create_record( ), details_url=due_date.url_expert, # noqa deadline=due_date.start, # noqa - ) + ), context def assignments( @@ -176,9 +189,6 @@ def assignments( circle_ids: List[graphene.ID] | None = None, urql_id: str = None, ) -> AssignmentsStatisticsType: - import structlog - - logger = structlog.get_logger() if urql_id is None: urql_id = str(course_id) @@ -186,22 +196,20 @@ def assignments( id__in=course_session_selection_ids, ) records: List[AssignmentStatisticsRecordType] = [] - + context = {} reset_queries() csas = query_competence_course_session_assignments(course_sessions, circle_ids) csets = query_competence_course_session_edoniq_tests(course_sessions, circle_ids) for csa in csas: - record = create_record(csa, user_selection_ids, urql_id_postfix=urql_id) + record, context = create_record(csa, user_selection_ids, urql_id_postfix=urql_id, context=context) records.append(record) for cset in csets: - record = create_record(cset, user_selection_ids, urql_id_postfix=urql_id) + record, context = create_record(cset, user_selection_ids, urql_id_postfix=urql_id, context=context) records.append(record) - - num_queries = len(connection.queries) - logger.info(f"cset number of queries executed: {num_queries}") - + num_queries = len(connections["default"].queries) + logger.info(num_queries) return AssignmentsStatisticsType( _id=urql_id, # noqa records=sorted(records, key=lambda r: r.deadline), # noqa From dbcae57091b94d18c20ae9ba58b899b63b72c55a Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 22 Jul 2024 16:12:59 +0200 Subject: [PATCH 05/10] Add CourseSessionUsers to context --- server/vbv_lernwelt/competence/services.py | 15 ++++-- .../dashboard/graphql/types/assignment.py | 54 ++++++++++++------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/server/vbv_lernwelt/competence/services.py b/server/vbv_lernwelt/competence/services.py index 168e938f..6905ef91 100644 --- a/server/vbv_lernwelt/competence/services.py +++ b/server/vbv_lernwelt/competence/services.py @@ -17,8 +17,12 @@ def query_competence_course_session_assignments(course_session_ids, circle_ids=N AssignmentType.CASEWORK.value, ], learning_content__content_assignment__competence_certificate__isnull=False, - ).select_related("submission_deadline", "learning_content", "course_session", - "learning_content__content_assignment"): + ).select_related( + "submission_deadline", + "learning_content", + "course_session", + "learning_content__content_assignment", + ): if circle_ids and csa.learning_content.get_circle().id not in circle_ids: continue result.append(csa) @@ -35,7 +39,12 @@ def query_competence_course_session_edoniq_tests(course_session_ids, circle_ids= for cset in CourseSessionEdoniqTest.objects.filter( course_session_id__in=course_session_ids, learning_content__content_assignment__competence_certificate__isnull=False, - ).select_related("deadline", "learning_content", "course_session", "learning_content__content_assignment"): + ).select_related( + "deadline", + "learning_content", + "course_session", + "learning_content__content_assignment", + ): if circle_ids and cset.learning_content.get_circle().id not in circle_ids: continue result.append(cset) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py index 766fb8af..ba26e3c6 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py @@ -1,9 +1,7 @@ import math -from typing import List, Dict, Tuple +from typing import List import graphene -import structlog -from django.db import connections, reset_queries import vbv_lernwelt.assignment.models from vbv_lernwelt.assignment.models import ( @@ -20,8 +18,6 @@ from vbv_lernwelt.course_session.models import ( CourseSessionEdoniqTest, ) -logger = structlog.get_logger() - class AssignmentCompletionMetricsType(graphene.ObjectType): _id = graphene.ID(required=True) @@ -101,14 +97,23 @@ def get_assignment_completion_metrics( assignment: vbv_lernwelt.assignment.models.Assignment, user_selection_ids: List[str] | None, urql_id_postfix: str = "", + context=None, ) -> AssignmentCompletionMetricsType: + if not context: + context = {} + if user_selection_ids: course_session_users = user_selection_ids else: - course_session_users = CourseSessionUser.objects.filter( - course_session=course_session, - role=CourseSessionUser.Role.MEMBER, - ).values_list("user", flat=True) + key = f"CourseSessionUser_{course_session.id}" + if not key in context: + course_session_users = CourseSessionUser.objects.filter( + course_session=course_session, + role=CourseSessionUser.Role.MEMBER, + ).values_list("user", flat=True) + context[key] = course_session_users + else: + course_session_users = context[key] evaluation_results = AssignmentCompletion.objects.filter( completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED.value, @@ -143,13 +148,20 @@ def create_record( user_selection_ids: List[str] | None, urql_id_postfix: str = "", context=None, -) -> Tuple[AssignmentStatisticsRecordType, Dict]: +) -> AssignmentStatisticsRecordType: if not context: context = {} - assignment_type = "CourseSessionAssignment" if isinstance(course_session_assignment, - CourseSessionAssignment) else "CourseSessionEdoniqTest" - due_date = course_session_assignment.submission_deadline if assignment_type == "CourseSessionAssignment" else course_session_assignment.deadline + assignment_type = ( + "CourseSessionAssignment" + if isinstance(course_session_assignment, CourseSessionAssignment) + else "CourseSessionEdoniqTest" + ) + due_date = ( + course_session_assignment.submission_deadline + if assignment_type == "CourseSessionAssignment" + else course_session_assignment.deadline + ) key = f"{assignment_type}_{course_session_assignment.learning_content.id}" @@ -176,10 +188,11 @@ def create_record( assignment=learning_content.content_assignment, # noqa user_selection_ids=user_selection_ids, # noqa urql_id_postfix=urql_id_postfix, # noqa + context=context, # noqa ), details_url=due_date.url_expert, # noqa deadline=due_date.start, # noqa - ), context + ) def assignments( @@ -197,19 +210,22 @@ def assignments( ) records: List[AssignmentStatisticsRecordType] = [] context = {} - reset_queries() + csas = query_competence_course_session_assignments(course_sessions, circle_ids) csets = query_competence_course_session_edoniq_tests(course_sessions, circle_ids) for csa in csas: - record, context = create_record(csa, user_selection_ids, urql_id_postfix=urql_id, context=context) + record = create_record( + csa, user_selection_ids, urql_id_postfix=urql_id, context=context + ) records.append(record) for cset in csets: - record, context = create_record(cset, user_selection_ids, urql_id_postfix=urql_id, context=context) + record = create_record( + cset, user_selection_ids, urql_id_postfix=urql_id, context=context + ) records.append(record) - num_queries = len(connections["default"].queries) - logger.info(num_queries) + return AssignmentsStatisticsType( _id=urql_id, # noqa records=sorted(records, key=lambda r: r.deadline), # noqa From 4d4e202a241c0184fb1ac45f65e275f578b2989a Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Wed, 24 Jul 2024 09:45:02 +0200 Subject: [PATCH 06/10] Preselect user --- server/vbv_lernwelt/dashboard/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/vbv_lernwelt/dashboard/views.py b/server/vbv_lernwelt/dashboard/views.py index 1cdf533a..e8266145 100644 --- a/server/vbv_lernwelt/dashboard/views.py +++ b/server/vbv_lernwelt/dashboard/views.py @@ -183,7 +183,7 @@ def _create_person_list_with_roles(user): if has_cs_role(cs.roles) and cs.course.configuration.is_uk: course_session_users = CourseSessionUser.objects.filter( course_session=cs.id - ) + ).select_related("user") my_role = user_role(cs.roles) for csu in course_session_users: person_data = result_persons.get( @@ -239,7 +239,6 @@ def _create_person_list_with_roles(user): result_persons[mentor_relation.mentor.id]["course_sessions"].append( course_session_entry ) - return result_persons.values() From c1e1f38a274cd2eea07ebcfde955847733363383 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Wed, 24 Jul 2024 11:18:19 +0200 Subject: [PATCH 07/10] Optimize duedates in dashboards --- server/vbv_lernwelt/dashboard/views.py | 41 ++++++++------------------ 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/server/vbv_lernwelt/dashboard/views.py b/server/vbv_lernwelt/dashboard/views.py index e8266145..9d20bab7 100644 --- a/server/vbv_lernwelt/dashboard/views.py +++ b/server/vbv_lernwelt/dashboard/views.py @@ -306,45 +306,28 @@ def get_dashboard_due_dates(request): course_sessions = get_course_sessions_with_roles_for_user(request.user) course_session_ids = [cs.id for cs in course_sessions] - all_due_dates = DueDate.objects.filter( - course_session__id__in=course_session_ids - ) - - # filter only future due dates - due_dates = [] today = date.today() - for due_date in all_due_dates: - # due_dates.append(due_date) - if due_date.end: - if due_date.end.date() >= today: - due_dates.append(due_date) - elif due_date.start: - if due_date.start.date() >= today: - due_dates.append(due_date) - due_dates.sort(key=lambda x: x.start) - - # find course session by id in `course_sessions` + # Fetch future due dates in a single query using Q objects for complex filtering + future_due_dates = DueDate.objects.filter( + Q(course_session_id__in=course_session_ids), + Q(end__gte=today) | Q(start__gte=today) + ).select_related('course_session') result_due_dates = [] - for due_date in due_dates: - data = DueDateSerializer(due_date).data + course_session_map = {cs.id: cs for cs in course_sessions} + + for due_date in sorted(future_due_dates, key=lambda x: x.start): + data = DueDateSerializer(due_date).data + cs = course_session_map.get(due_date.course_session_id) - cs = next( - course_session - for course_session in course_sessions - if course_session.id == due_date.course_session.id - ) if cs: data["course_session"] = _create_course_session_dict( cs, my_role=user_role(cs.roles), user_role="" ) result_due_dates.append(data) - return Response( - status=200, - data=result_due_dates, - ) + return Response(status=200, data=result_due_dates) except PermissionDenied as e: raise e @@ -625,7 +608,7 @@ def _get_course_sessions_with_roles_for_user( csr for csr in get_course_sessions_with_roles_for_user(user) if any(role in allowed_roles for role in csr.roles) - and csr.id in requested_cs_ids + and csr.id in requested_cs_ids ] # noqa return all_cs_roles_for_user From 58908bc5c687c60a900813cfee8ff794cba768dc Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Wed, 24 Jul 2024 11:37:03 +0200 Subject: [PATCH 08/10] Fix context --- .../dashboard/graphql/types/assignment.py | 50 ++++++++++--------- .../dashboard/graphql/types/competence.py | 3 -- server/vbv_lernwelt/dashboard/views.py | 6 +-- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py index ba26e3c6..32b91849 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/assignment.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/assignment.py @@ -1,5 +1,5 @@ import math -from typing import List +from typing import List, Tuple import graphene @@ -148,7 +148,7 @@ def create_record( user_selection_ids: List[str] | None, urql_id_postfix: str = "", context=None, -) -> AssignmentStatisticsRecordType: +) -> Tuple[AssignmentStatisticsRecordType, dict]: if not context: context = {} @@ -172,26 +172,29 @@ def create_record( learning_content = course_session_assignment.learning_content - return AssignmentStatisticsRecordType( - # make sure it's unique, across all types of assignments! - _id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}", - # noqa - course_session_id=str(course_session_assignment.course_session.id), # noqa - circle_id=circle_id, # noqa - course_session_assignment_id=str(course_session_assignment.id), # noqa - generation=course_session_assignment.course_session.generation, # noqa - assignment_type_translation_key=due_date.assignment_type_translation_key, - # noqa - assignment_title=learning_content.content_assignment.title, # noqa - metrics=get_assignment_completion_metrics( # noqa - course_session=course_session_assignment.course_session, # noqa - assignment=learning_content.content_assignment, # noqa - user_selection_ids=user_selection_ids, # noqa - urql_id_postfix=urql_id_postfix, # noqa - context=context, # noqa + return ( + AssignmentStatisticsRecordType( + # make sure it's unique, across all types of assignments! + _id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}", + # noqa + course_session_id=str(course_session_assignment.course_session.id), # noqa + circle_id=circle_id, # noqa + course_session_assignment_id=str(course_session_assignment.id), # noqa + generation=course_session_assignment.course_session.generation, # noqa + assignment_type_translation_key=due_date.assignment_type_translation_key, + # noqa + assignment_title=learning_content.content_assignment.title, # noqa + metrics=get_assignment_completion_metrics( # noqa + course_session=course_session_assignment.course_session, # noqa + assignment=learning_content.content_assignment, # noqa + user_selection_ids=user_selection_ids, # noqa + urql_id_postfix=urql_id_postfix, # noqa + context=context, # noqa + ), + details_url=due_date.url_expert, # noqa + deadline=due_date.start, # noqa ), - details_url=due_date.url_expert, # noqa - deadline=due_date.start, # noqa + context, ) @@ -204,7 +207,6 @@ def assignments( ) -> AssignmentsStatisticsType: if urql_id is None: urql_id = str(course_id) - course_sessions = CourseSession.objects.filter( id__in=course_session_selection_ids, ) @@ -215,13 +217,13 @@ def assignments( csets = query_competence_course_session_edoniq_tests(course_sessions, circle_ids) for csa in csas: - record = create_record( + record, context = create_record( csa, user_selection_ids, urql_id_postfix=urql_id, context=context ) records.append(record) for cset in csets: - record = create_record( + record, context = create_record( cset, user_selection_ids, urql_id_postfix=urql_id, context=context ) records.append(record) diff --git a/server/vbv_lernwelt/dashboard/graphql/types/competence.py b/server/vbv_lernwelt/dashboard/graphql/types/competence.py index dc00f167..2cf5d96f 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/competence.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/competence.py @@ -1,13 +1,10 @@ from typing import List, Tuple import graphene -import structlog from wagtail.models import Page from vbv_lernwelt.course.models import CourseCompletion, CourseCompletionStatus -logger = structlog.get_logger(__name__) - class CompetencePerformanceStatisticsSummaryType(graphene.ObjectType): _id = graphene.ID(required=True) diff --git a/server/vbv_lernwelt/dashboard/views.py b/server/vbv_lernwelt/dashboard/views.py index 9d20bab7..2e64c804 100644 --- a/server/vbv_lernwelt/dashboard/views.py +++ b/server/vbv_lernwelt/dashboard/views.py @@ -311,8 +311,8 @@ def get_dashboard_due_dates(request): # Fetch future due dates in a single query using Q objects for complex filtering future_due_dates = DueDate.objects.filter( Q(course_session_id__in=course_session_ids), - Q(end__gte=today) | Q(start__gte=today) - ).select_related('course_session') + Q(end__gte=today) | Q(start__gte=today), + ).select_related("course_session") result_due_dates = [] course_session_map = {cs.id: cs for cs in course_sessions} @@ -608,7 +608,7 @@ def _get_course_sessions_with_roles_for_user( csr for csr in get_course_sessions_with_roles_for_user(user) if any(role in allowed_roles for role in csr.roles) - and csr.id in requested_cs_ids + and csr.id in requested_cs_ids ] # noqa return all_cs_roles_for_user From fe2b91e619be268095ea9d42edb0fc196b63fc30 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Wed, 24 Jul 2024 14:00:29 +0200 Subject: [PATCH 09/10] Add debug middleware --- server/config/settings/base.py | 1 + server/vbv_lernwelt/debugtools/middleware.py | 38 ++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 server/vbv_lernwelt/debugtools/middleware.py diff --git a/server/config/settings/base.py b/server/config/settings/base.py index a4fda6fd..8251e138 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -201,6 +201,7 @@ MIDDLEWARE = [ "vbv_lernwelt.core.middleware.security.SecurityRequestResponseLoggingMiddleware", "wagtail.contrib.redirects.middleware.RedirectMiddleware", "vbv_lernwelt.core.middleware.auth.UserLoggedInCookieMiddleWare", + # "vbv_lernwelt.debugtools.middleware.QueryCountDebugMiddleware", ] # STATIC diff --git a/server/vbv_lernwelt/debugtools/middleware.py b/server/vbv_lernwelt/debugtools/middleware.py new file mode 100644 index 00000000..fea26453 --- /dev/null +++ b/server/vbv_lernwelt/debugtools/middleware.py @@ -0,0 +1,38 @@ +import time + +import structlog +from django.db import connection, reset_queries + +logger = structlog.get_logger(__name__) + + +class QueryCountDebugMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + if not request.path.startswith("/api/") and not request.path.startswith( + "/server/" + ): + return self.get_response(request) + + reset_queries() + start_queries = len(connection.queries) + start_time = time.time() + + response = self.get_response(request) + + end_queries = len(connection.queries) + end_time = time.time() + + total_queries = end_queries - start_queries + duration = end_time - start_time + + logger.debug( + "query_count_middleware", + request_path=request.path, + queries=total_queries, + duration=duration, + ) + + return response From a552ff75fe832792e52b64a66de5dd790a0cf6cf Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 29 Jul 2024 08:09:46 +0200 Subject: [PATCH 10/10] Change payment message --- client/src/pages/onboarding/vv/CheckoutAddress.vue | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/src/pages/onboarding/vv/CheckoutAddress.vue b/client/src/pages/onboarding/vv/CheckoutAddress.vue index 76e5a6ed..ba309415 100644 --- a/client/src/pages/onboarding/vv/CheckoutAddress.vue +++ b/client/src/pages/onboarding/vv/CheckoutAddress.vue @@ -265,11 +265,10 @@ const executePayment = async () => {

{{ - $t("a.Fehler bei der Zahlung. Bitte versuche es erneut oder kontaktiere uns") - }}: - - vermittler@vbv-afa.ch - + $t( + "a.Fehler bei der Zahlung. Bitte versuche es erneut oder wähle eine andere Zahlungsmethode." + ) + }}

{{ $t("a.Adresse") }}