This commit is contained in:
Christian Cueni 2023-07-20 15:19:46 +02:00
parent 12977b01cc
commit 5d0f7b88b5
6 changed files with 264 additions and 6 deletions

View File

@ -45,6 +45,7 @@ from vbv_lernwelt.feedback.views import (
from vbv_lernwelt.importer.views import (
coursesessions_students_import,
coursesessions_trainers_import,
t2l_sync,
)
from vbv_lernwelt.notify.views import email_notification_settings
from wagtail import urls as wagtail_urls
@ -158,6 +159,11 @@ urlpatterns = [
coursesessions_students_import,
name="coursesessions_students_import",
),
path(
r"server/importer/t2l-sync/",
t2l_sync,
name="t2l_sync",
),
# testing and debug
path('server/raise_error/',

View File

@ -1,3 +1,4 @@
from datetime import date, datetime, time
from typing import Any, Dict, List
import structlog
@ -24,6 +25,8 @@ CIRCLE_NAMES = {
"Haushalt Teil 2": {"de": "Haushalt Teil 2", "fr": "Haushalt Teil 2", "it": ""},
}
T2L_IGNORE_FIELDS = ["Vorname", "Name", "Email", "Sprache", "Durchführungen"]
class DataImportError(Exception):
pass
@ -322,7 +325,7 @@ def create_or_update_student(data: Dict[str, Any]):
)
user.language = data["Sprache"]
user.additional_json_data = user.additional_json_data | data
update_user_json_data(user, data)
user.save()
# general expert handling
@ -333,3 +336,56 @@ def create_or_update_student(data: Dict[str, Any]):
course_session_id=course_session.id, user_id=user.id
)
csu.save()
def sync_students_from_t2l_excel(filename: str):
workbook = load_workbook(filename=filename)
sheet = workbook.active
tuple_list = calc_header_tuple_list_from_pyxl_sheet(sheet)
for row in tuple_list:
data = dict(row)
sync_students_from_t2l(data | {})
def sync_students_from_t2l(data):
# ignore errors
try:
user = User.objects.get(
additional_json_data__Lehrvertragsnummer=data["Lehrvertragsnummer"]
)
except User.DoesNotExist:
return
# only sync data that is not in our user model
for field in T2L_IGNORE_FIELDS:
try:
del data[field]
except KeyError:
pass
update_user_json_data(user, data)
user.save()
def update_user_json_data(user: User, data: Dict[str, Any]):
user.additional_json_data = user.additional_json_data | sanitize_json_data_input(
data
)
def sanitize_json_data_input(data: Dict[str, Any]) -> Dict[str, Any]:
"""
Saving additional_json_data fails if the data contains datetime objects.
This is a quick and dirty fix to convert datetime objects to iso strings.
"""
for key, value in data.items():
if isinstance(value, datetime):
data[key] = value.isoformat()
elif isinstance(value, date):
data[key] = value.isoformat()
elif isinstance(value, time):
data[key] = value.isoformat()
else:
data[key] = value
return data

View File

@ -86,7 +86,9 @@ class CreateOrUpdateStudentTestCase(TestCase):
self.assertEqual(
CourseSessionUser.objects.filter(
user__additional_json_data__Lehrvertragsnummer=self.user_dict["Lehrvertragsnummer"]
user__additional_json_data__Lehrvertragsnummer=self.user_dict[
"Lehrvertragsnummer"
]
).count(),
1,
)

View File

