From 951d9b42e67947a5d9b47b1a7bd10598f17553f0 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Fri, 19 May 2023 15:46:39 +0200 Subject: [PATCH 01/12] Add text for "Vorbereitunsauftrag" --- .../assignment/creators/create_assignments.py | 255 +++++++++++++++++- .../0004_assignment_assignment_type.py | 18 ++ server/vbv_lernwelt/assignment/models.py | 25 +- .../commands/create_default_courses.py | 17 +- 4 files changed, 301 insertions(+), 14 deletions(-) create mode 100644 server/vbv_lernwelt/assignment/migrations/0004_assignment_assignment_type.py diff --git a/server/vbv_lernwelt/assignment/creators/create_assignments.py b/server/vbv_lernwelt/assignment/creators/create_assignments.py index 9471bbe9..5f3caa81 100644 --- a/server/vbv_lernwelt/assignment/creators/create_assignments.py +++ b/server/vbv_lernwelt/assignment/creators/create_assignments.py @@ -1,6 +1,11 @@ +from wagtail.blocks import StreamValue +from wagtail.blocks.list_block import ListBlock, ListValue +from wagtail.rich_text import RichText + from vbv_lernwelt.assignment.models import ( EvaluationSubTaskBlock, TaskContentStreamBlock, + AssignmentType, ) from vbv_lernwelt.assignment.tests.assignment_factories import ( AssignmentFactory, @@ -15,19 +20,11 @@ from vbv_lernwelt.assignment.tests.assignment_factories import ( from vbv_lernwelt.core.utils import replace_whitespace from vbv_lernwelt.course.consts import COURSE_TEST_ID, COURSE_UK from vbv_lernwelt.course.models import CoursePage -from wagtail.blocks import StreamValue -from wagtail.blocks.list_block import ListBlock, ListValue -from wagtail.rich_text import RichText -def create_uk_assignments(course_id=COURSE_UK): - course_page = CoursePage.objects.get(course_id=course_id) - assignment_page = AssignmentListPageFactory( - parent=course_page, - ) - +def create_uk_casework(assignment_list_page, course_id=COURSE_UK): assignment = AssignmentFactory( - parent=assignment_page, + parent=assignment_list_page, title="Überprüfen einer Motorfahrzeugs-Versicherungspolice", effort_required="ca. 5 Stunden", starting_position=replace_whitespace( @@ -896,3 +893,241 @@ def create_test_assignment(course_id=COURSE_TEST_ID): assignment.save() return assignment + + +def create_uk_prep_assignment(assignment_list_page, course_id=COURSE_UK): + assignment = AssignmentFactory( + parent=assignment_list_page, + assignment_type=AssignmentType.PREP_ASSIGNMENT.name, + title="Fahrzeug - Mein erstes Auto", + effort_required="ca. 3 Stunden", + starting_position=replace_whitespace( + """ +

Handlungskompetenzen, Arbeitssituationen & Leistungsziele

+

+ Handlungskompetenz d2: Informations- und Beratungsgespräch mit Kunden oder Lieferanten führen
+ Arbeitssituation 4: Kunden beraten und dazugehörige Prozesse abwickeln
+

+

+ +

+ Handlungskompetenz e4: Betriebsbezogene Inhalte multimedial aufbereiten
+ Arbeitssituation 1: Charakteristiken der Branche und Stärken des Betriebs einbringen
+

+

+ +

Ausgangslage

+

+ Stell dir vor, du hast die Autoprüfung abgeschlossen und nun kann es endlich losgehen mit deiner Mobilität. + Welches wird dein erstes eigenes Auto sein? Dieses Auto möchtest du natürlich auch schützen und richtig + versichern. +

+ """ + ), + performance_objectives=[], + ) + + assignment.tasks = [] + assignment.tasks.append( + ( + "task", + TaskBlockFactory( + title="Teilaufgabe 1: Verschaffe dir einen ersten Überblick zum Thema.", + # 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( + 'Schaue dazu das folgende Video: Wie funktioniert eine Autoversicherung? – Einfach erklärt' + ) + ), + ), + ( + "user_confirmation", + ExplanationBlockFactory( + text=RichText( + "Ja, ich habe das Video angeschaut und verstanden." + ) + ), + ), + ], + ), + ), + ) + ) + + assignment.tasks.append( + ( + "task", + TaskBlockFactory( + title="Teilaufgabe 2: Kapitel «Haftpflichtrecht und Motorfahrzeugversicherung» lesen", + # 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( + "Lese und bearbeite im Buch «Haftpflichtrecht und Motorfahrzeugversicherung» die entsprechenden Kapitel" + ) + ), + ), + ( + "user_confirmation", + ExplanationBlockFactory( + text=RichText( + "Ja, ich habe das Kapitel gelesen und verstanden." + ) + ), + ), + ], + ), + ), + ) + ) + + assignment.tasks.append( + ( + "task", + TaskBlockFactory( + title="Teilaufgabe 3: Offerte erstellen", + # 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( + replace_whitespace( + """ +

+ Nun geht es los! Erstelle dir für dein erstes eigenes Auto eine entsprechende + Offerte. Überlege dir, welche Deckungen du unbedingt abschliessen musst und + welche Deckungen für dich zusätzlich wünschenswert sind. Nutze dazu das + Offertentool deiner Unternehmung. Alternativ dazu kannst du auch irgendein + Onlinetool nutzen. +

+

+ Möglicherweise musst du mit deinem Geburtsjahrgang etwas schummeln, + damit du alt genug bist, um für dich eine Offerte zu machen. +

+ """ + ) + ) + ), + ), + ( + "user_confirmation", + ExplanationBlockFactory( + text=RichText("Ja, ich habe eine Offerte erstellt.") + ), + ), + ], + ), + ), + ) + ) + + assignment.tasks.append( + ( + "task", + TaskBlockFactory( + title="Teilaufgabe 4: Notizen und Fragestellungen", + content=StreamValue( + TaskContentStreamBlock(), + stream_data=[ + ( + "explanation", + ExplanationBlockFactory( + text=RichText( + "Mache dir im Verlauf des Prozesses Notizen zu den folgenden Fragestellungen:" + ) + ), + ), + ( + "user_text_input", + UserTextInputBlockFactory( + text=RichText( + "Wie bist du bei der Erstellung deiner Offerte vorgegangen?" + ) + ), + ), + ( + "user_text_input", + UserTextInputBlockFactory( + text=RichText( + "Welches waren die Schwierigkeiten bei der Erstellung der Offerte? Wie hast du die Schwierigkeiten gelöst?" + ) + ), + ), + ( + "user_text_input", + UserTextInputBlockFactory( + text=RichText( + "Welche Angaben sind zwingend notwendig, um eine saubere Motorfahrzeugofferte erstellen zu können?" + ) + ), + ), + ( + "user_text_input", + UserTextInputBlockFactory( + text=RichText( + "Welche zusätzlichen Deckungen hast du gewählt? Was waren die Überlegungen dazu?" + ) + ), + ), + ( + "user_text_input", + UserTextInputBlockFactory( + text=RichText( + "Welche Faktoren/Elemente bestimmen hauptsächlich die Höhe der Prämie?" + ) + ), + ), + ], + ), + ), + ) + ) + + assignment.tasks.append( + ( + "task", + TaskBlockFactory( + title="Teilaufgabe 5: Präzenz-Training", + content=StreamValue( + TaskContentStreamBlock(), + stream_data=[ + ( + "explanation", + ExplanationBlockFactory( + text=RichText( + "

Bringe die Offerte und diese Notizen mit ins Präsenz-Training.

" + "

Vergiss die dazugehörenden AVB nicht. Es ist auch okay, wenn du die Unterlagen nur elektronisch dabei hast.

" + ) + ), + ), + ], + ), + ), + ) + ) + + assignment.save() + + return assignment diff --git a/server/vbv_lernwelt/assignment/migrations/0004_assignment_assignment_type.py b/server/vbv_lernwelt/assignment/migrations/0004_assignment_assignment_type.py new file mode 100644 index 00000000..79e38723 --- /dev/null +++ b/server/vbv_lernwelt/assignment/migrations/0004_assignment_assignment_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.13 on 2023-05-19 13:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assignment', '0003_initial'), + ] + + operations = [ + migrations.AddField( + model_name='assignment', + name='assignment_type', + field=models.CharField(choices=[('CASEWORK', 'CASEWORK'), ('PREP_ASSIGNMENT', 'PREP_ASSIGNMENT'), ('REFLECTION', 'REFLECTION')], default='CASEWORK', max_length=50), + ), + ] diff --git a/server/vbv_lernwelt/assignment/models.py b/server/vbv_lernwelt/assignment/models.py index 9faab97e..fe879ed5 100644 --- a/server/vbv_lernwelt/assignment/models.py +++ b/server/vbv_lernwelt/assignment/models.py @@ -8,7 +8,10 @@ from wagtail.admin.panels import FieldPanel from wagtail.fields import RichTextField, StreamField from wagtail.models import Page -from vbv_lernwelt.core.constants import DEFAULT_RICH_TEXT_FEATURES +from vbv_lernwelt.core.constants import ( + DEFAULT_RICH_TEXT_FEATURES, + DEFAULT_RICH_TEXT_FEATURES_WITH_HEADER, +) from vbv_lernwelt.core.model_utils import find_available_slug from vbv_lernwelt.core.models import User from vbv_lernwelt.course.models import CourseBasePage @@ -104,6 +107,16 @@ class EvaluationTaskBlock(blocks.StructBlock): label = "Beurteilungskriterium" +AssignmentType = Enum( + "AssignmentType", + [ + "CASEWORK", # Geleitete Fallarbeit + "PREP_ASSIGNMENT", # Vorbereitungsauftrag + "REFLECTION", # Reflexion + ], +) + + class Assignment(CourseBasePage): serialize_field_names = [ "starting_position", @@ -115,8 +128,15 @@ class Assignment(CourseBasePage): "evaluation_tasks", ] + assignment_type = models.CharField( + max_length=50, + choices=[(tag.name, tag.name) for tag in AssignmentType], + default=AssignmentType.CASEWORK.name, + ) + starting_position = RichTextField( - help_text="Erläuterung der Ausgangslage", features=DEFAULT_RICH_TEXT_FEATURES + help_text="Erläuterung der Ausgangslage", + features=DEFAULT_RICH_TEXT_FEATURES_WITH_HEADER, ) effort_required = models.CharField( max_length=100, help_text="Zeitaufwand als Text", blank=True @@ -161,6 +181,7 @@ class Assignment(CourseBasePage): ) content_panels = Page.content_panels + [ + FieldPanel("assignment_type"), FieldPanel("starting_position"), FieldPanel("effort_required"), FieldPanel("performance_objectives"), 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 5e3f6b1c..5a10ee14 100644 --- a/server/vbv_lernwelt/course/management/commands/create_default_courses.py +++ b/server/vbv_lernwelt/course/management/commands/create_default_courses.py @@ -2,9 +2,13 @@ import random import djclick as click -from vbv_lernwelt.assignment.creators.create_assignments import create_uk_assignments +from vbv_lernwelt.assignment.creators.create_assignments import ( + create_uk_casework, + create_uk_prep_assignment, +) from vbv_lernwelt.assignment.models import Assignment from vbv_lernwelt.assignment.services import update_assignment_completion +from vbv_lernwelt.assignment.tests.assignment_factories import AssignmentListPageFactory from vbv_lernwelt.competence.create_uk_competence_profile import ( create_uk_competence_profile, create_uk_fr_competence_profile, @@ -148,7 +152,16 @@ def create_course_uk_de(): create_versicherungsvermittlerin_with_categories( course_id=COURSE_UK, title="Überbetriebliche Kurse" ) - create_uk_assignments(course_id=COURSE_UK) + + # assignments + course_page = CoursePage.objects.get(course_id=COURSE_UK) + assignment_list_page = AssignmentListPageFactory( + parent=course_page, + ) + create_uk_casework(assignment_list_page, course_id=COURSE_UK) + create_uk_prep_assignment(assignment_list_page, course_id=COURSE_UK) + + # learning path create_uk_learning_path(course_id=COURSE_UK) create_uk_competence_profile(course_id=COURSE_UK) create_default_media_library(course_id=COURSE_UK) From 9be0ce9d39ed84fcc0df0bdcb6f684146cd733c5 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Fri, 19 May 2023 15:57:31 +0200 Subject: [PATCH 02/12] Frontend: "Vorbereitungsauftrag" --- client/src/components/ui/ItTextarea.vue | 2 +- client/src/gql/gql.ts | 4 +- client/src/gql/graphql.ts | 19 ++++- client/src/gql/schema.graphql | 16 +++- client/src/graphql/queries.ts | 8 +- .../EvaluationIntro.vue | 6 +- .../EvaluationSummary.vue | 4 +- .../assignmentsPage/AssignmentDetails.vue | 4 +- .../AssignmentSubmissionProgress.vue | 2 +- .../cockpit/cockpitPage/AssignmentsTile.vue | 2 +- .../assignment/AssignmentIntroductionView.vue | 78 ++++++++++-------- .../assignment/AssignmentView.vue | 47 +++++++++-- .../layouts/LearningContentMultiLayout.vue | 4 +- client/src/services/assignmentService.ts | 4 +- client/src/types.ts | 6 +- client/src/utils/typeMaps.ts | 2 +- client/tailwind.css | 8 +- .../assignment/creators/create_assignments.py | 79 ++++++++++++++++++- .../vbv_lernwelt/assignment/graphql/types.py | 3 +- .../assignment/migrations/0001_initial.py | 3 +- server/vbv_lernwelt/assignment/models.py | 6 +- .../assignment/tests/assignment_factories.py | 2 +- .../course/creators/test_course.py | 10 ++- .../commands/create_default_courses.py | 9 ++- .../management/commands/create_uk_course.py | 10 ++- ...arningcontentassignment_assignment_type.py | 18 +++++ server/vbv_lernwelt/learnpath/models.py | 8 ++ 27 files changed, 282 insertions(+), 82 deletions(-) create mode 100644 server/vbv_lernwelt/learnpath/migrations/0003_learningcontentassignment_assignment_type.py diff --git a/client/src/components/ui/ItTextarea.vue b/client/src/components/ui/ItTextarea.vue index c4f3fa59..a296c6b5 100644 --- a/client/src/components/ui/ItTextarea.vue +++ b/client/src/components/ui/ItTextarea.vue @@ -3,7 +3,7 @@
{{ label }}