Add CourseSessionAttendance course and CourseSessionAssignment

This commit is contained in:
Lorenz Padberg 2023-06-26 17:44:31 +02:00
parent a5acc66981
commit 2706d6785d
7 changed files with 288 additions and 52 deletions

View File

@ -1,7 +1,9 @@
import json import json
from datetime import datetime
import wagtail_factories import wagtail_factories
from django.conf import settings from django.conf import settings
from django.utils import timezone
from slugify import slugify from slugify import slugify
from wagtail.models import Site from wagtail.models import Site
from wagtail.rich_text import RichText from wagtail.rich_text import RichText
@ -34,7 +36,8 @@ from vbv_lernwelt.course.models import (
CourseSession, CourseSession,
CourseSessionUser, CourseSessionUser,
) )
from vbv_lernwelt.learnpath.models import Circle from vbv_lernwelt.course_session.models import CourseSessionAssignment, CourseSessionAttendanceCourse
from vbv_lernwelt.learnpath.models import Circle, LearningContentAssignment, LearningContentAttendanceCourse
from vbv_lernwelt.learnpath.tests.learning_path_factories import ( from vbv_lernwelt.learnpath.tests.learning_path_factories import (
CircleFactory, CircleFactory,
LearningContentAssignmentFactory, LearningContentAssignmentFactory,
@ -79,16 +82,20 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
create_test_media_library() create_test_media_library()
if with_sessions: if with_sessions:
now = timezone.now()
# course sessions # course sessions
cs_bern = CourseSession.objects.create( cs_bern = CourseSession.objects.create(
course_id=COURSE_TEST_ID, course_id=COURSE_TEST_ID,
title="Test Bern 2022 a", title="Test Bern 2022 a",
id=TEST_COURSE_SESSION_BERN_ID, id=TEST_COURSE_SESSION_BERN_ID,
start_date=now,
) )
cs_zurich = CourseSession.objects.create( cs_zurich = CourseSession.objects.create(
course_id=COURSE_TEST_ID, course_id=COURSE_TEST_ID,
title="Test Zürich 2022 a", title="Test Zürich 2022 a",
id=TEST_COURSE_SESSION_ZURICH_ID, id=TEST_COURSE_SESSION_ZURICH_ID,
start_date=now,
) )
trainer1 = User.objects.get(email="test-trainer1@example.com") trainer1 = User.objects.get(email="test-trainer1@example.com")
@ -115,6 +122,12 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
course_session=cs_zurich, course_session=cs_zurich,
user=student2, user=student2,
) )
for cs in CourseSession.objects.all():
for assignment in LearningContentAssignment.objects.all():
create_course_session_assignment(cs, assignment)
for attendance_course in LearningContentAttendanceCourse.objects.all():
create_course_session_attendance_course(cs, attendance_course)
return course return course
@ -143,6 +156,28 @@ def create_test_assignment_submitted_data(assignment, course_session, user):
) )
def create_course_session_assignment(course_session, assignment):
csa, created = CourseSessionAssignment.objects.get_or_create(
course_session=course_session,
learning_content=assignment,
)
return csa
def create_course_session_attendance_course(course_session, course):
casc = CourseSessionAttendanceCourse.objects.create(
course_session=course_session,
learning_content=course,
location="Handelsschule KV Bern, Zimmer 123, Eigerstrasse 16, 3012 Bern",
trainer="Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
)
casc.due_date.start = timezone.make_aware(datetime(2023, 6, 14, 8, 30))
casc.due_date.end = timezone.make_aware(datetime(2023, 6, 14, 17, 0))
casc.due_date.save()
return casc
def create_test_course_with_categories(apps=None, schema_editor=None): def create_test_course_with_categories(apps=None, schema_editor=None):
if apps is not None: if apps is not None:
Course = apps.get_model("course", "Course") Course = apps.get_model("course", "Course")

View File

