diff --git a/server/config/settings/base.py b/server/config/settings/base.py index 0c82e079..5d32205a 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -113,6 +113,7 @@ LOCAL_APPS = [ "vbv_lernwelt.feedback", "vbv_lernwelt.files", "vbv_lernwelt.notify", + "vbv_lernwelt.assignment", ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS diff --git a/server/vbv_lernwelt/assignment/__init__.py b/server/vbv_lernwelt/assignment/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/vbv_lernwelt/assignment/admin.py b/server/vbv_lernwelt/assignment/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/server/vbv_lernwelt/assignment/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/vbv_lernwelt/assignment/apps.py b/server/vbv_lernwelt/assignment/apps.py new file mode 100644 index 00000000..d80b629e --- /dev/null +++ b/server/vbv_lernwelt/assignment/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AssignmentConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'assignment' diff --git a/server/vbv_lernwelt/assignment/migrations/0001_initial.py b/server/vbv_lernwelt/assignment/migrations/0001_initial.py new file mode 100644 index 00000000..7f2bc488 --- /dev/null +++ b/server/vbv_lernwelt/assignment/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.13 on 2023-03-28 08:53 + +import assignment.models +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0069_log_entry_jsonfield'), + ('files', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='AssignmentPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='Assignment', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ('starting_position', models.CharField(max_length=1024)), + ('due', models.DateTimeField()), + ('performance_objectives', wagtail.fields.StreamField([('performance_objective', assignment.models.PerformanceObjectiveBlock())], use_json_field=True)), + ('effort_required', models.CharField(max_length=255)), + ('tasks', wagtail.fields.StreamField([('task', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock()), ('file_submission_required', wagtail.blocks.BooleanBlock()), ('content', wagtail.blocks.StreamBlock([('explanation', assignment.models.ExplanationBlock()), ('user_text_input', assignment.models.UserTextInputBlock()), ('user_confirmation', assignment.models.UserConfirmationBlock())], use_json_field=True))]))], use_json_field=True)), + ('assessment_tool', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='files.uploadfile')), + ], + options={ + 'verbose_name': 'Auftrag', + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/server/vbv_lernwelt/assignment/migrations/__init__.py b/server/vbv_lernwelt/assignment/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/vbv_lernwelt/assignment/models.py b/server/vbv_lernwelt/assignment/models.py new file mode 100644 index 00000000..bed1ba4c --- /dev/null +++ b/server/vbv_lernwelt/assignment/models.py @@ -0,0 +1,84 @@ +from django.db import models +from django.db.models import DateTimeField, CharField +from wagtail import blocks +from wagtail.admin.panels import FieldPanel +from wagtail.blocks import StreamBlock +from wagtail.fields import StreamField +from wagtail.models import Page + +from vbv_lernwelt.files.models import UploadFile + + +class ExplanationBlock(blocks.CharBlock): + class Meta: + icon = "comment" + + +class PerformanceObjectiveBlock(blocks.CharBlock): + class Meta: + icon = "tick" + + +class UserTextInputBlock(blocks.StaticBlock): + class Meta: + icon = "edit" + + +class UserConfirmationBlock(blocks.CharBlock): + confirmation_text = blocks.BooleanBlock() + + class Meta: + icon = "tick-inverse" + + +class TaskBlock(blocks.StructBlock): + title = blocks.CharBlock() + file_submission_required = blocks.BooleanBlock() + content = StreamBlock( + [ + ("explanation", ExplanationBlock()), + ("user_text_input", UserTextInputBlock()), + ("user_confirmation", UserConfirmationBlock()), + ], + use_json_field=True, + ) + + class Meta: + icon = "tasks" + label = "Teilauftrag" + + +class Assignment(Page): + # TODO: Referenz auf durchfhrung + starting_position = CharField(max_length=1024) + due = DateTimeField() # Zwingend teil der Durchführung + performance_objectives = StreamField( + [ + ("performance_objective", PerformanceObjectiveBlock()), + ], + use_json_field=True, + ) + effort_required = CharField(max_length=255) + assessment_tool = models.OneToOneField(UploadFile, on_delete=models.PROTECT) + tasks = StreamField( + [ + ("task", TaskBlock()), + ], + use_json_field=True, + ) + + content_panels = Page.content_panels + [ + FieldPanel("starting_position"), + FieldPanel("due"), + FieldPanel("performance_objectives"), + FieldPanel("effort_required"), + FieldPanel("assessment_tool"), + FieldPanel("tasks"), + ] + + class Meta: + verbose_name = "Auftrag" + + +class AssignmentPage(Page): + subpage_types = ["assignment.Assignment"] diff --git a/server/vbv_lernwelt/assignment/tests.py b/server/vbv_lernwelt/assignment/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/server/vbv_lernwelt/assignment/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/vbv_lernwelt/assignment/tests/assignment_factories.py b/server/vbv_lernwelt/assignment/tests/assignment_factories.py new file mode 100644 index 00000000..1c4d281c --- /dev/null +++ b/server/vbv_lernwelt/assignment/tests/assignment_factories.py @@ -0,0 +1,55 @@ +import wagtail_factories + +from vbv_lernwelt.assignment.models import AssignmentPage, Assignment, TaskBlock + + +class ExplanationBlockFactory(wagtail_factories.StructBlockFactory): + class Meta: + model = "assignment.ExplanationBlock" + + text = """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.) + """ + + +class UserTextInputBlockFactory(wagtail_factories.StructBlockFactory): + class Meta: + model = "assignment.UserTextInputBlock" + + +class UserConfirmationBlockFactory(wagtail_factories.StructBlockFactory): + class Meta: + model = "assignment.UserConfirmationBlock" + + confirmation_text = "Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten." + + +class TaskBlockFactory(wagtail_factories.StructBlockFactory): + class Meta: + model = TaskBlock + + title = "Teilauftrag" + file_submission_required = False + content = wagtail_factories.StreamFieldFactory( + [ + ("explanation", ExplanationBlockFactory()), + ("user_text_input", UserTextInputBlockFactory()), + ("user_confirmation", UserConfirmationBlockFactory()), + ], + use_json_field=True, + ) + + +class AssignmentFactory(wagtail_factories.PageFactory): + title = "Auftrag" + + class Meta: + model = Assignment + + +class AssignmentPageFactory(wagtail_factories.PageFactory): + title = "Aufträge" + + class Meta: + model = AssignmentPage diff --git a/server/vbv_lernwelt/assignment/views.py b/server/vbv_lernwelt/assignment/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/server/vbv_lernwelt/assignment/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/server/vbv_lernwelt/course/models.py b/server/vbv_lernwelt/course/models.py index 6abf0e9d..bed607c4 100644 --- a/server/vbv_lernwelt/course/models.py +++ b/server/vbv_lernwelt/course/models.py @@ -121,6 +121,7 @@ class CoursePage(CourseBasePage): "learnpath.LearningPath", "competence.CompetenceProfilePage", "media_library.MediaLibraryPage", + "assignment.AssignmentPage", ] course = models.OneToOneField("course.Course", on_delete=models.PROTECT)