Sind das Kundenprofil und die Kundenbeziehung vollständig und nachvollziehbar dargestellt?
+
Ist das Alter des Fahrzeugs dokumentiert?
+
Welche Ressourcen stehen zur Verfügung?
+
+ """
+ )
+ ),
+ points=6,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage ist grösstenteils vollständig beschrieben.",
+ points=4,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage ist unvollständig - nur 2 Punkte wurden beschrieben.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage des Auftrag ist unvollständig - es fehlen mehr als 2 Punkte in der Beschreibung.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Inhaltsanalyse und Struktur",
+ max_points=6,
+ description=RichText(
+ "Sind die Deckungen der Police vollständig und nachvollziehbar dokumentiert?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse beinhaltet alle in der Police vorhandenen Deckungen und ist logisch aufgebaut.",
+ points=6,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse beinhaltet die meisten vorhandenen Deckungen in der Police und ist grösstenteils logisch aufgebaut.",
+ points=4,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse ist unvollständig (es fehlen mehr als 3 Deckungen) und der rote Faden ist nicht erkennbar.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse ist insgesamt nicht nachvollziehbar und es fehlen einige Deckungen.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Sinnvolle Empfehlungen",
+ max_points=6,
+ description=RichText(
+ "Leitet die lernende Person sinnvolle und geeignete Empfehlungen ab?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind durchgängig sinnvoll und nachvollziehbar begründet.",
+ points=6,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind grösstenteils sinnvoll und nachvollziehbar begründet.",
+ points=4,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind wenig sinnvoll und unvollständig begründet.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind weder sinnvoll nch nachvollziehbar begründet.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Qualität der Reflexion",
+ max_points=3,
+ description=RichText(
+ "Reflektiert die lernende Person die Durchführung der geleiteten Fallarbeit?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion bezieht sich auf die geleitete Fallarbeit und umfasst nachvollziehbare positive wie negative Aspekte.",
+ points=3,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion bezieht sich auf die geleitete Fallarbeit und umfasst grösstenteils nachvollziehbare positive wie negative Aspekte.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion ist unvollständig.",
+ points=1,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion bezieht sich nicht auf die geleitete Fallarbeit.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Eignung der Learnings",
+ max_points=3,
+ description=RichText(
+ "Leitet die lernende Person geeignete Learnings aus der Reflexion ab?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich auf die geleitete Fallarbeit und sind inhaltlich sinnvoll.",
+ points=3,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich grösstenteils auf die geleitete Fallarbeit und sind inhaltlich sinnvoll.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich teilweise auf die geleitete Fallarbeit und sind inhaltlich wenig sinnvoll.",
+ points=1,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich nicht auf die geleitete Fallarbeit.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
)
assignment.tasks = []
@@ -57,18 +244,24 @@ def create_uk_assignments(course_id=COURSE_UK):
TaskBlockFactory(
title="Teilaufgabe 1: Beispiel einer Versicherungspolice finden",
# it is hard to create a StreamValue programmatically, we have to
- # create a `StreamValue` manually. Ask the Daniel and/or Ramon
+ # create a `StreamValue` manually. Ask Daniel and/or Ramon
content=StreamValue(
TaskContentStreamBlock(),
stream_data=[
(
"explanation",
- ExplanationBlockFactory(text="Dies ist ein Beispieltext."),
+ ExplanationBlockFactory(
+ text=RichText(
+ "Bitte jemand aus deiner Familie oder deinem Freundeskreis darum, dir seine/ihre Motorfahrzeugversicherungspolice zur Verfügung zu stellen."
+ )
+ ),
),
(
"user_confirmation",
ExplanationBlockFactory(
- text="Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
+ text=RichText(
+ "Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
+ )
),
),
],
@@ -88,12 +281,16 @@ def create_uk_assignments(course_id=COURSE_UK):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Erläutere die Kundensituation und die Ausgangslage.
- * Hast du alle Informationen, die du für den Policen-Check benötigst?
- * Halte die wichtigsten Eckwerte des aktuellen Versicherungsverhältnisse in deiner Dokumentation fest (z.B wie lang wo versichert, Alter des Fahrzeugs, Kundenprofil, etc.)
- """
+ text=RichText(
+ replace_whitespace(
+ """
+ Erläutere die Kundensituation und die Ausgangslage.
+
+
Hast du alle Informationen, die du für den Policen-Check benötigst?
+
Halte die wichtigsten Eckwerte des aktuellen Versicherungsverhältnisse in deiner Dokumentation fest (z.B wie lang wo versichert, Alter des Fahrzeugs, Kundenprofil, etc.
+
+ """
+ )
)
),
),
@@ -116,10 +313,8 @@ def create_uk_assignments(course_id=COURSE_UK):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Zeige nun detailliert auf, wie dein Kundenbeispiel momentan versichert ist.
- """
+ text=RichText(
+ "Zeige nun detailliert auf, wie dein Kundenbeispiel momentan versichert ist."
)
),
),
@@ -141,40 +336,32 @@ def create_uk_assignments(course_id=COURSE_UK):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Erarbeite nun basierend auf deinen Erkenntnissen eine Empfehlung für die Person.
- """
+ text=RichText(
+ "Erarbeite nun basierend auf deinen Erkenntnissen eine Empfehlung für die Person."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest? Begründe deine Empfehlung
- """
+ text=RichText(
+ "Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest? Begründe deine Empfehlung"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Gibt es Deckungen, die du streichen würdest? Begründe deine Empfehlung.
- """
+ text=RichText(
+ "Gibt es Deckungen, die du streichen würdest? Begründe deine Empfehlung."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Wenn die Person gemäss deiner Einschätzung genau richtig versichert ist, argumentiere, warum dies der Fall ist.
- """
+ text=RichText(
+ "Wenn die Person gemäss deiner Einschätzung genau richtig versichert ist, argumentiere, warum dies der Fall ist."
)
),
),
@@ -195,40 +382,32 @@ def create_uk_assignments(course_id=COURSE_UK):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Reflektiere dein Handeln und halte deine Erkenntnisse fest. Frage dich dabei:
- """
+ text=RichText(
+ "Reflektiere dein Handeln und halte deine Erkenntnisse fest. Frage dich dabei:"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- War die Bearbeitung dieser geleiteten Fallarbeit erfolgreich? Begründe deine Einschätzung.
- """
+ text=RichText(
+ "War die Bearbeitung dieser geleiteten Fallarbeit erfolgreich? Begründe deine Einschätzung."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was ist dir bei der Bearbeitung des Auftrags gut gelungen?
- """
+ text=RichText(
+ "Was ist dir bei der Bearbeitung des Auftrags gut gelungen?"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was ist dir bei der Bearbeitung des Auftrags weniger gut gelungen?
- """
+ text=RichText(
+ "Was ist dir bei der Bearbeitung des Auftrags weniger gut gelungen?"
)
),
),
@@ -249,30 +428,24 @@ def create_uk_assignments(course_id=COURSE_UK):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Leite aus der Teilaufgabe 5 deine persönlichen Learnings ab.
- """
+ text=RichText(
+ "Leite aus der Teilaufgabe 5 deine persönlichen Learnings ab."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was würdest du beim nächsten Mal anders machen?
- """
+ text=RichText(
+ "Was würdest du beim nächsten Mal anders machen?"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was hast du beim Bearbeiten des Auftrags Neues gelernt?
- """
+ text=RichText(
+ "Was hast du beim Bearbeiten des Auftrags Neues gelernt?"
)
),
),
@@ -318,8 +491,8 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
),
),
],
- assessment_document_url="https://www.vbv.ch",
- assessment_description="Diese geleitete Fallarbeit wird auf Grund des folgenden Beurteilungsintrument bewertet.",
+ evaluation_document_url="https://www.vbv.ch",
+ evaluation_description="Diese geleitete Fallarbeit wird auf Grund des folgenden Beurteilungsintrument bewertet.",
)
assignment.tasks = []
@@ -335,12 +508,16 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
stream_data=[
(
"explanation",
- ExplanationBlockFactory(text="Dies ist ein Beispieltext."),
+ ExplanationBlockFactory(
+ text=RichText("Dies ist ein Beispieltext.")
+ ),
),
(
"user_confirmation",
ExplanationBlockFactory(
- text="Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
+ text=RichText(
+ "Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
+ )
),
),
],
@@ -360,12 +537,16 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Erläutere die Kundensituation und die Ausgangslage.
- * Hast du alle Informationen, die du für den Policen-Check benötigst?
- * Halte die wichtigsten Eckwerte des aktuellen Versicherungsverhältnisse in deiner Dokumentation fest (z.B wie lang wo versichert, Alter des Fahrzeugs, Kundenprofil, etc.)
- """
+ text=RichText(
+ replace_whitespace(
+ """
+ Erläutere die Kundensituation und die Ausgangslage.
+
+
Hast du alle Informationen, die du für den Policen-Check benötigst?
+
Halte die wichtigsten Eckwerte des aktuellen Versicherungsverhältnisse in deiner Dokumentation fest (z.B wie lang wo versichert, Alter des Fahrzeugs, Kundenprofil, etc.
+
+ """
+ )
)
),
),
@@ -388,10 +569,8 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Zeige nun detailliert auf, wie dein Kundenbeispiel momentan versichert ist.
- """
+ text=RichText(
+ "Zeige nun detailliert auf, wie dein Kundenbeispiel momentan versichert ist."
)
),
),
@@ -413,40 +592,32 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Erarbeite nun basierend auf deinen Erkenntnissen eine Empfehlung für die Person.
- """
+ text=RichText(
+ "Erarbeite nun basierend auf deinen Erkenntnissen eine Empfehlung für die Person."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest? Begründe deine Empfehlung
- """
+ text=RichText(
+ "Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest? Begründe deine Empfehlung"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Gibt es Deckungen, die du streichen würdest? Begründe deine Empfehlung.
- """
+ text=RichText(
+ "Gibt es Deckungen, die du streichen würdest? Begründe deine Empfehlung."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Wenn die Person gemäss deiner Einschätzung genau richtig versichert ist, argumentiere, warum dies der Fall ist.
- """
+ text=RichText(
+ "Wenn die Person gemäss deiner Einschätzung genau richtig versichert ist, argumentiere, warum dies der Fall ist."
)
),
),
@@ -467,40 +638,32 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Reflektiere dein Handeln und halte deine Erkenntnisse fest. Frage dich dabei:
- """
+ text=RichText(
+ "Reflektiere dein Handeln und halte deine Erkenntnisse fest. Frage dich dabei:"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- War die Bearbeitung dieser geleiteten Fallarbeit erfolgreich? Begründe deine Einschätzung.
- """
+ text=RichText(
+ "War die Bearbeitung dieser geleiteten Fallarbeit erfolgreich? Begründe deine Einschätzung."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was ist dir bei der Bearbeitung des Auftrags gut gelungen?
- """
+ text=RichText(
+ "Was ist dir bei der Bearbeitung des Auftrags gut gelungen?"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was ist dir bei der Bearbeitung des Auftrags weniger gut gelungen?
- """
+ text=RichText(
+ "Was ist dir bei der Bearbeitung des Auftrags weniger gut gelungen?"
)
),
),
@@ -521,30 +684,24 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
(
"explanation",
ExplanationBlockFactory(
- text=replace_whitespace(
- """
- Leite aus der Teilaufgabe 5 deine persönlichen Learnings ab.
- """
+ text=RichText(
+ "Leite aus der Teilaufgabe 5 deine persönlichen Learnings ab."
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was würdest du beim nächsten Mal anders machen?
- """
+ text=RichText(
+ "Was würdest du beim nächsten Mal anders machen?"
)
),
),
(
"user_text_input",
UserTextInputBlockFactory(
- text=replace_whitespace(
- """
- Was hast du beim Bearbeiten des Auftrags Neues gelernt?
- """
+ text=RichText(
+ "Was hast du beim Bearbeiten des Auftrags Neues gelernt?"
)
),
),
@@ -554,6 +711,185 @@ def create_test_assignment(course_id=COURSE_TEST_ID):
)
)
+ assignment.evaluation_tasks = []
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Ausgangslage des Auftrags",
+ description=RichText(
+ "Beschreibt der/die Lernende die Ausgangslage des Auftrags vollständig?"
+ ),
+ max_points=6,
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage des Auftrag ist vollständig beschrieben.",
+ description=RichText(
+ replace_whitespace(
+ """
+
+
Worum geht es? Was ist die Aufgabe?
+
Sind das Kundenprofil und die Kundenbeziehung vollständig und nachvollziehbar dargestellt?
+
Ist das Alter des Fahrzeugs dokumentiert?
+
Welche Ressourcen stehen zur Verfügung?
+
+ """
+ )
+ ),
+ points=6,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage ist grösstenteils vollständig beschrieben.",
+ points=4,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage ist unvollständig - nur 2 Punkte wurden beschrieben.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Ausgangslage des Auftrag ist unvollständig - es fehlen mehr als 2 Punkte in der Beschreibung.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Inhaltsanalyse und Struktur",
+ max_points=6,
+ description=RichText(
+ "Sind die Deckungen der Police vollständig und nachvollziehbar dokumentiert?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse beinhaltet alle in der Police vorhandenen Deckungen und ist logisch aufgebaut.",
+ points=6,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse beinhaltet die meisten vorhandenen Deckungen in der Police und ist grösstenteils logisch aufgebaut.",
+ points=4,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse ist unvollständig (es fehlen mehr als 3 Deckungen) und der rote Faden ist nicht erkennbar.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Analyse ist insgesamt nicht nachvollziehbar und es fehlen einige Deckungen.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Sinnvolle Empfehlungen",
+ max_points=6,
+ description=RichText(
+ "Leitet die lernende Person sinnvolle und geeignete Empfehlungen ab?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind durchgängig sinnvoll und nachvollziehbar begründet.",
+ points=6,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind grösstenteils sinnvoll und nachvollziehbar begründet.",
+ points=4,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind wenig sinnvoll und unvollständig begründet.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Empfehlungen sind weder sinnvoll nch nachvollziehbar begründet.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Qualität der Reflexion",
+ max_points=3,
+ description=RichText(
+ "Reflektiert die lernende Person die Durchführung der geleiteten Fallarbeit?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion bezieht sich auf die geleitete Fallarbeit und umfasst nachvollziehbare positive wie negative Aspekte.",
+ points=3,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion bezieht sich auf die geleitete Fallarbeit und umfasst grösstenteils nachvollziehbare positive wie negative Aspekte.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion ist unvollständig.",
+ points=1,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Reflexion bezieht sich nicht auf die geleitete Fallarbeit.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+ assignment.evaluation_tasks.append(
+ (
+ "task",
+ EvaluationTaskBlockFactory(
+ title="Eignung der Learnings",
+ max_points=3,
+ description=RichText(
+ "Leitet die lernende Person geeignete Learnings aus der Reflexion ab?"
+ ),
+ sub_tasks=ListValue(
+ ListBlock(EvaluationSubTaskBlock()),
+ values=[
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich auf die geleitete Fallarbeit und sind inhaltlich sinnvoll.",
+ points=3,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich grösstenteils auf die geleitete Fallarbeit und sind inhaltlich sinnvoll.",
+ points=2,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich teilweise auf die geleitete Fallarbeit und sind inhaltlich wenig sinnvoll.",
+ points=1,
+ ),
+ EvaluationSubTaskBlockFactory(
+ title="Die Learnings beziehen sich nicht auf die geleitete Fallarbeit.",
+ points=0,
+ ),
+ ],
+ ),
+ ),
+ ),
+ )
+
assignment.save()
return assignment
diff --git a/server/vbv_lernwelt/assignment/migrations/0001_initial.py b/server/vbv_lernwelt/assignment/migrations/0001_initial.py
index e3441d81..f4f0386e 100644
--- a/server/vbv_lernwelt/assignment/migrations/0001_initial.py
+++ b/server/vbv_lernwelt/assignment/migrations/0001_initial.py
@@ -1,19 +1,20 @@
-# Generated by Django 3.2.13 on 2023-04-11 09:30
+# Generated by Django 3.2.13 on 2023-05-01 15:43
import django.db.models.deletion
import wagtail.blocks
import wagtail.fields
+from django.conf import settings
from django.db import migrations, models
-import vbv_lernwelt.assignment.models
-
class Migration(migrations.Migration):
initial = True
dependencies = [
- ("wagtailcore", "0069_log_entry_jsonfield"),
+ ("course", "0006_alter_coursesession_attendance_days"),
+ ("wagtailcore", "0083_workflowcontenttype"),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
@@ -33,7 +34,9 @@ class Migration(migrations.Migration):
),
(
"starting_position",
- models.TextField(help_text="Erläuterung der Ausgangslage"),
+ wagtail.fields.RichTextField(
+ help_text="Erläuterung der Ausgangslage"
+ ),
),
(
"effort_required",
@@ -57,20 +60,6 @@ class Migration(migrations.Migration):
use_json_field=True,
),
),
- (
- "assessment_description",
- models.TextField(
- blank=True, help_text="Beschreibung der Bewertung"
- ),
- ),
- (
- "assessment_document_url",
- models.CharField(
- blank=True,
- help_text="URL zum Beurteilungsinstrument",
- max_length=255,
- ),
- ),
(
"tasks",
wagtail.fields.StreamField(
@@ -94,14 +83,35 @@ class Migration(migrations.Migration):
[
(
"text",
- wagtail.blocks.TextBlock(),
+ wagtail.blocks.RichTextBlock(
+ features=[
+ "ul",
+ "bold",
+ "italic",
+ ]
+ ),
)
]
),
),
(
"user_text_input",
- vbv_lernwelt.assignment.models.UserTextInputBlock(),
+ wagtail.blocks.StructBlock(
+ [
+ (
+ "text",
+ wagtail.blocks.RichTextBlock(
+ blank=True,
+ features=[
+ "ul",
+ "bold",
+ "italic",
+ ],
+ required=False,
+ ),
+ )
+ ]
+ ),
),
(
"user_confirmation",
@@ -109,7 +119,13 @@ class Migration(migrations.Migration):
[
(
"text",
- wagtail.blocks.TextBlock(),
+ wagtail.blocks.RichTextBlock(
+ features=[
+ "ul",
+ "bold",
+ "italic",
+ ]
+ ),
)
]
),
@@ -127,6 +143,78 @@ class Migration(migrations.Migration):
use_json_field=True,
),
),
+ (
+ "evaluation_description",
+ wagtail.fields.RichTextField(
+ blank=True, help_text="Beschreibung der Bewertung"
+ ),
+ ),
+ (
+ "evaluation_document_url",
+ models.CharField(
+ blank=True,
+ help_text="URL zum Beurteilungsinstrument",
+ max_length=255,
+ ),
+ ),
+ (
+ "evaluation_tasks",
+ wagtail.fields.StreamField(
+ [
+ (
+ "task",
+ wagtail.blocks.StructBlock(
+ [
+ ("title", wagtail.blocks.TextBlock()),
+ (
+ "description",
+ wagtail.blocks.RichTextBlock(
+ blank=True,
+ features=["ul", "bold", "italic"],
+ required=False,
+ ),
+ ),
+ ("max_points", wagtail.blocks.IntegerBlock()),
+ (
+ "sub_tasks",
+ wagtail.blocks.ListBlock(
+ wagtail.blocks.StructBlock(
+ [
+ (
+ "title",
+ wagtail.blocks.TextBlock(),
+ ),
+ (
+ "description",
+ wagtail.blocks.RichTextBlock(
+ blank=True,
+ features=[
+ "ul",
+ "bold",
+ "italic",
+ ],
+ required=False,
+ ),
+ ),
+ (
+ "points",
+ wagtail.blocks.IntegerBlock(),
+ ),
+ ]
+ ),
+ blank=True,
+ use_json_field=True,
+ ),
+ ),
+ ]
+ ),
+ )
+ ],
+ blank=True,
+ help_text="Beurteilungsschritte",
+ use_json_field=True,
+ ),
+ ),
],
options={
"verbose_name": "Auftrag",
@@ -153,4 +241,148 @@ class Migration(migrations.Migration):
},
bases=("wagtailcore.page",),
),
+ migrations.CreateModel(
+ name="AssignmentCompletionAuditLog",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ (
+ "completion_status",
+ models.CharField(
+ choices=[
+ (1, "in_progress"),
+ (2, "submitted"),
+ (3, "evaluation_in_progress"),
+ (4, "evaluated"),
+ ],
+ default="in_progress",
+ max_length=255,
+ ),
+ ),
+ ("completion_data", models.JSONField(default=dict)),
+ ("additional_json_data", models.JSONField(default=dict)),
+ ("assignment_user_email", models.CharField(max_length=255)),
+ ("assignment_slug", models.CharField(max_length=255)),
+ (
+ "evaluation_user_email",
+ models.CharField(blank=True, default="", max_length=255),
+ ),
+ (
+ "assignment",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="assignment.assignment",
+ ),
+ ),
+ (
+ "assignment_user",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ (
+ "course_session",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="course.coursesession",
+ ),
+ ),
+ (
+ "evaluation_user",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ migrations.CreateModel(
+ name="AssignmentCompletion",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("created_at", models.DateTimeField(auto_now_add=True)),
+ ("updated_at", models.DateTimeField(auto_now=True)),
+ ("submitted_at", models.DateTimeField(blank=True, null=True)),
+ ("evaluated_at", models.DateTimeField(blank=True, null=True)),
+ (
+ "completion_status",
+ models.CharField(
+ choices=[
+ (1, "in_progress"),
+ (2, "submitted"),
+ (3, "evaluation_in_progress"),
+ (4, "evaluated"),
+ ],
+ default="in_progress",
+ max_length=255,
+ ),
+ ),
+ ("completion_data", models.JSONField(default=dict)),
+ ("additional_json_data", models.JSONField(default=dict)),
+ (
+ "assignment",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="assignment.assignment",
+ ),
+ ),
+ (
+ "assignment_user",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ (
+ "course_session",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="course.coursesession",
+ ),
+ ),
+ (
+ "evaluation_user",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ migrations.AddConstraint(
+ model_name="assignmentcompletion",
+ constraint=models.UniqueConstraint(
+ fields=("assignment_user", "assignment", "course_session"),
+ name="assignment_completion_unique_user_assignment_course_session",
+ ),
+ ),
]
diff --git a/server/vbv_lernwelt/assignment/migrations/0002_auto_20230425_0849.py b/server/vbv_lernwelt/assignment/migrations/0002_auto_20230425_0849.py
deleted file mode 100644
index 185a5b58..00000000
--- a/server/vbv_lernwelt/assignment/migrations/0002_auto_20230425_0849.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# Generated by Django 3.2.13 on 2023-04-25 06:49
-
-import django.db.models.deletion
-from django.conf import settings
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("course", "0004_coursesession_assignment_details_list"),
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ("assignment", "0001_initial"),
- ]
-
- operations = [
- migrations.CreateModel(
- name="AssignmentCompletionAuditLog",
- fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("created_at", models.DateTimeField(auto_now_add=True)),
- (
- "completion_status",
- models.CharField(
- choices=[
- (1, "in_progress"),
- (2, "submitted"),
- (3, "grading_in_progress"),
- (4, "graded"),
- ],
- default="in_progress",
- max_length=255,
- ),
- ),
- ("completion_data", models.JSONField(default=dict)),
- ("additional_json_data", models.JSONField(default=dict)),
- ("assignment_user_email", models.CharField(max_length=255)),
- ("assignment_slug", models.CharField(max_length=255)),
- (
- "grading_user_email",
- models.CharField(blank=True, default="", max_length=255),
- ),
- (
- "assignment",
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.SET_NULL,
- related_name="+",
- to="assignment.assignment",
- ),
- ),
- (
- "assignment_user",
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.SET_NULL,
- related_name="+",
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- (
- "course_session",
- models.ForeignKey(
- null=True,
- on_delete=django.db.models.deletion.SET_NULL,
- related_name="+",
- to="course.coursesession",
- ),
- ),
- (
- "grading_user",
- models.ForeignKey(
- blank=True,
- null=True,
- on_delete=django.db.models.deletion.SET_NULL,
- related_name="+",
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.CreateModel(
- name="AssignmentCompletion",
- fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("created_at", models.DateTimeField(auto_now_add=True)),
- ("updated_at", models.DateTimeField(auto_now=True)),
- ("submitted_at", models.DateTimeField(blank=True, null=True)),
- ("graded_at", models.DateTimeField(blank=True, null=True)),
- (
- "completion_status",
- models.CharField(
- choices=[
- (1, "in_progress"),
- (2, "submitted"),
- (3, "grading_in_progress"),
- (4, "graded"),
- ],
- default="in_progress",
- max_length=255,
- ),
- ),
- ("completion_data", models.JSONField(default=dict)),
- ("additional_json_data", models.JSONField(default=dict)),
- (
- "assignment",
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- to="assignment.assignment",
- ),
- ),
- (
- "assignment_user",
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- (
- "course_session",
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- to="course.coursesession",
- ),
- ),
- (
- "grading_user",
- models.ForeignKey(
- blank=True,
- null=True,
- on_delete=django.db.models.deletion.CASCADE,
- related_name="+",
- to=settings.AUTH_USER_MODEL,
- ),
- ),
- ],
- ),
- migrations.AddConstraint(
- model_name="assignmentcompletion",
- constraint=models.UniqueConstraint(
- fields=("assignment_user", "assignment", "course_session"),
- name="assignment_completion_unique_user_assignment_course_session",
- ),
- ),
- ]
diff --git a/server/vbv_lernwelt/assignment/models.py b/server/vbv_lernwelt/assignment/models.py
index ba9cb055..626dc32d 100644
--- a/server/vbv_lernwelt/assignment/models.py
+++ b/server/vbv_lernwelt/assignment/models.py
@@ -5,9 +5,10 @@ from django.db.models import UniqueConstraint
from slugify import slugify
from wagtail import blocks
from wagtail.admin.panels import FieldPanel
-from wagtail.fields import StreamField
+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.model_utils import find_available_slug
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseBasePage
@@ -28,12 +29,8 @@ class AssignmentListPage(CourseBasePage):
return f"{self.title}"
-# class AssignmentSubmission(modModel):
-# created_at = models.DateTimeField(auto_now_add=True)
-
-
class ExplanationBlock(blocks.StructBlock):
- text = blocks.TextBlock()
+ text = blocks.RichTextBlock(features=DEFAULT_RICH_TEXT_FEATURES)
class Meta:
icon = "comment"
@@ -47,14 +44,16 @@ class PerformanceObjectiveBlock(blocks.StructBlock):
class UserTextInputBlock(blocks.StructBlock):
- text = blocks.TextBlock(blank=True)
+ text = blocks.RichTextBlock(
+ blank=True, required=False, features=DEFAULT_RICH_TEXT_FEATURES
+ )
class Meta:
icon = "edit"
class UserConfirmationBlock(blocks.StructBlock):
- text = blocks.TextBlock()
+ text = blocks.RichTextBlock(features=DEFAULT_RICH_TEXT_FEATURES)
class Meta:
icon = "tick-inverse"
@@ -78,17 +77,47 @@ class TaskBlock(blocks.StructBlock):
label = "Teilauftrag"
+class EvaluationSubTaskBlock(blocks.StructBlock):
+ title = blocks.TextBlock()
+ description = blocks.RichTextBlock(
+ blank=True, required=False, features=DEFAULT_RICH_TEXT_FEATURES
+ )
+ points = blocks.IntegerBlock()
+
+ class Meta:
+ icon = "tick"
+ label = "Beurteilung"
+
+
+class EvaluationTaskBlock(blocks.StructBlock):
+ title = blocks.TextBlock()
+ description = blocks.RichTextBlock(
+ blank=True, required=False, features=DEFAULT_RICH_TEXT_FEATURES
+ )
+ max_points = blocks.IntegerBlock()
+ sub_tasks = blocks.ListBlock(
+ EvaluationSubTaskBlock(), blank=True, use_json_field=True
+ )
+
+ class Meta:
+ icon = "tasks"
+ label = "Beurteilungskriterium"
+
+
class Assignment(CourseBasePage):
serialize_field_names = [
"starting_position",
"effort_required",
"performance_objectives",
- "assessment_description",
- "assessment_document_url",
+ "evaluation_description",
+ "evaluation_document_url",
"tasks",
+ "evaluation_tasks",
]
- starting_position = models.TextField(help_text="Erläuterung der Ausgangslage")
+ starting_position = RichTextField(
+ help_text="Erläuterung der Ausgangslage", features=DEFAULT_RICH_TEXT_FEATURES
+ )
effort_required = models.CharField(
max_length=100, help_text="Zeitaufwand als Text", blank=True
)
@@ -101,14 +130,6 @@ class Assignment(CourseBasePage):
blank=True,
help_text="Leistungsziele des Auftrags",
)
- assessment_description = models.TextField(
- blank=True, help_text="Beschreibung der Bewertung"
- )
- assessment_document_url = models.CharField(
- max_length=255,
- blank=True,
- help_text="URL zum Beurteilungsinstrument",
- )
tasks = StreamField(
[
@@ -119,13 +140,34 @@ class Assignment(CourseBasePage):
help_text="Teilaufgaben",
)
+ evaluation_description = RichTextField(
+ blank=True,
+ help_text="Beschreibung der Bewertung",
+ features=DEFAULT_RICH_TEXT_FEATURES,
+ )
+ evaluation_document_url = models.CharField(
+ max_length=255,
+ blank=True,
+ help_text="URL zum Beurteilungsinstrument",
+ )
+
+ evaluation_tasks = StreamField(
+ [
+ ("task", EvaluationTaskBlock()),
+ ],
+ use_json_field=True,
+ blank=True,
+ help_text="Beurteilungsschritte",
+ )
+
content_panels = Page.content_panels + [
FieldPanel("starting_position"),
FieldPanel("effort_required"),
FieldPanel("performance_objectives"),
- FieldPanel("assessment_description"),
- FieldPanel("assessment_document_url"),
FieldPanel("tasks"),
+ FieldPanel("evaluation_description"),
+ FieldPanel("evaluation_document_url"),
+ FieldPanel("evaluation_tasks"),
]
subpage_types = []
@@ -172,10 +214,13 @@ class Assignment(CourseBasePage):
if sub_dict["type"] in subtask_types
]
+ def filter_evaluation_tasks(self):
+ return self.evaluation_tasks.raw_data
+
AssignmentCompletionStatus = Enum(
"AssignmentCompletionStatus",
- ["in_progress", "submitted", "grading_in_progress", "graded"],
+ ["in_progress", "submitted", "evaluation_in_progress", "evaluated"],
)
@@ -184,8 +229,8 @@ class AssignmentCompletion(models.Model):
updated_at = models.DateTimeField(auto_now=True)
submitted_at = models.DateTimeField(null=True, blank=True)
- graded_at = models.DateTimeField(null=True, blank=True)
- grading_user = models.ForeignKey(
+ evaluated_at = models.DateTimeField(null=True, blank=True)
+ evaluation_user = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
@@ -217,12 +262,12 @@ class AssignmentCompletion(models.Model):
class AssignmentCompletionAuditLog(models.Model):
"""
- This model is used to store the "submitted" and "graded" data separately
+ This model is used to store the "submitted" and "evaluated" data separately
"""
created_at = models.DateTimeField(auto_now_add=True)
- grading_user = models.ForeignKey(
+ evaluation_user = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, blank=True, related_name="+"
)
assignment_user = models.ForeignKey(
@@ -246,4 +291,4 @@ class AssignmentCompletionAuditLog(models.Model):
assignment_user_email = models.CharField(max_length=255)
assignment_slug = models.CharField(max_length=255)
- grading_user_email = models.CharField(max_length=255, blank=True, default="")
+ evaluation_user_email = models.CharField(max_length=255, blank=True, default="")
diff --git a/server/vbv_lernwelt/assignment/serializers.py b/server/vbv_lernwelt/assignment/serializers.py
index 19d0bff2..3a478ce9 100644
--- a/server/vbv_lernwelt/assignment/serializers.py
+++ b/server/vbv_lernwelt/assignment/serializers.py
@@ -11,12 +11,12 @@ class AssignmentCompletionSerializer(serializers.ModelSerializer):
"created_at",
"updated_at",
"submitted_at",
- "graded_at",
+ "evaluated_at",
"assignment_user",
"assignment",
"course_session",
"completion_status",
"completion_data",
- "grading_user",
+ "evaluation_user",
"additional_json_data",
]
diff --git a/server/vbv_lernwelt/assignment/services.py b/server/vbv_lernwelt/assignment/services.py
index fc6ac4df..59d413f2 100644
--- a/server/vbv_lernwelt/assignment/services.py
+++ b/server/vbv_lernwelt/assignment/services.py
@@ -21,7 +21,7 @@ def update_assignment_completion(
course_session: CourseSession,
completion_data=None,
completion_status: Type[AssignmentCompletionStatus] = "in_progress",
- grading_user: User | None = None,
+ evaluation_user: User | None = None,
validate_completion_status_change: bool = True,
copy_task_data: bool = False,
) -> AssignmentCompletion:
@@ -40,7 +40,7 @@ def update_assignment_completion(
},
}
:param copy_task_data: if true, the task data will be copied to the completion data
- used for "submitted" and "graded" status, so that we don't lose the question
+ used for "submitted" and "evaluated" status, so that we don't lose the question
context
:return: AssignmentCompletion
"""
@@ -56,31 +56,35 @@ def update_assignment_completion(
if validate_completion_status_change:
# TODO: check time?
if completion_status == "submitted":
- if ac.completion_status in ["submitted", "grading_in_progress", "graded"]:
+ if ac.completion_status in [
+ "submitted",
+ "evaluation_in_progress",
+ "evaluated",
+ ]:
raise serializers.ValidationError(
{
"completion_status": f"Cannot update completion status from {ac.completion_status} to submitted"
}
)
- elif completion_status == "graded":
- if ac.completion_status == "graded":
+ elif completion_status == "evaluated":
+ if ac.completion_status == "evaluated":
raise serializers.ValidationError(
{
- "completion_status": f"Cannot update completion status from {ac.completion_status} to graded"
+ "completion_status": f"Cannot update completion status from {ac.completion_status} to evaluated"
}
)
- if completion_status in ["graded", "grading_in_progress"]:
- if grading_user is None:
+ if completion_status in ["evaluated", "evaluation_in_progress"]:
+ if evaluation_user is None:
raise serializers.ValidationError(
- {"grading_user": "grading_user is required for graded status"}
+ {"evaluation_user": "evaluation_user is required for evaluated status"}
)
- ac.grading_user = grading_user
+ ac.evaluation_user = evaluation_user
if completion_status == "submitted":
ac.submitted_at = timezone.now()
- elif completion_status == "graded":
- ac.graded_at = timezone.now()
+ elif completion_status == "evaluated":
+ ac.evaluated_at = timezone.now()
ac.completion_status = completion_status
@@ -101,19 +105,19 @@ def update_assignment_completion(
ac.save()
- if completion_status in ["graded", "submitted"]:
+ if completion_status in ["evaluated", "submitted"]:
acl = AssignmentCompletionAuditLog.objects.create(
assignment_user=assignment_user,
assignment=assignment,
course_session=course_session,
- grading_user=grading_user,
+ evaluation_user=evaluation_user,
completion_status=completion_status,
assignment_user_email=assignment_user.email,
assignment_slug=assignment.slug,
completion_data=deepcopy(ac.completion_data),
)
- if grading_user:
- acl.grading_user_email = grading_user.email
+ if evaluation_user:
+ acl.evaluation_user_email = evaluation_user.email
# copy over the question data, so that we don't lose the context
substasks = assignment.filter_user_subtasks()
@@ -132,9 +136,12 @@ def _remove_unknown_entries(assignment, completion_data):
possible_subtask_uuids = [
subtask["id"] for subtask in assignment.filter_user_subtasks()
]
+ possible_evaluation_uuids = [
+ task["id"] for task in assignment.filter_evaluation_tasks()
+ ]
filtered_completion_data = {
key: value
for key, value in completion_data.items()
- if key in possible_subtask_uuids
+ if key in possible_subtask_uuids or key in possible_evaluation_uuids
}
return filtered_completion_data
diff --git a/server/vbv_lernwelt/assignment/tests/assignment_factories.py b/server/vbv_lernwelt/assignment/tests/assignment_factories.py
index c152422d..2dcfaaa0 100644
--- a/server/vbv_lernwelt/assignment/tests/assignment_factories.py
+++ b/server/vbv_lernwelt/assignment/tests/assignment_factories.py
@@ -1,9 +1,12 @@
import wagtail_factories
from factory import SubFactory
+from wagtail.rich_text import RichText
from vbv_lernwelt.assignment.models import (
Assignment,
AssignmentListPage,
+ EvaluationSubTaskBlock,
+ EvaluationTaskBlock,
ExplanationBlock,
PerformanceObjectiveBlock,
TaskBlock,
@@ -15,14 +18,16 @@ from vbv_lernwelt.core.utils import replace_whitespace
class ExplanationBlockFactory(wagtail_factories.StructBlockFactory):
- text = "Dies ist ein Beispieltext."
+ text = RichText("Dies ist ein Beispieltext.")
class Meta:
model = ExplanationBlock
class UserConfirmationBlockFactory(wagtail_factories.StructBlockFactory):
- text = "Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
+ text = RichText(
+ "Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
+ )
class Meta:
model = UserConfirmationBlock
@@ -50,6 +55,24 @@ class TaskBlockFactory(wagtail_factories.StructBlockFactory):
model = TaskBlock
+class EvaluationSubTaskBlockFactory(wagtail_factories.StructBlockFactory):
+ title = "Beurteilung"
+ description = RichText("")
+ points = 6
+
+ class Meta:
+ model = EvaluationSubTaskBlock
+
+
+class EvaluationTaskBlockFactory(wagtail_factories.StructBlockFactory):
+ title = "Beurteilungskriterum"
+ description = RichText("")
+ max_points = 6
+
+ class Meta:
+ model = EvaluationTaskBlock
+
+
class PerformanceObjectiveBlockFactory(wagtail_factories.StructBlockFactory):
text = "Die Teilnehmer können die wichtigsten Eckwerte eines Versicherungsverhältnisses erfassen."
diff --git a/server/vbv_lernwelt/assignment/tests/test_assignment_api.py b/server/vbv_lernwelt/assignment/tests/test_assignment_api.py
index eb50cf6d..09d648d7 100644
--- a/server/vbv_lernwelt/assignment/tests/test_assignment_api.py
+++ b/server/vbv_lernwelt/assignment/tests/test_assignment_api.py
@@ -181,7 +181,7 @@ class AssignmentApiTestCase(APITestCase):
"assignment_id": self.assignment.id,
"assignment_user_id": self.student.id,
"course_session_id": self.cs.id,
- "completion_status": "grading_in_progress",
+ "completion_status": "evaluation_in_progress",
"completion_data": {
user_text_input["id"]: {
"expert_data": {"points": 1, "comment": "Gut gemacht!"}
@@ -196,7 +196,7 @@ class AssignmentApiTestCase(APITestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response_json["assignment_user"], self.student.id)
self.assertEqual(response_json["assignment"], self.assignment.id)
- self.assertEqual(response_json["completion_status"], "grading_in_progress")
+ self.assertEqual(response_json["completion_status"], "evaluation_in_progress")
self.assertDictEqual(
response_json["completion_data"],
{
@@ -212,7 +212,7 @@ class AssignmentApiTestCase(APITestCase):
course_session_id=self.cs.id,
assignment_id=self.assignment.id,
)
- self.assertEqual(db_entry.completion_status, "grading_in_progress")
+ self.assertEqual(db_entry.completion_status, "evaluation_in_progress")
self.assertDictEqual(
db_entry.completion_data,
{
@@ -230,7 +230,7 @@ class AssignmentApiTestCase(APITestCase):
"assignment_id": self.assignment.id,
"assignment_user_id": self.student.id,
"course_session_id": self.cs.id,
- "completion_status": "graded",
+ "completion_status": "evaluated",
"completion_data": {
user_text_input["id"]: {
"expert_data": {"points": 1, "comment": "Gut gemacht!"}
@@ -245,7 +245,7 @@ class AssignmentApiTestCase(APITestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response_json["assignment_user"], self.student.id)
self.assertEqual(response_json["assignment"], self.assignment.id)
- self.assertEqual(response_json["completion_status"], "graded")
+ self.assertEqual(response_json["completion_status"], "evaluated")
self.assertDictEqual(
response_json["completion_data"],
{
@@ -261,7 +261,7 @@ class AssignmentApiTestCase(APITestCase):
course_session_id=self.cs.id,
assignment_id=self.assignment.id,
)
- self.assertEqual(db_entry.completion_status, "graded")
+ self.assertEqual(db_entry.completion_status, "evaluated")
self.assertDictEqual(
db_entry.completion_data,
{
@@ -272,12 +272,12 @@ class AssignmentApiTestCase(APITestCase):
},
)
- # `graded` will create a new AssignmentCompletionAuditLog
+ # `evaluated` will create a new AssignmentCompletionAuditLog
acl = AssignmentCompletionAuditLog.objects.get(
assignment_user=self.student,
course_session_id=self.cs.id,
assignment_id=self.assignment.id,
- completion_status="graded",
+ completion_status="evaluated",
)
self.maxDiff = None
self.assertDictEqual(
diff --git a/server/vbv_lernwelt/assignment/tests/test_services.py b/server/vbv_lernwelt/assignment/tests/test_services.py
index dca1eda8..c1032abb 100644
--- a/server/vbv_lernwelt/assignment/tests/test_services.py
+++ b/server/vbv_lernwelt/assignment/tests/test_services.py
@@ -296,7 +296,42 @@ class UpdateAssignmentCompletionTestCase(TestCase):
)
)
- def test_can_add_grading_data_without_loosing_user_input_data(self):
+ def test_can_evaluate_with_evaluation_tasks(self):
+ ac = AssignmentCompletion.objects.create(
+ assignment_user=self.user,
+ assignment=self.assignment,
+ course_session=self.course_session,
+ completion_status="submitted",
+ )
+
+ evaluation_task = self.assignment.filter_evaluation_tasks()[0]
+
+ update_assignment_completion(
+ assignment_user=self.user,
+ assignment=self.assignment,
+ course_session=self.course_session,
+ completion_data={
+ evaluation_task["id"]: {
+ "expert_data": {"points": 2, "text": "Gut gemacht!"}
+ },
+ },
+ completion_status="evaluation_in_progress",
+ evaluation_user=self.trainer,
+ )
+
+ ac = AssignmentCompletion.objects.get(
+ assignment_user=self.user,
+ assignment=self.assignment,
+ course_session=self.course_session,
+ )
+
+ self.assertEqual(ac.completion_status, "evaluation_in_progress")
+ trainer_input = ac.completion_data[evaluation_task["id"]]
+ self.assertDictEqual(
+ trainer_input["expert_data"], {"points": 2, "text": "Gut gemacht!"}
+ )
+
+ def test_can_add_evaluation_data_without_loosing_user_input_data(self):
subtasks = self.assignment.filter_user_subtasks(
subtask_types=["user_text_input"]
)
@@ -329,8 +364,8 @@ class UpdateAssignmentCompletionTestCase(TestCase):
"expert_data": {"points": 1, "comment": "Gut gemacht!"}
},
},
- completion_status="grading_in_progress",
- grading_user=self.trainer,
+ completion_status="evaluation_in_progress",
+ evaluation_user=self.trainer,
)
ac = AssignmentCompletion.objects.get(
@@ -339,7 +374,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
course_session=self.course_session,
)
- self.assertEqual(ac.completion_status, "grading_in_progress")
+ self.assertEqual(ac.completion_status, "evaluation_in_progress")
user_input = ac.completion_data[user_text_input["id"]]
self.assertDictEqual(
user_input["expert_data"], {"points": 1, "comment": "Gut gemacht!"}
@@ -348,7 +383,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
user_input["user_data"]["text"], "Ich würde nichts weiteres empfehlen."
)
- def test_cannot_grading_data_without_grading_user(self):
+ def test_cannot_evaluate_data_without_evaluation_user(self):
subtasks = self.assignment.filter_user_subtasks(
subtask_types=["user_text_input"]
)
@@ -377,7 +412,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
assignment_user=self.user,
assignment=self.assignment,
course_session=self.course_session,
- completion_status="grading_in_progress",
+ completion_status="evaluation_in_progress",
completion_data={
user_text_input["id"]: {
"expert_data": {"points": 1, "comment": "Gut gemacht!"}
@@ -386,5 +421,5 @@ class UpdateAssignmentCompletionTestCase(TestCase):
)
self.assertTrue(
- "grading_user" in error.exception.detail,
+ "evaluation_user" in error.exception.detail,
)
diff --git a/server/vbv_lernwelt/assignment/views.py b/server/vbv_lernwelt/assignment/views.py
index 66eeb27a..6d1d1554 100644
--- a/server/vbv_lernwelt/assignment/views.py
+++ b/server/vbv_lernwelt/assignment/views.py
@@ -64,6 +64,19 @@ def request_assignment_completion_for_user(
raise PermissionDenied()
+@api_view(["GET"])
+def request_assignment_completion_status(request, assignment_id, course_session_id):
+ # TODO quickfix before GraphQL...
+ if is_course_session_expert(request.user, course_session_id):
+ qs = AssignmentCompletion.objects.filter(
+ course_session_id=course_session_id,
+ assignment_id=assignment_id,
+ ).values("id", "assignment_user_id", "completion_status")
+ return Response(status=200, data=qs)
+
+ raise PermissionDenied()
+
+
@api_view(["POST"])
def upsert_user_assignment_completion(request):
try:
@@ -107,12 +120,14 @@ def upsert_user_assignment_completion(request):
@api_view(["POST"])
-def grade_assignment_completion(request):
+def evaluate_assignment_completion(request):
try:
assignment_id = request.data.get("assignment_id")
assignment_user_id = request.data.get("assignment_user_id")
course_session_id = request.data.get("course_session_id")
- completion_status = request.data.get("completion_status", "grading_in_progress")
+ completion_status = request.data.get(
+ "completion_status", "evaluation_in_progress"
+ )
completion_data = request.data.get("completion_data", {})
assignment_page = Page.objects.get(id=assignment_id)
@@ -133,7 +148,7 @@ def grade_assignment_completion(request):
completion_data=completion_data,
completion_status=completion_status,
copy_task_data=False,
- grading_user=request.user,
+ evaluation_user=request.user,
)
logger.debug(
@@ -144,7 +159,7 @@ def grade_assignment_completion(request):
assignment_user_id=assignment_user_id,
course_session_id=course_session_id,
completion_status=completion_status,
- grading_user_id=request.user.id,
+ evaluation_user_id=request.user.id,
)
return Response(status=200, data=AssignmentCompletionSerializer(ac).data)
diff --git a/server/vbv_lernwelt/core/constants.py b/server/vbv_lernwelt/core/constants.py
new file mode 100644
index 00000000..dfd65020
--- /dev/null
+++ b/server/vbv_lernwelt/core/constants.py
@@ -0,0 +1,5 @@
+DEFAULT_RICH_TEXT_FEATURES = [
+ "ul",
+ "bold",
+ "italic",
+]
diff --git a/server/vbv_lernwelt/core/create_default_users.py b/server/vbv_lernwelt/core/create_default_users.py
index d885aaa8..c5cced85 100644
--- a/server/vbv_lernwelt/core/create_default_users.py
+++ b/server/vbv_lernwelt/core/create_default_users.py
@@ -176,6 +176,7 @@ def create_default_users(user_model=User, group_model=Group, default_password=No
first_name="Lina",
last_name="Egger",
avatar_url="/static/avatars/uk1.lina.egger.jpg",
+ password="myvbv1234",
)
_create_student_user(
email="evelyn.schmid@example.com",
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 5dd86501..75262a53 100644
--- a/server/vbv_lernwelt/course/management/commands/create_default_courses.py
+++ b/server/vbv_lernwelt/course/management/commands/create_default_courses.py
@@ -69,7 +69,7 @@ def command(course):
slug="überbetriebliche-kurse-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
),
course_session=CourseSession.objects.get(title="Bern 2023 a"),
- user=User.objects.get(email="michael.meier@example.com"),
+ user=User.objects.get(email="lina.egger@example.com"),
)
if COURSE_UK_FR in course:
@@ -320,6 +320,12 @@ def create_course_uk_de_assignment_completion_data(assignment, course_session, u
}
},
)
+ update_assignment_completion(
+ assignment_user=user,
+ assignment=assignment,
+ course_session=course_session,
+ completion_status="submitted",
+ )
def create_course_uk_de_completion_data(course_session):
diff --git a/server/vbv_lernwelt/course/migrations/0006_alter_coursesession_attendance_days.py b/server/vbv_lernwelt/course/migrations/0006_alter_coursesession_attendance_days.py
new file mode 100644
index 00000000..c32ef1a2
--- /dev/null
+++ b/server/vbv_lernwelt/course/migrations/0006_alter_coursesession_attendance_days.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.2.13 on 2023-04-26 16:28
+
+import django_jsonform.models.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("course", "0005_alter_coursesession_attendance_days"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="coursesession",
+ name="attendance_days",
+ field=django_jsonform.models.fields.JSONField(blank=True, default=list),
+ ),
+ ]
diff --git a/server/vbv_lernwelt/course/views.py b/server/vbv_lernwelt/course/views.py
index 0068cffc..3e4146ca 100644
--- a/server/vbv_lernwelt/course/views.py
+++ b/server/vbv_lernwelt/course/views.py
@@ -149,12 +149,9 @@ def get_course_sessions(request):
@api_view(["GET"])
-def get_course_session_users(request, course_slug):
+def get_course_session_users(request, course_session_id):
try:
- course_sessions = course_sessions_for_user_qs(request.user).filter(
- course__slug=course_slug
- )
- qs = CourseSessionUser.objects.filter(course_session__in=course_sessions)
+ qs = CourseSessionUser.objects.filter(course_session_id=course_session_id)
user_data = [csu.to_dict() for csu in qs]
return Response(status=200, data=user_data)