From d2e36d36750fdc95587d029c200e72bd0a57a5ec Mon Sep 17 00:00:00 2001 From: dezhidki Date: Wed, 19 Feb 2025 15:41:54 +0200 Subject: [PATCH] examGroupManager: Add per-exam practice exam variation --- .../examGroupManager/examGroupManager.py | 27 ++++++++++++++----- .../exam-group-manager.component.ts | 26 +++++++++++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/timApp/plugin/examGroupManager/examGroupManager.py b/timApp/plugin/examGroupManager/examGroupManager.py index 8bd3097c63..3c46eda0e6 100644 --- a/timApp/plugin/examGroupManager/examGroupManager.py +++ b/timApp/plugin/examGroupManager/examGroupManager.py @@ -107,6 +107,11 @@ class Exam: url: str | None = None +@dataclass +class ExamWithPractice(Exam): + practice: Exam | None = None + + @dataclass class ExamGroupManagerMarkup(GenericMarkupModel): groupsPath: str | Missing = missing @@ -114,7 +119,7 @@ class ExamGroupManagerMarkup(GenericMarkupModel): showAllGroups: bool = False show: ViewOptionsMarkup = field(default_factory=ViewOptionsMarkup) groupNamePrefix: str | Missing = missing - exams: list[Exam] = field(default_factory=list) + exams: list[ExamWithPractice] = field(default_factory=list) practiceExam: Exam | Missing = missing @@ -760,16 +765,26 @@ def print_login_codes( users = _get_exam_group_members_json(ug) plugin, _ = _get_plugin_markup(GlobalParId(doc_id, par_id)) - if practice and not plugin.practiceExam: - raise NotExist(gettext("Practice exam not set in the plugin markup.")) exams_by_doc_id = {e.docId: e for e in plugin.exams} - exam = ( + exam: Exam | None = ( exams_by_doc_id.get(extra_data.examDocId, None) - if not practice and not isinstance(extra_data.examDocId, Missing) - else plugin.practiceExam + if not isinstance(extra_data.examDocId, Missing) + else None ) + + if practice: + exam = exam.practice if isinstance(exam, ExamWithPractice) else None + if not exam and isinstance(plugin.practiceExam, Exam): + exam = plugin.practiceExam + + if practice and not exam: + raise NotExist(gettext("Practice exam not set in the plugin markup.")) + + if not exam: + raise NotExist(gettext("Exam info not found in the plugin markup.")) + exam_url: str | None = None exam_title: str | None = None if exam and not isinstance(exam, Missing): diff --git a/timApp/static/scripts/tim/plugin/examGroupManager/exam-group-manager.component.ts b/timApp/static/scripts/tim/plugin/examGroupManager/exam-group-manager.component.ts index 2d23f1a0c4..1086a255df 100644 --- a/timApp/static/scripts/tim/plugin/examGroupManager/exam-group-manager.component.ts +++ b/timApp/static/scripts/tim/plugin/examGroupManager/exam-group-manager.component.ts @@ -122,13 +122,22 @@ const ExamT = t.type({ url: t.union([t.string, t.null]), }); +const ExamWithPracticeT = t.intersection([ + ExamT, + t.partial({ + practice: t.union([ExamT, t.null]), + }), +]); + export interface Exam extends t.TypeOf {} +export interface ExamWithPractice extends t.TypeOf {} + const ExamManagerMarkup = t.intersection([ t.type({ groupsPath: withDefault(t.string, ""), showAllGroups: withDefault(t.boolean, false), - exams: withDefault(t.array(ExamT), []), + exams: withDefault(t.array(ExamWithPracticeT), []), }), t.partial({ extraInfoTitle: t.string, @@ -393,7 +402,7 @@ export class ToggleComponent { i18n> Print login codes (Main exam) - @@ -430,9 +439,9 @@ export class ToggleComponent {