@ -1,6 +1,6 @@
import os import os
import random import random
from datetime import datetime from datetime import datetime, timedelta
import djclick as click import djclick as click
from django.utils import timezone from django.utils import timezone
@ -70,7 +70,7 @@ from vbv_lernwelt.course.models import (
CourseSessionUser, CourseSessionUser,
) )
from vbv_lernwelt.course.services import mark_course_completion from vbv_lernwelt.course.services import mark_course_completion
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse, CourseSessionAssignment
from vbv_lernwelt.duedate.models import DueDate from vbv_lernwelt.duedate.models import DueDate
from vbv_lernwelt.feedback.creators.create_demo_feedback import create_feedback from vbv_lernwelt.feedback.creators.create_demo_feedback import create_feedback
from vbv_lernwelt.importer.services import ( from vbv_lernwelt.importer.services import (
@ -84,9 +84,9 @@ from vbv_lernwelt.learnpath.create_vv_new_learning_path import (
from vbv_lernwelt.learnpath.models import ( from vbv_lernwelt.learnpath.models import (
Circle, Circle,
LearningContent, LearningContent,
LearningContentAssignment,
LearningContentAttendanceCourse, LearningContentAttendanceCourse,
) )
from vbv_lernwelt.learnpath.models import LearningContentAssignment
from vbv_lernwelt.media_library.create_default_media_library import ( from vbv_lernwelt.media_library.create_default_media_library import (
create_default_media_library, create_default_media_library,
) )
@ -252,22 +252,22 @@ def create_course_uk_de():
# "trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch", # "trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
# } # }
# ], # ],
assignment_details_list=[ # assignment_details_list=[
{ # {
"learningContentId": LearningContentAssignment.objects.get( # "learningContentId": LearningContentAssignment.objects.get(
slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice" # slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"
).id, # ).id,
"submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z", # "submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z",
"evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", # "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z",
}, # },
{ # {
"learningContentId": LearningContentAssignment.objects.get( # "learningContentId": LearningContentAssignment.objects.get(
slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-fahrzeug-mein-erstes-auto" # slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-fahrzeug-mein-erstes-auto"
).id, # ).id,
"submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z", # "submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z",
"evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", # "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z",
}, # },
], # ],
) )
csac = CourseSessionAttendanceCourse.objects.create( csac = CourseSessionAttendanceCourse.objects.create(
@ -559,8 +559,25 @@ def create_course_training_de():
) )
for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING): for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING):
csa = CourseSessionAssignment.objects.create(
course_session=cs,
learning_content=LearningContentAssignment.objects.get(
slug=f"{course.slug}-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"
),
)
print(csa)
submission_deadline = csa.submission_deadline
submission_deadline.end = cs.start_date + timedelta(days=14)
submission_deadline.save()
evaluation_deadline = csa.evaluation_deadline
evaluation_deadline.end = cs.start_date + timedelta(days=28)
evaluation_deadline.save()
cs.assignment_details_list = [ cs.assignment_details_list = [
{ {
"learningContentId": LearningContentAssignment.objects.get( "learningContentId": LearningContentAssignment.objects.get(
slug=f"{course.slug}-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice" slug=f"{course.slug}-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"
).id, ).id,
@ -643,22 +660,22 @@ def create_course_training_fr():
) )
for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING_FR): for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING_FR):
cs.assignment_details_list = [ # cs.assignment_details_list = [
{ # {
"learningContentId": LearningContentAssignment.objects.get( # "learningContentId": LearningContentAssignment.objects.get(
slug=f"{course.slug}-lp-circle-véhicule-lc-vérification-dune-police-dassurance-de-véhicule-à-moteur" # slug=f"{course.slug}-lp-circle-véhicule-lc-vérification-dune-police-dassurance-de-véhicule-à-moteur"
).id, # ).id,
"submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z", # "submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z",
"evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", # "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z",
}, # },
{ # {
"learningContentId": LearningContentAssignment.objects.get( # "learningContentId": LearningContentAssignment.objects.get(
slug=f"{course.slug}-lp-circle-véhicule-lc-véhicule-à-moteur-ma-première-voiture" # slug=f"{course.slug}-lp-circle-véhicule-lc-véhicule-à-moteur-ma-première-voiture"
).id, # ).id,
"submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z", # "submissionDeadlineDateTimeUtc": "2023-06-13T19:00:00Z",
"evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", # "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z",
}, # },
] # ]
cs.save() cs.save()
# attach users as trainers to ÜK course # attach users as trainers to ÜK course
@ -730,22 +747,22 @@ def create_course_training_it():
) )
for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING_IT): for cs in CourseSession.objects.filter(course_id=COURSE_UK_TRAINING_IT):
cs.assignment_details_list = [ # cs.assignment_details_list = [
{ # {
"learningContentId": LearningContentAssignment.objects.get( # "learningContentId": LearningContentAssignment.objects.get(
slug=f"{course.slug}-lp-circle-veicolo-lc-verifica-di-una-polizza-di-assicurazione-veicoli-a-motore" # slug=f"{course.slug}-lp-circle-veicolo-lc-verifica-di-una-polizza-di-assicurazione-veicoli-a-motore"
).id, # ).id,
"submissionDeadlineDateTimeUtc": "2023-06-20T19:00:00Z", # "submissionDeadlineDateTimeUtc": "2023-06-20T19:00:00Z",
"evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", # "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z",
}, # },
{ # {
"learningContentId": LearningContentAssignment.objects.get( # "learningContentId": LearningContentAssignment.objects.get(
slug=f"{course.slug}-lp-circle-veicolo-lc-veicolo-la-mia-prima-auto" # slug=f"{course.slug}-lp-circle-veicolo-lc-veicolo-la-mia-prima-auto"
).id, # ).id,
"submissionDeadlineDateTimeUtc": "2023-06-20T19:00:00Z", # "submissionDeadlineDateTimeUtc": "2023-06-20T19:00:00Z",
"evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z", # "evaluationDeadlineDateTimeUtc": "2023-06-27T19:00:00Z",
}, # },
] # ]
cs.save() cs.save()
# attach users as trainers to ÜK course # attach users as trainers to ÜK course

