From 3a2d12c0b9549c65ca73bb7bc2cb0ba38b450764 Mon Sep 17 00:00:00 2001 From: Elia Bieri Date: Wed, 2 Aug 2023 08:13:35 +0000 Subject: [PATCH] Merged in feature/VBV-474-auftragstyp-condition-acceptance (pull request #173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add CONDITION_ACCEPTANCE assignment type * Add CONDITION_ACCEPTANCE assignment type * Add translations * Create default CONDITION_ACCEPTANCE assignment * Move CONDITION_ACCEPTANCE assignment in learning sequence * Add additional translations * Add condition acceptance to ÜK basis circle # Conflicts: # server/vbv_lernwelt/course/management/commands/create_default_courses.py * Move condition acceptance to kickoff circle --- .../cockpitPage/SubmissionsOverview.vue | 11 +++- .../assignment/AssignmentView.vue | 6 +- client/src/types.ts | 6 +- client/src/utils/typeMaps.ts | 10 +++- .../assignment/creators/create_assignments.py | 60 +++++++++++++++++++ .../0005_alter_assignment_assignment_type.py | 27 +++++++++ server/vbv_lernwelt/assignment/models.py | 1 + .../course/creators/test_course.py | 9 +++ .../vbv_lernwelt/course/creators/uk_course.py | 7 +++ .../commands/create_default_courses.py | 2 + ...arningcontentassignment_assignment_type.py | 27 +++++++++ server/vbv_lernwelt/learnpath/models.py | 4 ++ 12 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 server/vbv_lernwelt/assignment/migrations/0005_alter_assignment_assignment_type.py create mode 100644 server/vbv_lernwelt/learnpath/migrations/0002_alter_learningcontentassignment_assignment_type.py diff --git a/client/src/pages/cockpit/cockpitPage/SubmissionsOverview.vue b/client/src/pages/cockpit/cockpitPage/SubmissionsOverview.vue index 33550db9..bb679d13 100644 --- a/client/src/pages/cockpit/cockpitPage/SubmissionsOverview.vue +++ b/client/src/pages/cockpit/cockpitPage/SubmissionsOverview.vue @@ -92,7 +92,10 @@ const getShowDetailsText = (lc: LearningContent) => { const assignmentType = (lc as LearningContentAssignment).assignment_type; if (assignmentType === "CASEWORK" || assignmentType === "REFLECTION") { return t("Ergebnisse anschauen"); - } else if (assignmentType === "PREP_ASSIGNMENT") { + } else if ( + assignmentType === "PREP_ASSIGNMENT" || + assignmentType === "CONDITION_ACCEPTANCE" + ) { return t("Status anschauen"); } } @@ -109,7 +112,11 @@ const getDetailsLink = (lc: LearningContent) => { const getIconName = (lc: LearningContent) => { if (isAssignment(lc)) { const assignmentType = (lc as LearningContentAssignment).assignment_type; - if (assignmentType === "PREP_ASSIGNMENT" || assignmentType === "CASEWORK") { + if ( + assignmentType === "PREP_ASSIGNMENT" || + assignmentType === "CASEWORK" || + assignmentType === "CONDITION_ACCEPTANCE" + ) { return "it-icon-assignment-large"; } else if (assignmentType === "REFLECTION") { return "it-icon-test-large"; diff --git a/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue b/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue index fce54b94..591958b0 100644 --- a/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue +++ b/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue @@ -190,9 +190,11 @@ const assignmentUser = computed(() => { const endBadgeText = computed(() => { if (assignmentType.value === "PREP_ASSIGNMENT") { - return "Aufgaben"; + return t("Aufgaben"); } else if (assignmentType.value === "CASEWORK") { - return "Abgabe"; + return t("Abgabe"); + } else if (assignmentType.value === "CONDITION_ACCEPTANCE") { + return t("Akzeptieren"); } // just return the number of tasks as default diff --git a/client/src/types.ts b/client/src/types.ts index e3e68284..d95a7df8 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -344,7 +344,11 @@ export interface AssignmentEvaluationTask { }; } -export type AssignmentType = "CASEWORK" | "PREP_ASSIGNMENT" | "REFLECTION"; +export type AssignmentType = + | "CASEWORK" + | "PREP_ASSIGNMENT" + | "REFLECTION" + | "CONDITION_ACCEPTANCE"; export interface Assignment extends BaseCourseWagtailPage { readonly content_type: "assignment.Assignment"; diff --git a/client/src/utils/typeMaps.ts b/client/src/utils/typeMaps.ts index dbe01f63..34198631 100644 --- a/client/src/utils/typeMaps.ts +++ b/client/src/utils/typeMaps.ts @@ -1,5 +1,6 @@ import type { LearningContent } from "@/types"; import { assertUnreachable } from "@/utils/utils"; +import { useTranslation } from "i18next-vue"; export interface LearningContentIdentifier { title: string; @@ -9,15 +10,18 @@ export interface LearningContentIdentifier { export function learningContentTypeData( lc: LearningContent ): LearningContentIdentifier { + const { t } = useTranslation(); switch (lc.content_type) { case "learnpath.LearningContentAssignment": { let title = "unknown"; if (lc.assignment_type === "CASEWORK") { - title = "Geleitete Fallarbeit"; + title = t("Geleitete Fallarbeit"); } else if (lc.assignment_type === "PREP_ASSIGNMENT") { - title = "Vorbereitungsaufgabe"; + title = t("Vorbereitungsaufgabe"); } else if (lc.assignment_type === "REFLECTION") { - title = "Reflexion"; + title = t("Reflexion"); + } else if (lc.assignment_type === "CONDITION_ACCEPTANCE") { + title = t("Vorbedingung"); } return { title: title, diff --git a/server/vbv_lernwelt/assignment/creators/create_assignments.py b/server/vbv_lernwelt/assignment/creators/create_assignments.py index 50e6e00d..57add32b 100644 --- a/server/vbv_lernwelt/assignment/creators/create_assignments.py +++ b/server/vbv_lernwelt/assignment/creators/create_assignments.py @@ -2673,6 +2673,66 @@ def create_uk_basis_prep_assignment(course_id=COURSE_UK): return assignment +def create_uk_condition_acceptance(course_id=COURSE_UK_FR): + assignment_list_page = ( + CoursePage.objects.get(course_id=course_id) + .get_children() + .exact_type(AssignmentListPage) + .first() + ) + + assignment = AssignmentFactory( + parent=assignment_list_page, + assignment_type=AssignmentType.CONDITION_ACCEPTANCE.name, + title="Redlichkeitserklärung", + intro_text=replace_whitespace( + """ +

Was akzeptierst du?

+

+ Die folgende Redlichkeitserklärung ist ein wichtiges Dokument, das bestätigt, dass die Arbeit, die du einreichst, ganz und gar deine eigene ist und dass du alle Regeln der akademischen Integrität eingehalten hast. Akademische Integrität beinhaltet Ehrlichkeit, Verantwortung und Respekt für das geistige Eigentum anderer. Dies bedeutet, dass du keine unerlaubte Hilfe in Anspruch nimmst und dass du alle Quellen und Materialien, die du zur Unterstützung deiner Arbeit genutzt hast, korrekt zitierst und anerkennst. + Durch das Unterzeichnen dieser Erklärung bestätigst du, dass du die Bedeutung der akademischen Integrität verstanden hast und die Verantwortung für die Einhaltung dieser Prinzipien übernimmst. Bitte bedenke, dass das Brechen dieser Regeln ernsthafte Konsequenzen nach sich ziehen kann, darunter eine Verringerung deiner Note, das Durchfallen des Kurses oder andere disziplinarische Maßnahmen. +

+ """ + ), + performance_objectives=[], + ) + + assignment.tasks = [] + assignment.tasks.append( + ( + "task", + TaskBlockFactory( + title="Erklärung", + # it is hard to create a StreamValue programmatically, we have to + # create a `StreamValue` manually. Ask Daniel and/or Ramon + content=StreamValue( + TaskContentStreamBlock(), + stream_data=[ + ( + "explanation", + ExplanationBlockFactory( + text=RichText( + "Ich erkläre hiermit, dass ich diese Prüfung oder Aufgabe selbstständig und ohne unzulässige Hilfe Dritter ausgeführt habe. Alle verwendeten Quellen und Hilfsmittel sind korrekt und vollständig angegeben. Ich verstehe, dass ein Verstoß gegen diese Erklärung ernsthafte Konsequenzen nach sich ziehen kann, einschließlich, aber nicht beschränkt auf, Notenreduzierung, Kursversagen und disziplinarische Maßnahmen." + ) + ), + ), + ( + "user_confirmation", + ExplanationBlockFactory( + text=RichText("Ja, ich akzeptiere diese Bedingungen.") + ), + ), + ], + ), + ), + ) + ) + + assignment.save() + + return assignment + + def create_uk_reflection(course_id=COURSE_UK): assignment_list_page = ( CoursePage.objects.get(course_id=course_id) diff --git a/server/vbv_lernwelt/assignment/migrations/0005_alter_assignment_assignment_type.py b/server/vbv_lernwelt/assignment/migrations/0005_alter_assignment_assignment_type.py new file mode 100644 index 00000000..45cd2e6a --- /dev/null +++ b/server/vbv_lernwelt/assignment/migrations/0005_alter_assignment_assignment_type.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.13 on 2023-08-01 08:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("assignment", "0004_alter_assignmentcompletion_additional_json_data"), + ] + + operations = [ + migrations.AlterField( + model_name="assignment", + name="assignment_type", + field=models.CharField( + choices=[ + ("CASEWORK", "CASEWORK"), + ("PREP_ASSIGNMENT", "PREP_ASSIGNMENT"), + ("REFLECTION", "REFLECTION"), + ("CONDITION_ACCEPTANCE", "CONDITION_ACCEPTANCE"), + ], + default="CASEWORK", + max_length=50, + ), + ), + ] diff --git a/server/vbv_lernwelt/assignment/models.py b/server/vbv_lernwelt/assignment/models.py index e1854f54..74c25df6 100644 --- a/server/vbv_lernwelt/assignment/models.py +++ b/server/vbv_lernwelt/assignment/models.py @@ -112,6 +112,7 @@ class AssignmentType(Enum): CASEWORK = "CASEWORK" # Geleitete Fallarbeit PREP_ASSIGNMENT = "PREP_ASSIGNMENT" # Vorbereitungsauftrag REFLECTION = "REFLECTION" # Reflexion + CONDITION_ACCEPTANCE = "CONDITION_ACCEPTANCE" # Bedingungsannahme class Assignment(CourseBasePage): diff --git a/server/vbv_lernwelt/course/creators/test_course.py b/server/vbv_lernwelt/course/creators/test_course.py index 2eaaae2d..a43207f7 100644 --- a/server/vbv_lernwelt/course/creators/test_course.py +++ b/server/vbv_lernwelt/course/creators/test_course.py @@ -6,6 +6,7 @@ from slugify import slugify from wagtail.rich_text import RichText from vbv_lernwelt.assignment.creators.create_assignments import ( + create_uk_condition_acceptance, create_uk_fahrzeug_casework, create_uk_fahrzeug_prep_assignment, create_uk_reflection, @@ -79,6 +80,7 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False): ) create_uk_fahrzeug_casework(course_id=COURSE_TEST_ID) create_uk_fahrzeug_prep_assignment(course_id=COURSE_TEST_ID) + create_uk_condition_acceptance(course_id=COURSE_TEST_ID) create_uk_reflection(course_id=COURSE_TEST_ID) create_test_learning_path(include_uk=include_uk, include_vv=include_vv) @@ -292,6 +294,13 @@ damit du erfolgreich mit deinem Lernpfad (durch-)starten kannst. ), content_url=f"/course/{lp.get_course().slug}/media/handlungsfelder/{slugify(title)}", ) + LearningContentAssignmentFactory( + title="Redlichkeitserklärung", + parent=circle, + content_assignment=Assignment.objects.get( + slug__startswith="test-lehrgang-assignment-redlichkeits" + ), + ), LearningContentAssignmentFactory( title="Fahrzeug - Mein erstes Auto", assignment_type="PREP_ASSIGNMENT", diff --git a/server/vbv_lernwelt/course/creators/uk_course.py b/server/vbv_lernwelt/course/creators/uk_course.py index 58a75ead..cee7cd10 100644 --- a/server/vbv_lernwelt/course/creators/uk_course.py +++ b/server/vbv_lernwelt/course/creators/uk_course.py @@ -324,6 +324,13 @@ In diesem Circle erfährst du wie die überbetrieblichen Kurse aufgebaut sind. Z ) LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle) + LearningContentAssignmentFactory( + title="Redlichkeitserklärung", + parent=circle, + content_assignment=Assignment.objects.get( + slug__startswith="überbetriebliche-kurse-assignment-redlichkeits" + ), + ) LearningContentAssignmentFactory( title="Reflexion", assignment_type="REFLECTION", diff --git a/server/vbv_lernwelt/course/management/commands/create_default_courses.py b/server/vbv_lernwelt/course/management/commands/create_default_courses.py index d8b09b63..39afa90f 100644 --- a/server/vbv_lernwelt/course/management/commands/create_default_courses.py +++ b/server/vbv_lernwelt/course/management/commands/create_default_courses.py @@ -8,6 +8,7 @@ from django.utils import timezone from vbv_lernwelt.assignment.creators.create_assignments import ( create_uk_basis_prep_assignment, + create_uk_condition_acceptance, create_uk_fahrzeug_casework, create_uk_fahrzeug_prep_assignment, create_uk_fr_fahrzeug_casework, @@ -236,6 +237,7 @@ def create_course_uk_de(course_id=COURSE_UK, lang="de"): parent=course.coursepage, ) create_uk_kickoff_prep_assignment(course_id=course_id) + create_uk_condition_acceptance(course_id=course_id) create_uk_basis_prep_assignment(course_id=course_id) create_uk_fahrzeug_casework(course_id=course_id) create_uk_fahrzeug_prep_assignment(course_id=course_id) diff --git a/server/vbv_lernwelt/learnpath/migrations/0002_alter_learningcontentassignment_assignment_type.py b/server/vbv_lernwelt/learnpath/migrations/0002_alter_learningcontentassignment_assignment_type.py new file mode 100644 index 00000000..fcdbbdbe --- /dev/null +++ b/server/vbv_lernwelt/learnpath/migrations/0002_alter_learningcontentassignment_assignment_type.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.13 on 2023-08-01 08:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("learnpath", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="learningcontentassignment", + name="assignment_type", + field=models.CharField( + choices=[ + ("CASEWORK", "CASEWORK"), + ("PREP_ASSIGNMENT", "PREP_ASSIGNMENT"), + ("REFLECTION", "REFLECTION"), + ("CONDITION_ACCEPTANCE", "CONDITION_ACCEPTANCE"), + ], + default="CASEWORK", + max_length=50, + ), + ), + ] diff --git a/server/vbv_lernwelt/learnpath/models.py b/server/vbv_lernwelt/learnpath/models.py index 765f5aa9..6eb19c7f 100644 --- a/server/vbv_lernwelt/learnpath/models.py +++ b/server/vbv_lernwelt/learnpath/models.py @@ -376,6 +376,10 @@ class LearningContentAssignment(LearningContent): FieldPanel("description"), ] + def save(self, clean=True, user=None, log_action=False, **kwargs): + self.assignment_type = self.content_assignment.assignment_type + super().save(**kwargs) + class LearningContentDocumentList(LearningContent): can_user_self_toggle_course_completion = models.BooleanField(default=True)