@ -0,0 +1,178 @@
import os
from datetime import date, datetime, time
from django.test import TestCase
from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.importer.services import (
create_or_update_student,
sanitize_json_data_input,
sync_students_from_t2l,
)
test_dir = os.path.dirname(os.path.abspath(__file__))
class SyncT2lTestCase(TestCase):
def setUp(self):
self.course = create_test_course(include_vv=False)
self.course_session_a = CourseSession.objects.create(
course=self.course,
title="Deutschschweiz 2023 A",
import_id="DE 2023 A",
group="A",
)
self.user_dict = {
"Name": "Rascher",
"Vorname": "Barbara",
"Email": "barbara.rascher@vbv-afa.ch",
"Sprache": "de",
"Durchführungen": "DE 2023 A",
"Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43",
}
create_or_update_student(self.user_dict)
def test_updates_field(self):
user_dict = {
"Name": "Rascher",
"Vorname": "Barbara",
"Email": "barbara.rascher@vbv-afa.ch",
"Sprache": "de",
"Durchführungen": "DE 2023 A",
"Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 65",
}
sync_students_from_t2l(user_dict)
updated_user = CourseSessionUser.objects.get(
user__email=self.user_dict["Email"]
)
self.assertEqual(
updated_user.user.additional_json_data["Tel. Privat"],
user_dict["Tel. Privat"],
)
def test_adds_field(self):
user_dict = {
"Name": "Rascher",
"Vorname": "Barbara",
"Email": "barbara.rascher@vbv-afa.ch",
"Sprache": "de",
"Durchführungen": "DE 2023 A",
"Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43",
"Firma": "VBV",
}
sync_students_from_t2l(user_dict)
updated_user = CourseSessionUser.objects.get(
user__email=self.user_dict["Email"]
)
self.assertEqual(
updated_user.user.additional_json_data["Firma"], user_dict["Firma"]
)
def test_ignors_defined_field(self):
user_dict = {
"Name": "Rascher2",
"Vorname": "Barbara2",
"Email": "barbara.rascher2@vbv-afa.ch",
"Sprache": "fr",
"Durchführungen": "DE 2023 B",
"Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43",
}
sync_students_from_t2l(user_dict)
updated_user = CourseSessionUser.objects.get(
user__email=self.user_dict["Email"]
)
self.assertEqual(
updated_user.user.additional_json_data["Name"], self.user_dict["Name"]
)
self.assertEqual(
updated_user.user.additional_json_data["Vorname"], self.user_dict["Vorname"]
)
self.assertEqual(
updated_user.user.additional_json_data["Durchführungen"],
self.user_dict["Durchführungen"],
)
self.assertEqual(
updated_user.user.additional_json_data["Sprache"], self.user_dict["Sprache"]
)
def test_ignors_missing_defined_field(self):
user_dict = {
"Name": "Rascher2",
"Vorname": "Barbara2",
"Email": "barbara.rascher2@vbv-afa.ch",
"Sprache": "fr",
"Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43",
}
sync_students_from_t2l(user_dict)
updated_user = CourseSessionUser.objects.get(
user__email=self.user_dict["Email"]
)
self.assertEqual(
updated_user.user.additional_json_data["Name"], self.user_dict["Name"]
)
self.assertEqual(
updated_user.user.additional_json_data["Vorname"], self.user_dict["Vorname"]
)
self.assertEqual(
updated_user.user.additional_json_data["Sprache"], self.user_dict["Sprache"]
)
def test_ignors_wrong_contract_nummer(self):
user_dict = {
"Name": "Rascher2",
"Vorname": "Barbara2",
"Email": "barbara.rascher2@vbv-afa.ch",
"Sprache": "fr",
"Lehrvertragsnummer": "12345",
"Tel. Privat": "079 593 83 43",
}
try:
sync_students_from_t2l(user_dict)
updated_user = CourseSessionUser.objects.get(
user__email=self.user_dict["Email"]
)
except Exception as e:
self.fail(
f"SyncT2lTestCase.test_ignors_wrong_contract_number: An exception was unexpectedly raised: {str(e)}"
)
class SanitizerTestCase(TestCase):
def test_date(self):
a_date = date(2021, 1, 1)
user_dict = {"Name": "Rascher", "Datum": a_date}
expected_sanitized_data = {"Name": "Rascher", "Datum": a_date.isoformat()}
sanitized_data = sanitize_json_data_input(user_dict)
self.assertEqual(sanitized_data, expected_sanitized_data)
def test_datetime(self):
a_date = datetime(2021, 1, 1)
user_dict = {"Name": "Rascher", "Datum": a_date}
expected_sanitized_data = {"Name": "Rascher", "Datum": a_date.isoformat()}
sanitized_data = sanitize_json_data_input(user_dict)
self.assertEqual(sanitized_data, expected_sanitized_data)
def test_time(self):
a_date = time(23, 59, 59)
user_dict = {"Name": "Rascher", "Datum": a_date}
expected_sanitized_data = {"Name": "Rascher", "Datum": a_date.isoformat()}
sanitized_data = sanitize_json_data_input(user_dict)
self.assertEqual(sanitized_data, expected_sanitized_data)

View File

@ -8,6 +8,7 @@ from vbv_lernwelt.importer.services import (
import_course_sessions_from_excel,
import_students_from_excel,
import_trainers_from_excel_for_training,
sync_students_from_t2l_excel,
)
@ -36,6 +37,15 @@ def coursesessions_students_import(request):
)
@staff_member_required
def t2l_sync(request):
return handle_import(
request,
"Die Daten wurden erflogreich synchronisiert!",
sync_students_from_t2l_excel,
)
def handle_import(request, success_msg: str, importer: Callable[[str], None]):
if request.method == "POST" and request.FILES["excel_file"]:
excel_file = request.FILES["excel_file"]

View File

@ -5,7 +5,7 @@
{% include "admin/app_list.html" with app_list=app_list show_changelinks=True %}
<div class="content">
<h1>Export üK</h1>
<h1>üK</h1>
<h1>Excel Import üK</h1>
<h2>Durchführungen und Trainer</h2>
<form method="post" enctype="multipart/form-data" action="/server/importer/coursesession-trainer-import/">
@ -21,11 +21,17 @@
<input type="submit" value="Teilnehmer importieren">
</form>
<h2>Edoniq Teilnehmer</h2>
<h2>Sync mit T2L Daten</h2>
<form method="post" enctype="multipart/form-data" action="/server/importer/t2l-sync/">
{% csrf_token %}
<input type="file" name="excel_file" accept=".xlsx, .xls">
<input type="submit" value="Teilnehmer mit T2L-Daten Synchronisiern">
</form>
<h2>Export Edoniq Teilnehmer</h2>
<a href="{% url 'edoniq_export_students' %}" class="btn btn-primary">Teilnehmer exportieren</a>
<h2>Reset</h2>
<h1>Reset</h1>
<form action="/api/core/cypressreset/" method="post">
{% csrf_token %}
<button class="btn" name="">Testdaten zurück setzen</button>