Merged in feature/update-importer (pull request #188)

Feature/update importer
This commit is contained in:
Christian Cueni 2023-08-17 09:18:22 +00:00
commit 45a70f6b75
11 changed files with 112 additions and 10 deletions

View File

@ -269,7 +269,7 @@
"selfEvaluationNo": "@:selfEvaluation: Muss ich nochmals anschauen.", "selfEvaluationNo": "@:selfEvaluation: Muss ich nochmals anschauen.",
"selfEvaluationYes": "@:selfEvaluation: Ich kann das.", "selfEvaluationYes": "@:selfEvaluation: Ich kann das.",
"steps": "Schritt {{current}} von {{max}}", "steps": "Schritt {{current}} von {{max}}",
"title": "@:selfEvaluation.selfEvaluation {{title}}", "title": "Selbsteinschätzung {{title}}",
"yes": "Ja, ich kann das" "yes": "Ja, ich kann das"
}, },
"settings": { "settings": {

View File

@ -91,7 +91,9 @@ const getNextStepLink = (courseSession: CourseSession) => {
<br /> <br />
{{ $t("uk.contact.address") }} {{ $t("uk.contact.address") }}
<br /> <br />
<a href="mailto:uek-support@vbv-afa.ch">uk.contact.email</a> <a class="link" href="mailto:uek-support@vbv-afa.ch">
uek-support@vbv-afa.ch
</a>
</p> </p>
</address> </address>
</div> </div>

View File

@ -37,7 +37,11 @@ from vbv_lernwelt.course.views import (
request_course_completion, request_course_completion,
request_course_completion_for_user, request_course_completion_for_user,
) )
from vbv_lernwelt.edoniq_test.views import export_students, export_trainers from vbv_lernwelt.edoniq_test.views import (
export_students,
export_students_and_trainers,
export_trainers,
)
from vbv_lernwelt.feedback.views import ( from vbv_lernwelt.feedback.views import (
get_expert_feedbacks_for_course, get_expert_feedbacks_for_course,
get_feedback_for_circle, get_feedback_for_circle,
@ -148,6 +152,8 @@ urlpatterns = [
# edoniq test # edoniq test
path(r'api/core/edoniq-test/export-users/', export_students, name='edoniq_export_students'), path(r'api/core/edoniq-test/export-users/', export_students, name='edoniq_export_students'),
path(r'api/core/edoniq-test/export-trainers/', export_trainers, name='edoniq_export_trainers'), path(r'api/core/edoniq-test/export-trainers/', export_trainers, name='edoniq_export_trainers'),
path(r'api/core/edoniq-test/export-users-trainers/', export_students_and_trainers,
name='edoniq_export_students_and_trainers'),
# importer # importer
path( path(

View File

@ -6,7 +6,9 @@ from vbv_lernwelt.core.admin import User
from vbv_lernwelt.core.create_default_users import create_default_users from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.course.consts import COURSE_TEST_ID from vbv_lernwelt.course.consts import COURSE_TEST_ID
from vbv_lernwelt.course.creators.test_course import create_test_course from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.edoniq_test.views import ( from vbv_lernwelt.edoniq_test.views import (
fetch_course_session_all_users,
fetch_course_session_users, fetch_course_session_users,
generate_export_response, generate_export_response,
) )
@ -36,6 +38,37 @@ class EdoniqUserExportTestCase(TestCase):
users = fetch_course_session_users([COURSE_TEST_ID]) users = fetch_course_session_users([COURSE_TEST_ID])
self.assertEqual(len(users), 2) self.assertEqual(len(users), 2)
def test_fetch_course_session_trainers(self):
users = fetch_course_session_users(
[COURSE_TEST_ID], role=CourseSessionUser.Role.EXPERT
)
self.assertEqual(len(users), 1)
def test_remove_eiger_versicherungen(self):
user1 = User.objects.get(email="test-student1@example.com")
user1.email = "some@eiger-versicherungen.ch"
user1.save()
users = fetch_course_session_users([COURSE_TEST_ID])
self.assertEqual(len(users), 1)
def test_export_students_and_trainers(self):
users = fetch_course_session_all_users([COURSE_TEST_ID])
self.assertEqual(len(users), 3)
def test_deduplicates_users(self):
trainer1 = User.objects.get(email="test-trainer1@example.com")
cs_zrh = CourseSession.objects.get(
title="Test Zürich 2022 a",
)
_csu = CourseSessionUser.objects.create(
course_session=cs_zrh,
user=trainer1,
)
users = fetch_course_session_all_users([COURSE_TEST_ID])
for u in users:
print(u.edoniq_role, u.email)
self.assertEqual(len(users), 3)
def test_response_csv(self): def test_response_csv(self):
users = fetch_course_session_users([COURSE_TEST_ID]) users = fetch_course_session_users([COURSE_TEST_ID])
response = generate_export_response(users) response = generate_export_response(users)

View File

@ -1,8 +1,10 @@
import csv import csv
from datetime import date from datetime import date
from itertools import chain
from typing import List from typing import List
from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.views.decorators import staff_member_required
from django.db.models import CharField, Value
from django.http import HttpResponse from django.http import HttpResponse
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User
@ -18,26 +20,53 @@ def export_students(request):
return generate_export_response(course_session_users) return generate_export_response(course_session_users)
@staff_member_required
def export_trainers(request): def export_trainers(request):
course_session_users = fetch_course_session_users( course_session_users = fetch_course_session_users(
UK_COURSE_IDS, role=CourseSessionUser.Role.EXPERT UK_COURSE_IDS, role=CourseSessionUser.Role.EXPERT
) )
return generate_export_response(course_session_users, role="Trainer") return generate_export_response(course_session_users)
@staff_member_required
def export_students_and_trainers(request):
course_session_users = fetch_course_session_all_users(UK_COURSE_IDS)
return generate_export_response(course_session_users)
def fetch_course_session_users(courses: List[int], role=CourseSessionUser.Role.MEMBER): def fetch_course_session_users(courses: List[int], role=CourseSessionUser.Role.MEMBER):
if role == CourseSessionUser.Role.EXPERT:
edoniq_role = "Trainer"
else:
edoniq_role = "Lernende"
# if users should be exported per course session, remove the distinct() call # if users should be exported per course session, remove the distinct() call
return ( return (
User.objects.filter( User.objects.filter(
coursesessionuser__course_session__course__id__in=courses, coursesessionuser__course_session__course__id__in=courses,
coursesessionuser__role=role, coursesessionuser__role=role,
) )
.exclude(email__contains="eiger-versicherungen.ch") # exclude test users
.exclude(email__contains="assurance.ch")
.order_by("email") .order_by("email")
.annotate(edoniq_role=Value(edoniq_role, output_field=CharField()))
.distinct() .distinct()
) )
def generate_export_response(cs_users: List[User], role="Lernende") -> HttpResponse: def fetch_course_session_all_users(courses: List[int]):
course_session_users = fetch_course_session_users(courses)
course_session_trainers = fetch_course_session_users(
courses, role=CourseSessionUser.Role.EXPERT
)
combined_queryset = chain(course_session_users, course_session_trainers)
# use email as key to remove duplicates. Maybe we can use the sso id in the future, but it is not set for all users
unique_dict = {obj.email: obj for obj in combined_queryset}
return list(unique_dict.values())
def generate_export_response(cs_users: List[User]) -> HttpResponse:
response = HttpResponse(content_type="text/csv") response = HttpResponse(content_type="text/csv")
response[ response[
"Content-Disposition" "Content-Disposition"
@ -71,7 +100,7 @@ def generate_export_response(cs_users: List[User], role="Lernende") -> HttpRespo
cs_user.language, cs_user.language,
cs_user.email, cs_user.email,
cs_user.additional_json_data.get("Geburtsdatum", ""), cs_user.additional_json_data.get("Geburtsdatum", ""),
role, cs_user.edoniq_role,
cs_user.additional_json_data.get("Firmenname", ""), cs_user.additional_json_data.get("Firmenname", ""),
cs_user.additional_json_data.get("Lehrvertragsnummer", ""), cs_user.additional_json_data.get("Lehrvertragsnummer", ""),
cs_user.coursesessionuser_set.first().course_session.import_id, cs_user.coursesessionuser_set.first().course_session.import_id,

View File

@ -185,6 +185,7 @@ def create_or_update_user(
last_name: str = "", last_name: str = "",
sso_id: str = None, sso_id: str = None,
contract_number: str = "", contract_number: str = "",
date_of_birth: str = "",
): ):
logger.debug( logger.debug(
"create_or_update_user", "create_or_update_user",
@ -200,9 +201,13 @@ def create_or_update_user(
if user_qs.exists(): if user_qs.exists():
user = user_qs.first() user = user_qs.first()
# use the ID from DBPLAP2 (Lehrvertragsnummer, firstname, lastname, date of birth)
if not user and contract_number: if not user and contract_number:
user_qs = User.objects.filter( user_qs = User.objects.filter(
additional_json_data__Lehrvertragsnummer=contract_number first_name=first_name,
last_name=last_name,
additional_json_data__Lehrvertragsnummer=contract_number,
additional_json_data__Geburtsdatum=date_of_birth,
) )
if user_qs.exists(): if user_qs.exists():
user = user_qs.first() user = user_qs.first()
@ -502,6 +507,8 @@ def import_students_from_excel(filename: str):
"Name", "Name",
"Sprache", "Sprache",
"Durchführungen", "Durchführungen",
"Lehrvertragsnummer",
"Geburtsdatum",
], ],
) )
create_or_update_student(data) create_or_update_student(data)
@ -514,11 +521,14 @@ def create_or_update_student(data: Dict[str, Any]):
label="import", label="import",
) )
date_of_birth = _get_date_of_birth(data)
user = create_or_update_user( user = create_or_update_user(
email=data["Email"].lower(), email=data["Email"].lower(),
first_name=data["Vorname"], first_name=data["Vorname"],
last_name=data["Name"], last_name=data["Name"],
contract_number=data.get("Lehrvertragsnummer", ""), contract_number=data.get("Lehrvertragsnummer", ""),
date_of_birth=date_of_birth,
) )
user.language = data["Sprache"] user.language = data["Sprache"]
@ -535,6 +545,16 @@ def create_or_update_student(data: Dict[str, Any]):
csu.save() csu.save()
def _get_date_of_birth(data: Dict[str, Any]) -> str:
date_of_birth = data.get("Geburtsdatum", None)
if date_of_birth is None:
return ""
elif date_of_birth is date or date_of_birth is datetime:
return date_of_birth.strftime("%d.%m.%Y")
elif type(date_of_birth) is str:
return date_of_birth
def sync_students_from_t2l_excel(filename: str): def sync_students_from_t2l_excel(filename: str):
workbook = load_workbook(filename=filename) workbook = load_workbook(filename=filename)
sheet = workbook.active sheet = workbook.active
@ -546,10 +566,13 @@ def sync_students_from_t2l_excel(filename: str):
def sync_students_from_t2l(data): def sync_students_from_t2l(data):
# ignore errors date_of_birth = _get_date_of_birth(data)
try: try:
user = User.objects.get( user = User.objects.get(
additional_json_data__Lehrvertragsnummer=data["Lehrvertragsnummer"] first_name=data["Vorname"],
last_name=data["Name"],
additional_json_data__Lehrvertragsnummer=data["Lehrvertragsnummer"],
additional_json_data__Geburtsdatum=date_of_birth,
) )
except User.DoesNotExist: except User.DoesNotExist:
return return

View File

@ -51,6 +51,7 @@ class CreateOrUpdateStudentTestCase(TestCase):
"Durchführungen": "DE 2023 A", "Durchführungen": "DE 2023 A",
"Lehrvertragsnummer": "1234", "Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43", "Tel. Privat": "079 593 83 43",
"Geburtsdatum": "01.01.2000",
} }
def test_create_student(self): def test_create_student(self):

View File

@ -32,6 +32,7 @@ class SyncT2lTestCase(TestCase):
"Durchführungen": "DE 2023 A", "Durchführungen": "DE 2023 A",
"Lehrvertragsnummer": "1234", "Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43", "Tel. Privat": "079 593 83 43",
"Geburtsdatum": "01.01.2000",
} }
create_or_update_student(self.user_dict) create_or_update_student(self.user_dict)
@ -44,6 +45,7 @@ class SyncT2lTestCase(TestCase):
"Durchführungen": "DE 2023 A", "Durchführungen": "DE 2023 A",
"Lehrvertragsnummer": "1234", "Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 65", "Tel. Privat": "079 593 83 65",
"Geburtsdatum": "01.01.2000",
} }
sync_students_from_t2l(user_dict) sync_students_from_t2l(user_dict)
@ -65,6 +67,7 @@ class SyncT2lTestCase(TestCase):
"Lehrvertragsnummer": "1234", "Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43", "Tel. Privat": "079 593 83 43",
"Firma": "VBV", "Firma": "VBV",
"Geburtsdatum": "01.01.2000",
} }
sync_students_from_t2l(user_dict) sync_students_from_t2l(user_dict)
@ -84,6 +87,7 @@ class SyncT2lTestCase(TestCase):
"Durchführungen": "DE 2023 B", "Durchführungen": "DE 2023 B",
"Lehrvertragsnummer": "1234", "Lehrvertragsnummer": "1234",
"Tel. Privat": "079 593 83 43", "Tel. Privat": "079 593 83 43",
"Geburtsdatum": "01.01.2000",
} }
sync_students_from_t2l(user_dict) sync_students_from_t2l(user_dict)

View File

@ -31,9 +31,13 @@
<h2>Export Edoniq Teilnehmer</h2> <h2>Export Edoniq Teilnehmer</h2>
<a href="{% url 'edoniq_export_students' %}" class="btn btn-primary">Teilnehmer exportieren</a> <a href="{% url 'edoniq_export_students' %}" class="btn btn-primary">Teilnehmer exportieren</a>
<h2>Export Edoniq Trainer</h2> <h2>Export Edoniq Trainer</h2>
<a href="{% url 'edoniq_export_trainers' %}" class="btn btn-primary">Trainer exportieren</a> <a href="{% url 'edoniq_export_trainers' %}" class="btn btn-primary">Trainer exportieren</a>
<h2>Export Edoniq Teilnehmer und Trainer</h2>
<a href="{% url 'edoniq_export_students_and_trainers' %}" class="btn btn-primary">Teilnehmer und Trainer exportieren</a>
<h1>Reset</h1> <h1>Reset</h1>
<form action="/api/core/cypressreset/" method="post"> <form action="/api/core/cypressreset/" method="post">
{% csrf_token %} {% csrf_token %}