View File

@ -0,0 +1,26 @@
from django.contrib import admin
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse, CourseSessionAssignment
@admin.register(CourseSessionAttendanceCourse)
class CourseSessionAttendanceCourseAdmin(admin.ModelAdmin):
# Inline fields are not possible for the DueDate model, because it is not a ForeignKey relatoion.
readonly_fields = ['course_session', 'learning_content', 'due_date']
list_display = [
"course_session",
"learning_content",
"trainer",
]
list_filter = ["course_session__course"]
@admin.register(CourseSessionAssignment)
class CourseSessionAssignmentAdmin(admin.ModelAdmin):
# Inline fields are not possible for the DueDate model, because it is not a ForeignKey relatoion.
readonly_fields = ['course_session', 'learning_content']
list_display = [
"course_session",
"learning_content",
]
list_filter = ["course_session__course"]

View File

@ -1,7 +1,15 @@
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _
from vbv_lernwelt.duedate.models import DueDate
class CourseSessionAttendanceCourse(models.Model): class CourseSessionAttendanceCourse(models.Model):
"""
Präsenzkurs Durchührung
Kann über einen Zeitraum von meheren Tagen gehen.
"""
course_session = models.ForeignKey( course_session = models.ForeignKey(
"course.CourseSession", "course.CourseSession",
on_delete=models.CASCADE, on_delete=models.CASCADE,
@ -19,5 +27,68 @@ class CourseSessionAttendanceCourse(models.Model):
location = models.CharField(max_length=255, blank=True, default="") location = models.CharField(max_length=255, blank=True, default="")
trainer = models.CharField(max_length=255, blank=True, default="") trainer = models.CharField(max_length=255, blank=True, default="")
def save(self, *args, **kwargs):
if not self.pk:
title = ""
page = None
if self.learning_content_id:
title = self.learning_content.title
page = self.learning_content.page_ptr
self.due_date = DueDate.objects.create(
title=f"{title} {_('Präsenzkurs')}",
course_session=self.course_session,
page=page)
super().save(*args, **kwargs)
def __str__(self):
return f"{self.course_session} - {self.learning_content}"
class CourseSessionAssignment(models.Model):
"""
Auftrag
- Geletitete Fallarbeit ist eine speziefische ausprägung eines Auftrags (assignment_type)
"""
course_session = models.ForeignKey(
"course.CourseSession",
on_delete=models.CASCADE,
)
learning_content = models.ForeignKey(
"learnpath.LearningContentAssignment",
on_delete=models.CASCADE,
)
submission_deadline = models.OneToOneField(
"duedate.DueDate",
on_delete=models.CASCADE,
related_name="assignment_submission_deadline",
)
evaluation_deadline = models.OneToOneField(
"duedate.DueDate",
on_delete=models.CASCADE,
related_name="assignment_evaluation_deadline",
)
def save(self, *args, **kwargs):
if not self.pk:
title = ""
page = None
if self.learning_content_id:
title = self.learning_content.title
page = self.learning_content.page_ptr
self.submission_deadline = DueDate.objects.create(
title=f"{title} {_('Submission Deadline')}",
course_session=self.course_session,
page=page)
self.evaluation_deadline = DueDate.objects.create(
title=f"{title} {_('Evaluation Deadline')}",
course_session=self.course_session,
page=page)
super().save(*args, **kwargs)
def __str__(self): def __str__(self):
return f"{self.course_session} - {self.learning_content}" return f"{self.course_session} - {self.learning_content}"

View File

@ -0,0 +1,47 @@
from datetime import timedelta
from django.test import TestCase
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.consts import COURSE_TEST_ID
from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.course_session.models import CourseSessionAssignment
from vbv_lernwelt.learnpath.models import Circle
class CourseSessionModelsTestCase(TestCase):
def setUp(self) -> None:
create_default_users()
create_test_course()
self.user = User.objects.get(username="student")
self.expert = User.objects.get(
username="patrizia.huggel@eiger-versicherungen.ch"
)
self.course_session = CourseSession.objects.create(
course_id=COURSE_TEST_ID,
title="Test Lehrgang Session",
)
csu = CourseSessionUser.objects.create(
course_session=self.course_session,
user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"),
role=CourseSessionUser.Role.EXPERT,
)
csu.expert.add(Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug"))
def test_course_session_assignment(self):
csa = CourseSessionAssignment.objects.create(
course_session=self.course_session,
# cs learning_content=LearningContentAssignment.objects.get(
# slug=f"{course.slug}-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"
# ),
)
print(csa)
submission_deadline = csa.submission_deadline
submission_deadline.end = self.course_session.start_date + timedelta(days=14)
submission_deadline.save()

View File

@ -0,0 +1,39 @@
from datetime import datetime
from django.test import TestCase
from django.utils import timezone
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course_session.models import CourseSessionAssignment, CourseSessionAttendanceCourse
from vbv_lernwelt.duedate.models import DueDate
class CourseSessionModelsTestCase(TestCase):
def setUp(self) -> None:
create_default_users()
create_test_course(with_sessions=True)
def test_course_session_assignment(self):
csa = CourseSessionAssignment.objects.all().first()
submission_deadline = csa.submission_deadline
deadline_date = datetime(2023, 7, 6, 8, 30, tzinfo=timezone.get_current_timezone())
submission_deadline.end = deadline_date
submission_deadline.save()
this_date = DueDate.objects.get(pk=submission_deadline.pk)
self.assertEqual(this_date.end, deadline_date)
def test_course_session_attendance_course(self):
csac = CourseSessionAttendanceCourse.objects.all().first()
due_date = csac.due_date
deadline_date = datetime(2023, 7, 6, 8, 30, tzinfo=timezone.get_current_timezone())
due_date.end = deadline_date
due_date.save()
this_date = DueDate.objects.get(pk=due_date.pk)
self.assertEqual(this_date.end, deadline_date)

View File

@ -14,6 +14,7 @@ class DueDateAdmin(admin.ModelAdmin):
date_hierarchy = "end" date_hierarchy = "end"
list_display = ["title", "course_session", "start", "end", "unset"] list_display = ["title", "course_session", "start", "end", "unset"]
list_filter = ["course_session"] list_filter = ["course_session"]
readonly_fields = ["course_session", "page"]
def formfield_for_foreignkey(self, db_field, request, **kwargs): def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "page": if db_field.name == "page":