VBV-450: Custom CourseSessionAttendanceCourse model
This commit is contained in:
parent
e631cc4d13
commit
a5acc66981
|
|
@ -230,7 +230,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
): CourseSessionAttendanceCourse | undefined {
|
||||
if (currentCourseSession.value) {
|
||||
return currentCourseSession.value.attendance_courses.find(
|
||||
(attendanceCourse) => attendanceCourse.learningContentId === contentId
|
||||
(attendanceCourse) => attendanceCourse.learning_content === contentId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ export interface CircleDocument {
|
|||
}
|
||||
|
||||
export interface CourseSessionAttendanceCourse {
|
||||
learningContentId: number;
|
||||
learning_content: number;
|
||||
start: string;
|
||||
end: string;
|
||||
location: string;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ LOCAL_APPS = [
|
|||
"vbv_lernwelt.learnpath",
|
||||
"vbv_lernwelt.competence",
|
||||
"vbv_lernwelt.media_library",
|
||||
"vbv_lernwelt.course_session",
|
||||
"vbv_lernwelt.feedback",
|
||||
"vbv_lernwelt.files",
|
||||
"vbv_lernwelt.notify",
|
||||
|
|
|
|||
|
|
@ -29,4 +29,4 @@ def command():
|
|||
call_command("migrate")
|
||||
call_command("create_default_users")
|
||||
call_command("create_default_courses")
|
||||
call_command("create_default_duedates")
|
||||
# call_command("create_default_duedates")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import os
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
import djclick as click
|
||||
from django.utils import timezone
|
||||
|
||||
from vbv_lernwelt.assignment.creators.create_assignments import (
|
||||
create_uk_basis_prep_assignment,
|
||||
|
|
@ -68,6 +70,8 @@ from vbv_lernwelt.course.models import (
|
|||
CourseSessionUser,
|
||||
)
|
||||
from vbv_lernwelt.course.services import mark_course_completion
|
||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
from vbv_lernwelt.duedate.models import DueDate
|
||||
from vbv_lernwelt.feedback.creators.create_demo_feedback import create_feedback
|
||||
from vbv_lernwelt.importer.services import (
|
||||
import_course_sessions_from_excel,
|
||||
|
|
@ -237,17 +241,17 @@ def create_course_uk_de():
|
|||
cs = CourseSession.objects.create(
|
||||
course_id=COURSE_UK,
|
||||
title="Bern 2023 a",
|
||||
attendance_courses=[
|
||||
{
|
||||
"learningContentId": LearningContentAttendanceCourse.objects.get(
|
||||
slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-präsenzkurs-fahrzeug"
|
||||
).id,
|
||||
"start": "2023-05-23T08:30:00+0200",
|
||||
"end": "2023-05-23T17:00:00+0200",
|
||||
"location": "Handelsschule KV Bern, Zimmer 123, Eigerstrasse 16, 3012 Bern",
|
||||
"trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
|
||||
}
|
||||
],
|
||||
# attendance_courses=[
|
||||
# {
|
||||
# "learningContentId": LearningContentAttendanceCourse.objects.get(
|
||||
# slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-präsenzkurs-fahrzeug"
|
||||
# ).id,
|
||||
# "start": "2023-05-23T08:30:00+0200",
|
||||
# "end": "2023-05-23T17:00:00+0200",
|
||||
# "location": "Handelsschule KV Bern, Zimmer 123, Eigerstrasse 16, 3012 Bern",
|
||||
# "trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
|
||||
# }
|
||||
# ],
|
||||
assignment_details_list=[
|
||||
{
|
||||
"learningContentId": LearningContentAssignment.objects.get(
|
||||
|
|
@ -266,6 +270,23 @@ def create_course_uk_de():
|
|||
],
|
||||
)
|
||||
|
||||
csac = CourseSessionAttendanceCourse.objects.create(
|
||||
course_session=cs,
|
||||
learning_content=LearningContentAttendanceCourse.objects.get(
|
||||
slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-präsenzkurs-fahrzeug"
|
||||
),
|
||||
due_date=DueDate.objects.create(
|
||||
course_session=cs,
|
||||
start=timezone.make_aware(datetime(2023, 6, 14, 8, 30)),
|
||||
end=timezone.make_aware(datetime(2023, 6, 14, 17, 0)),
|
||||
page=LearningContentAttendanceCourse.objects.get(
|
||||
slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-präsenzkurs-fahrzeug"
|
||||
),
|
||||
),
|
||||
location="Handelsschule KV Bern, Zimmer 123, Eigerstrasse 16, 3012 Bern",
|
||||
trainer="Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
|
||||
)
|
||||
|
||||
# figma demo users and data
|
||||
csu = CourseSessionUser.objects.create(
|
||||
course_session=cs,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 3.2.13 on 2023-06-14 14:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('course', '0004_import_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='coursesession',
|
||||
name='attendance_courses',
|
||||
),
|
||||
]
|
||||
|
|
@ -195,23 +195,23 @@ class CourseSession(models.Model):
|
|||
|
||||
# TODO: Das wird durch event modell ersetzt
|
||||
|
||||
ATTENDANCE_COURSES_SCHEMA = {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"learningContentId": {
|
||||
"type": "number",
|
||||
"title": "ID des Lerninhalts",
|
||||
"required": True,
|
||||
},
|
||||
"start": {"type": "string", "format": "datetime"},
|
||||
"end": {"type": "string", "format": "datetime"},
|
||||
"location": {"type": "string"},
|
||||
"trainer": {"type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
# ATTENDANCE_COURSES_SCHEMA = {
|
||||
# "type": "array",
|
||||
# "items": {
|
||||
# "type": "object",
|
||||
# "properties": {
|
||||
# "learningContentId": {
|
||||
# "type": "number",
|
||||
# "title": "ID des Lerninhalts",
|
||||
# "required": True,
|
||||
# },
|
||||
# "start": {"type": "string", "format": "datetime"},
|
||||
# "end": {"type": "string", "format": "datetime"},
|
||||
# "location": {"type": "string"},
|
||||
# "trainer": {"type": "string"},
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
|
@ -228,9 +228,6 @@ class CourseSession(models.Model):
|
|||
start_date = models.DateField(null=True, blank=True)
|
||||
end_date = models.DateField(null=True, blank=True)
|
||||
|
||||
attendance_courses = JSONField(
|
||||
schema=ATTENDANCE_COURSES_SCHEMA, blank=True, default=list
|
||||
)
|
||||
assignment_details_list = models.JSONField(default=list, blank=True)
|
||||
|
||||
additional_json_data = models.JSONField(default=dict, blank=True)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ from vbv_lernwelt.course.models import (
|
|||
CourseCompletion,
|
||||
CourseSession,
|
||||
)
|
||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
from vbv_lernwelt.course_session.serializers import (
|
||||
CourseSessionAttendanceCourseSerializer,
|
||||
)
|
||||
from vbv_lernwelt.duedate.models import DueDate
|
||||
from vbv_lernwelt.duedate.serializers import DueDateSerializer
|
||||
|
||||
|
|
@ -52,6 +56,7 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
competence_url = serializers.SerializerMethodField()
|
||||
media_library_url = serializers.SerializerMethodField()
|
||||
documents = serializers.SerializerMethodField()
|
||||
attendance_courses = serializers.SerializerMethodField()
|
||||
duedates = serializers.SerializerMethodField()
|
||||
|
||||
def get_course(self, obj):
|
||||
|
|
@ -78,6 +83,11 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
)
|
||||
return CircleDocumentSerializer(documents, many=True).data
|
||||
|
||||
def get_attendance_courses(self, obj):
|
||||
return CourseSessionAttendanceCourseSerializer(
|
||||
CourseSessionAttendanceCourse.objects.filter(course_session=obj), many=True
|
||||
).data
|
||||
|
||||
def get_duedates(self, obj):
|
||||
# TODO: Filter by user / userrole
|
||||
duedates = DueDate.objects.filter(course_session=obj)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CourseSessionConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "vbv_lernwelt.course_session"
|
||||
|
||||
def ready(self):
|
||||
try:
|
||||
# pylint: disable=unused-import,import-outside-toplevel
|
||||
import vbv_lernwelt.course_session.signals # noqa F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Generated by Django 3.2.13 on 2023-06-14 15:01
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('learnpath', '0007_learningunit_title_hidden'),
|
||||
('course', '0005_remove_coursesession_attendance_courses'),
|
||||
('duedate', '0002_auto_20230614_1500'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CourseSessionAttendanceCourse',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('location', models.CharField(blank=True, default='', max_length=255)),
|
||||
('trainer', models.CharField(blank=True, default='', max_length=255)),
|
||||
('course_session', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.coursesession')),
|
||||
('due_date', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='attendance_course_due_date', to='duedate.duedate')),
|
||||
('learning_content', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='learnpath.learningcontentattendancecourse')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class CourseSessionAttendanceCourse(models.Model):
|
||||
course_session = models.ForeignKey(
|
||||
"course.CourseSession",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
learning_content = models.ForeignKey(
|
||||
"learnpath.LearningContentAttendanceCourse",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
due_date = models.OneToOneField(
|
||||
"duedate.DueDate",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="attendance_course_due_date",
|
||||
)
|
||||
|
||||
location = models.CharField(max_length=255, blank=True, default="")
|
||||
trainer = models.CharField(max_length=255, blank=True, default="")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.course_session} - {self.learning_content}"
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
|
||||
|
||||
class CourseSessionAttendanceCourseSerializer(serializers.ModelSerializer):
|
||||
start = serializers.SerializerMethodField()
|
||||
end = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = CourseSessionAttendanceCourse
|
||||
fields = [
|
||||
"id",
|
||||
"course_session",
|
||||
"learning_content",
|
||||
"due_date",
|
||||
"location",
|
||||
"trainer",
|
||||
"start",
|
||||
"end",
|
||||
]
|
||||
|
||||
def get_start(self, obj):
|
||||
return obj.due_date.start
|
||||
|
||||
def get_end(self, obj):
|
||||
return obj.due_date.end
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
|
@ -5,6 +5,8 @@ from openpyxl.reader.excel import load_workbook
|
|||
|
||||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.course.models import Course, CourseSession, CourseSessionUser
|
||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
from vbv_lernwelt.duedate.models import DueDate
|
||||
from vbv_lernwelt.importer.utils import (
|
||||
calc_header_tuple_list_from_pyxl_sheet,
|
||||
parse_circle_group_string,
|
||||
|
|
@ -109,42 +111,40 @@ def create_or_update_course_session(
|
|||
|
||||
cs.save()
|
||||
for circle in circles:
|
||||
attendance_course_lp_qs = None
|
||||
if language == "de":
|
||||
attendance_course_lp_qs = LearningContentAttendanceCourse.objects.filter(
|
||||
slug=f"{course.slug}-lp-circle-{circle.lower()}-lc-präsenzkurs-{circle.lower()}"
|
||||
)
|
||||
add_attendance_course_date(cs, attendance_course_lp_qs, circle, data)
|
||||
|
||||
elif language == "fr":
|
||||
# todo: this is a hack remove me
|
||||
attendance_course_lp_qs = LearningContentAttendanceCourse.objects.filter(
|
||||
slug=f"{course.slug}-lp-circle-véhicule-lc-cours-de-présence-véhicule-à-moteur"
|
||||
)
|
||||
add_attendance_course_date(cs, attendance_course_lp_qs, circle, data)
|
||||
elif language == "it":
|
||||
# todo: this is a hack remove me
|
||||
attendance_course_lp_qs = LearningContentAttendanceCourse.objects.filter(
|
||||
slug=f"{course.slug}-lp-circle-veicolo-lc-corso-di-presenza-veicolo"
|
||||
)
|
||||
print(attendance_course_lp_qs)
|
||||
add_attendance_course_date(cs, attendance_course_lp_qs, circle, data)
|
||||
|
||||
if attendance_course_lp_qs and attendance_course_lp_qs.exists():
|
||||
CourseSessionAttendanceCourse.objects.create(
|
||||
course_session=cs,
|
||||
learning_content=attendance_course_lp_qs.first(),
|
||||
due_date=DueDate.objects.create(
|
||||
course_session=cs,
|
||||
start=try_parse_datetime(data[f"{circle} Start"])[1],
|
||||
end=try_parse_datetime(data[f"{circle} Ende"])[1],
|
||||
page=attendance_course_lp_qs.first(),
|
||||
),
|
||||
location=data[f"{circle} Raum"],
|
||||
trainer="",
|
||||
)
|
||||
|
||||
return cs
|
||||
|
||||
|
||||
def add_attendance_course_date(course_session, attendance_course_lp_qs, circle, data):
|
||||
if attendance_course_lp_qs.exists():
|
||||
course_session.attendance_courses.append(
|
||||
{
|
||||
"learningContentId": attendance_course_lp_qs.first().id,
|
||||
"start": try_parse_datetime(data[f"{circle} Start"])[1].isoformat(),
|
||||
"end": try_parse_datetime(data[f"{circle} Ende"])[1].isoformat(),
|
||||
"location": data[f"{circle} Raum"],
|
||||
"trainer": "",
|
||||
}
|
||||
)
|
||||
course_session.save()
|
||||
|
||||
|
||||
def import_trainers_from_excel(course: Course, filename: str, language="de"):
|
||||
workbook = load_workbook(filename=filename)
|
||||
sheet = workbook["Schulungen Trainer"]
|
||||
|
|
@ -157,6 +157,7 @@ def import_trainers_from_excel(course: Course, filename: str, language="de"):
|
|||
def create_or_update_trainer(course: Course, data: Dict[str, Any], language="de"):
|
||||
logger.debug(
|
||||
"create_or_update_trainer",
|
||||
course=course.title,
|
||||
data=data,
|
||||
label="import",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from openpyxl.reader.excel import load_workbook
|
|||
|
||||
from vbv_lernwelt.course.creators.test_course import create_test_course
|
||||
from vbv_lernwelt.course.models import CourseSession
|
||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
from vbv_lernwelt.importer.services import create_or_update_course_session
|
||||
from vbv_lernwelt.importer.utils import calc_header_tuple_list_from_pyxl_sheet
|
||||
|
||||
|
|
@ -61,20 +62,12 @@ class CreateOrUpdateCourseSessionTestCase(TestCase):
|
|||
self.assertEqual(cs.region, "Deutschschweiz")
|
||||
self.assertEqual(cs.group, "A")
|
||||
|
||||
attendance_course = cs.attendance_courses[0]
|
||||
attendance_course = {
|
||||
k: v
|
||||
for k, v in attendance_course.items()
|
||||
if k not in ["learningContentId", "location"]
|
||||
}
|
||||
|
||||
self.assertDictEqual(
|
||||
attendance_course,
|
||||
{
|
||||
"start": "2023-06-06T13:30:00",
|
||||
"end": "2023-06-06T15:00:00",
|
||||
"trainer": "",
|
||||
},
|
||||
attendance_course = CourseSessionAttendanceCourse.objects.first()
|
||||
self.assertEqual(
|
||||
attendance_course.due_date.start.isoformat(), "2023-06-06T11:30:00+00:00"
|
||||
)
|
||||
self.assertEqual(
|
||||
attendance_course.due_date.end.isoformat(), "2023-06-06T13:00:00+00:00"
|
||||
)
|
||||
|
||||
def test_update_course_session(self):
|
||||
|
|
@ -112,18 +105,10 @@ class CreateOrUpdateCourseSessionTestCase(TestCase):
|
|||
self.assertEqual(cs.region, "Deutschschweiz")
|
||||
self.assertEqual(cs.group, "A")
|
||||
|
||||
attendance_course = cs.attendance_courses[0]
|
||||
attendance_course = {
|
||||
k: v
|
||||
for k, v in attendance_course.items()
|
||||
if k not in ["learningContentId", "location"]
|
||||
}
|
||||
|
||||
self.assertDictEqual(
|
||||
attendance_course,
|
||||
{
|
||||
"start": "2023-06-06T13:30:00",
|
||||
"end": "2023-06-06T15:00:00",
|
||||
"trainer": "",
|
||||
},
|
||||
attendance_course = CourseSessionAttendanceCourse.objects.first()
|
||||
self.assertEqual(
|
||||
attendance_course.due_date.start.isoformat(), "2023-06-06T11:30:00+00:00"
|
||||
)
|
||||
self.assertEqual(
|
||||
attendance_course.due_date.end.isoformat(), "2023-06-06T13:00:00+00:00"
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue