Reformat code with ruff

This commit is contained in:
Daniel Egger 2024-08-22 13:33:46 +02:00
parent 889922725a
commit d5e6b623d3
87 changed files with 588 additions and 551 deletions

View File

@ -10,4 +10,6 @@ echo 'format client code'
npm run prettier npm run prettier
echo 'format python code' echo 'format python code'
ufmt format server ruff check server --fix
ruff format server

View File

@ -9,8 +9,11 @@ echo 'prettier:check'
echo 'lint and typecheck' echo 'lint and typecheck'
(cd client && npm run lint:errors && npm run typecheck) (cd client && npm run lint:errors && npm run typecheck)
echo 'python ufmt check' echo 'ruff check'
ufmt check server ruff check server
echo 'ruff format --check'
ruff format server --check
echo 'check git-crypt files diff' echo 'check git-crypt files diff'
git-crypt status -e | sort > git-crypt-encrypted-files-check.txt && diff git-crypt-encrypted-files.txt git-crypt-encrypted-files-check.txt git-crypt status -e | sort > git-crypt-encrypted-files-check.txt && diff git-crypt-encrypted-files.txt git-crypt-encrypted-files-check.txt

View File

@ -1,4 +1,5 @@
# pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position # pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position
# ruff: noqa
import os import os
from dotenv import dotenv_values from dotenv import dotenv_values

View File

@ -1,7 +1,6 @@
# pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position # pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position
import os import os
os.environ["IT_APP_ENVIRONMENT"] = "local" os.environ["IT_APP_ENVIRONMENT"] = "local"
os.environ["AWS_S3_SECRET_ACCESS_KEY"] = os.environ.get( os.environ["AWS_S3_SECRET_ACCESS_KEY"] = os.environ.get(
"AWS_S3_SECRET_ACCESS_KEY", "AWS_S3_SECRET_ACCESS_KEY",

View File

@ -12,7 +12,7 @@ from .base import * # noqa
# GENERAL # GENERAL
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
DATABASES["default"]["NAME"] = "vbv_lernwelt_cypress" DATABASES["default"]["NAME"] = "vbv_lernwelt_cypress" # noqa F405
DATATRANS_API_ENDPOINT = "http://localhost:8001/server/fakeapi/datatrans/api" DATATRANS_API_ENDPOINT = "http://localhost:8001/server/fakeapi/datatrans/api"
DATATRANS_PAY_URL = "http://localhost:8001/server/fakeapi/datatrans/pay" DATATRANS_PAY_URL = "http://localhost:8001/server/fakeapi/datatrans/pay"
@ -26,7 +26,7 @@ CYPRESS_TEST = True
# Your stuff... # Your stuff...
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = { REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = { # noqa F405
"anon": "10000/day", "anon": "10000/day",
"hour-throttle": "40000/hour", "hour-throttle": "40000/hour",
"day-throttle": "2000000/day", "day-throttle": "2000000/day",

View File

@ -11,6 +11,9 @@ from django.views import defaults as default_views
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django_ratelimit.exceptions import Ratelimited from django_ratelimit.exceptions import Ratelimited
from graphene_django.views import GraphQLView from graphene_django.views import GraphQLView
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as media_library_urls
from vbv_lernwelt.api.directory import list_entities from vbv_lernwelt.api.directory import list_entities
from vbv_lernwelt.api.user import get_profile, me_user_view, post_avatar from vbv_lernwelt.api.user import get_profile, me_user_view, post_avatar
@ -74,9 +77,6 @@ from vbv_lernwelt.shop.datatrans.datatrans_fake_server import (
fake_datatrans_api_view, fake_datatrans_api_view,
fake_datatrans_pay_view, fake_datatrans_pay_view,
) )
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as media_library_urls
class SignedIntConverter(IntConverter): class SignedIntConverter(IntConverter):
@ -99,7 +99,7 @@ def raise_example_error(request):
""" """
raise Exception("Test Error: I know python!") raise Exception("Test Error: I know python!")
# pylint: disable=unreachable # pylint: disable=unreachable
return HttpResponse("no error?") return HttpResponse("no error?") # noqa F821
# fmt: off # fmt: off
@ -241,7 +241,7 @@ urlpatterns = [
# testing and debug # testing and debug
path('server/raise_error/', path('server/raise_error/',
user_passes_test(lambda u: u.is_superuser, login_url='/login/')( user_passes_test(lambda u: u.is_superuser, login_url='/login/')(
raise_example_error), ), raise_example_error) ),
path("server/checkratelimit/", check_rate_limit), path("server/checkratelimit/", check_rate_limit),
] ]

View File

@ -1,4 +1,4 @@
from django.test import override_settings, TestCase from django.test import TestCase, override_settings
class RateLimitTest(TestCase): class RateLimitTest(TestCase):

View File

@ -15,7 +15,7 @@ if __name__ == "__main__":
try: try:
import django # noqa import django # noqa
except ImportError: except ImportError:
raise ImportError( raise ImportError( # noqa
"Couldn't import Django. Are you sure it's installed and " "Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you " "available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?" "forget to activate a virtual environment?"

16
server/ruff.toml Normal file
View File

@ -0,0 +1,16 @@
[lint]
select = [
"E", "F", "B", "I", "COM818", "ISC002"
# "PL",
# "DJ", "RUF",
]
ignore = [
"E501", # line too long
"F841", # local variable assigned but never used
"B007", # loop control variable
]
unfixable = ["B"]
[format]
quote-style = "double"

View File

@ -1,3 +1,7 @@
from wagtail.blocks import StreamValue
from wagtail.blocks.list_block import ListBlock, ListValue
from wagtail.rich_text import RichText
from vbv_lernwelt.assignment.models import ( from vbv_lernwelt.assignment.models import (
AssignmentListPage, AssignmentListPage,
AssignmentType, AssignmentType,
@ -21,9 +25,6 @@ from vbv_lernwelt.course.consts import (
) )
from vbv_lernwelt.course.models import CoursePage from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.media_files.models import ContentDocument from vbv_lernwelt.media_files.models import ContentDocument
from wagtail.blocks import StreamValue
from wagtail.blocks.list_block import ListBlock, ListValue
from wagtail.rich_text import RichText
def create_uk_fahrzeug_casework( def create_uk_fahrzeug_casework(

View File

@ -25,7 +25,6 @@ from vbv_lernwelt.course_session.services.export_attendance import (
make_export_filename, make_export_filename,
sanitize_sheet_name, sanitize_sheet_name,
) )
from vbv_lernwelt.duedate.models import DueDate
from vbv_lernwelt.learnpath.models import LearningContent from vbv_lernwelt.learnpath.models import LearningContent
logger = structlog.get_logger(__name__) logger = structlog.get_logger(__name__)
@ -137,9 +136,7 @@ def _create_sheet(
# common user headers, Circle <title> <learningcontenttitle> bestanden, Circle <title> <learningcontenttitle> Resultat, ... # common user headers, Circle <title> <learningcontenttitle> bestanden, Circle <title> <learningcontenttitle> Resultat, ...
col_idx = add_user_headers(sheet) col_idx = add_user_headers(sheet)
ordered_assignement_ids = ( ordered_assignement_ids = [] # keep track of the order of the columns when adding the rows
[]
) # keep track of the order of the columns when adding the rows
for cse in competence_certificate_element: for cse in competence_certificate_element:
circle = cse.learning_content.get_circle() circle = cse.learning_content.get_circle()

View File

@ -202,8 +202,8 @@ def update_assignment_completion(
if copy_task_data: if copy_task_data:
# copy over the question data, so that we don't lose the context # copy over the question data, so that we don't lose the context
sub_tasks = assignment.get_input_tasks() sub_tasks = assignment.get_input_tasks()
for key, value in ac.completion_data.items(): for key, _ in ac.completion_data.items():
task_data = find_first(sub_tasks, pred=lambda x: x["id"] == key) task_data = find_first(sub_tasks, pred=lambda x: x["id"] == key) # noqa
if task_data: if task_data:
ac.completion_data[key].update(task_data) ac.completion_data[key].update(task_data)
@ -235,8 +235,8 @@ def update_assignment_completion(
# copy over the question data, so that we don't lose the context # copy over the question data, so that we don't lose the context
subtasks = assignment.get_input_tasks() subtasks = assignment.get_input_tasks()
for key, value in acl.completion_data.items(): for key, _ in acl.completion_data.items():
task_data = find_first(subtasks, pred=lambda x: x["id"] == key) task_data = find_first(subtasks, pred=lambda x: x["id"] == key) # noqa
if task_data: if task_data:
acl.completion_data[key].update(task_data) acl.completion_data[key].update(task_data)
acl.save() acl.save()

View File

@ -222,7 +222,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
self.course_session, self.course_session,
) )
self.assertTrue( self.assertTrue(
f"/course/test-lehrgang/assignment-evaluation" in notification.target_url "/course/test-lehrgang/assignment-evaluation" in notification.target_url
) )
# second submit will fail # second submit will fail
@ -268,7 +268,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
), ),
) )
ac = AssignmentCompletion.objects.create( AssignmentCompletion.objects.create(
assignment_user=self.student, assignment_user=self.student,
assignment=self.assignment, assignment=self.assignment,
learning_content_page=self.assignment.find_attached_learning_content(), learning_content_page=self.assignment.find_attached_learning_content(),

View File

@ -230,7 +230,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
}, },
) )
with self.assertRaises(serializers.ValidationError) as error: with self.assertRaises(serializers.ValidationError):
update_assignment_completion( update_assignment_completion(
assignment_user=self.user, assignment_user=self.user,
assignment=self.assignment, assignment=self.assignment,
@ -403,7 +403,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
), ),
) )
ac = AssignmentCompletion.objects.create( AssignmentCompletion.objects.create(
assignment_user=self.user, assignment_user=self.user,
assignment=self.assignment, assignment=self.assignment,
course_session=self.course_session, course_session=self.course_session,
@ -471,7 +471,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
evaluation_user=self.trainer, evaluation_user=self.trainer,
) )
with self.assertRaises(serializers.ValidationError) as error: with self.assertRaises(serializers.ValidationError):
# not setting grade will raise an error # not setting grade will raise an error
update_assignment_completion( update_assignment_completion(
assignment_user=self.user, assignment_user=self.user,

View File

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here. # Register your models here.

View File

@ -40,7 +40,7 @@ class CompetenceCertificateQuery(object):
if not can_view_profile(info.context.user, course_session_user): if not can_view_profile(info.context.user, course_session_user):
return None return None
setattr(info.context, "assignment_user_ids", user_ids) setattr(info.context, "assignment_user_ids", user_ids) # noqa: B010
return resolve_course_page( return resolve_course_page(
CompetenceCertificateList, CompetenceCertificateList,

View File

@ -3,7 +3,6 @@ from django.utils.text import slugify
from wagtail import blocks from wagtail import blocks
from wagtail.admin.panels import FieldPanel from wagtail.admin.panels import FieldPanel
from wagtail.fields import StreamField from wagtail.fields import StreamField
from wagtail.models import Page
from vbv_lernwelt.core.model_utils import find_available_slug from vbv_lernwelt.core.model_utils import find_available_slug
from vbv_lernwelt.course.models import CourseBasePage from vbv_lernwelt.course.models import CourseBasePage
@ -106,7 +105,7 @@ class ActionCompetence(CourseBasePage):
) )
def get_frontend_url(self): def get_frontend_url(self):
return f"" return ""
content_panels = [ content_panels = [
FieldPanel("title"), FieldPanel("title"),

View File

@ -1,5 +1,6 @@
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.auth import admin as auth_admin, get_user_model from django.contrib.auth import admin as auth_admin
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from vbv_lernwelt.core.models import ( from vbv_lernwelt.core.models import (
@ -44,13 +45,13 @@ def create_or_sync_berufsbildner(modeladmin, request, queryset):
messages.add_message( messages.add_message(
request, request,
messages.SUCCESS, messages.SUCCESS,
f"Berufsbildner erfolgreich erstellt oder synchronisiert", "Berufsbildner erfolgreich erstellt oder synchronisiert",
) )
else: else:
messages.add_message( messages.add_message(
request, request,
messages.ERROR, messages.ERROR,
f"Einige Berufsbildner konnten nicht erstellt oder synchronisiert werden", "Einige Berufsbildner konnten nicht erstellt oder synchronisiert werden",
) )

View File

@ -4,12 +4,6 @@ from django.contrib.auth.models import Group, Permission
from django.core.files import File from django.core.files import File
from environs import Env from environs import Env
from vbv_lernwelt.core.model_utils import add_countries
from vbv_lernwelt.media_files.models import UserImage
env = Env()
env.read_env()
from vbv_lernwelt.core.constants import ( from vbv_lernwelt.core.constants import (
ADMIN_USER_ID, ADMIN_USER_ID,
TEST_BERUFSBILDNER1_USER_ID, TEST_BERUFSBILDNER1_USER_ID,
@ -25,7 +19,12 @@ from vbv_lernwelt.core.constants import (
TEST_USER_DATATRANS_HANNA_ID, TEST_USER_DATATRANS_HANNA_ID,
TEST_USER_EMPTY_ID, TEST_USER_EMPTY_ID,
) )
from vbv_lernwelt.core.model_utils import add_countries
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User
from vbv_lernwelt.media_files.models import UserImage
env = Env()
env.read_env()
VBV_STAFF_GROUP = "VBV Staff" VBV_STAFF_GROUP = "VBV Staff"
@ -432,7 +431,6 @@ def create_default_users(default_password="test", set_avatar=False):
def _get_or_create_user(user_model, *args, **kwargs): def _get_or_create_user(user_model, *args, **kwargs):
username = kwargs.get("username", None) username = kwargs.get("username", None)
password = kwargs.get("password", None)
language = kwargs.get("language", "de") language = kwargs.get("language", "de")
id = kwargs.get("id", None) id = kwargs.get("id", None)
created = False created = False

View File

@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
import djclick as click import djclick as click
from dateutil.relativedelta import relativedelta, TU from dateutil.relativedelta import TU, relativedelta
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.db import connection from django.db import connection
from django.utils import timezone from django.utils import timezone

View File

@ -23,7 +23,12 @@ from vbv_lernwelt.course_session.models import (
CourseSessionEdoniqTest, CourseSessionEdoniqTest,
) )
from vbv_lernwelt.course_session_group.models import CourseSessionGroup from vbv_lernwelt.course_session_group.models import CourseSessionGroup
from vbv_lernwelt.feedback.models import FeedbackResponse from vbv_lernwelt.importer.services import (
LP_DATA,
TRANSLATIONS,
create_or_update_course_session,
get_uk_course,
)
from vbv_lernwelt.learning_mentor.models import ( from vbv_lernwelt.learning_mentor.models import (
AgentParticipantRelation, AgentParticipantRelation,
AgentParticipantRoleType, AgentParticipantRoleType,
@ -32,12 +37,6 @@ from vbv_lernwelt.learnpath.models import Circle
from vbv_lernwelt.notify.models import Notification from vbv_lernwelt.notify.models import Notification
logger = structlog.get_logger(__name__) logger = structlog.get_logger(__name__)
from vbv_lernwelt.importer.services import (
create_or_update_course_session,
get_uk_course,
LP_DATA,
TRANSLATIONS,
)
IT_VV_TEST_COURSE = "Iterativ VV Testkurs" IT_VV_TEST_COURSE = "Iterativ VV Testkurs"
IT_UK_TEST_COURSE = "Iterativ üK Testkurs" IT_UK_TEST_COURSE = "Iterativ üK Testkurs"
@ -113,7 +112,7 @@ def delete_cs_data(cs: CourseSession):
else: else:
logger.info("no_course_session_found", import_id=cs.import_id) logger.info("no_course_session_found", import_id=cs.import_id)
FeedbackResponse.objects.filter(feedback_user__in=users).delete() # FeedbackResponse.objects.filter(feedback_user__in=users).delete()
def add_to_course_session( def add_to_course_session(

View File

@ -46,8 +46,8 @@ class CountrySerializer(serializers.ModelSerializer):
"vbv_country_id": country.vbv_country_id, "vbv_country_id": country.vbv_country_id,
"name": self.get_name(country), "name": self.get_name(country),
} }
except Country.DoesNotExist: except Country.DoesNotExist as e:
raise serializers.ValidationError({"id": "Invalid country ID"}) raise serializers.ValidationError({"id": "Invalid country ID"}) from e
return super().to_internal_value(data) return super().to_internal_value(data)

View File

@ -1,7 +1,7 @@
from collections import deque from collections import deque
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import MO, relativedelta, TH, TU, WE from dateutil.relativedelta import MO, TH, TU, WE, relativedelta
from django.utils import timezone from django.utils import timezone
from slugify import slugify from slugify import slugify
from wagtail.rich_text import RichText from wagtail.rich_text import RichText
@ -454,9 +454,9 @@ def create_edoniq_test_result_data(
max_points=24, max_points=24,
evaluation_points_deducted=0, evaluation_points_deducted=0,
): ):
assignment.assignment.evaluation_tasks.raw_data[0]["value"][ assignment.assignment.evaluation_tasks.raw_data[0]["value"]["max_points"] = (
"max_points" max_points
] = max_points )
assignment.assignment.save() assignment.assignment.save()
if assignment and course_session and assignment_user: if assignment and course_session and assignment_user:
ac, _ = update_assignment_completion( ac, _ = update_assignment_completion(
@ -855,7 +855,6 @@ def create_test_competence_navi():
def create_test_media_library(): def create_test_media_library():
course = Course.objects.get(id=COURSE_TEST_ID)
course_page = CoursePage.objects.get(course_id=COURSE_TEST_ID) course_page = CoursePage.objects.get(course_id=COURSE_TEST_ID)
media_lib_page = MediaLibraryPageFactory( media_lib_page = MediaLibraryPageFactory(

View File

@ -30,11 +30,6 @@ from vbv_lernwelt.learnpath.tests.learning_path_factories import (
LearningUnitFactory, LearningUnitFactory,
TopicFactory, TopicFactory,
) )
from vbv_lernwelt.media_files.create_default_documents import (
create_default_collections,
create_default_content_documents,
)
from vbv_lernwelt.media_files.create_default_images import create_default_images
from vbv_lernwelt.media_library.tests.media_library_factories import ( from vbv_lernwelt.media_library.tests.media_library_factories import (
LearnMediaBlockFactory, LearnMediaBlockFactory,
) )
@ -247,7 +242,7 @@ damit du erfolgreich mit deinem Lernpfad (durch-)starten kannst.
f"<p>In der Mediathek unter dem Handlungsfeld «{title}» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>" f"<p>In der Mediathek unter dem Handlungsfeld «{title}» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>"
f"<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>" f"<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>"
), ),
content_url=f"/course/überbetriebliche-kurse/media", content_url="/course/überbetriebliche-kurse/media",
) )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
@ -291,22 +286,24 @@ In diesem Circle erfährst du wie die überbetrieblichen Kurse aufgebaut sind. Z
) )
LearningUnitFactory(title="Vorbereitung", title_hidden=True, parent=circle) LearningUnitFactory(title="Vorbereitung", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen", title="Allgemeines zu Versicherungen",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>In der Mediathek unter «Allgemeines zu Versicherungen» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>" "<p>In der Mediathek unter «Allgemeines zu Versicherungen» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>"
f"<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>" "<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>"
), ),
content_url=f"/course/überbetriebliche-kurse/media", content_url="/course/überbetriebliche-kurse/media",
) )
LearningContentAssignmentFactory( (
title="Vorbereitungsauftrag Circle Kickoff", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Vorbereitungsauftrag Circle Kickoff",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"überbetriebliche-kurse-assignment-circle-kickoff" content_assignment=Assignment.objects.get(
slug__startswith="überbetriebliche-kurse-assignment-circle-kickoff"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle) LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -382,14 +379,16 @@ In diesem Circle erfährst du wie die überbetrieblichen Kurse aufgebaut sind. Z
slug__startswith="überbetriebliche-kurse-assignment-redlichkeits" slug__startswith="überbetriebliche-kurse-assignment-redlichkeits"
), ),
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"überbetriebliche-kurse-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith="überbetriebliche-kurse-assignment-reflexion"
),
), ),
), )
def create_uk_fr_circle_kickoff(lp, title="Lancement"): def create_uk_fr_circle_kickoff(lp, title="Lancement"):
@ -404,22 +403,24 @@ Dans ce cercle, tu apprendras comment les cours interentreprises sont structuré
LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start") LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle) LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen", title="Allgemeines zu Versicherungen",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</p>" "<p>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</p>"
f"<p>Nous te recommandons de te familiariser avec le sujet avant de suivre les autres unités de cours.</p>" "<p>Nous te recommandons de te familiariser avec le sujet avant de suivre les autres unités de cours.</p>"
), ),
content_url=f"/course/{circle.get_course().slug}/media", content_url=f"/course/{circle.get_course().slug}/media",
) )
LearningContentAssignmentFactory( (
title="Mission de préparation", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Mission de préparation",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"cours-interentreprises-assignment-circle-lancement", content_assignment=Assignment.objects.get(
slug__startswith="cours-interentreprises-assignment-circle-lancement",
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle) LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -497,14 +498,16 @@ Dans ce cercle, tu apprendras comment les cours interentreprises sont structuré
slug__startswith=f"{circle.get_course().slug}-assignment-redlichkeits" slug__startswith=f"{circle.get_course().slug}-assignment-redlichkeits"
), ),
) )
LearningContentAssignmentFactory( (
title="Réflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Réflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
def create_uk_it_circle_kickoff(lp, title="Introduzione"): def create_uk_it_circle_kickoff(lp, title="Introduzione"):
@ -521,22 +524,24 @@ In questo Circle imparerai come sono strutturati i corsi interaziendali. Imparer
) )
LearningUnitFactory(title="Preparazione", title_hidden=True, parent=circle) LearningUnitFactory(title="Preparazione", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen", title="Allgemeines zu Versicherungen",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>Nella mediateca, sotto il campo d'azione «Allgemeines zu Versicherungen», troverai tutte le risorse rilevanti per le tue competenze professionali." "<p>Nella mediateca, sotto il campo d'azione «Allgemeines zu Versicherungen», troverai tutte le risorse rilevanti per le tue competenze professionali."
f"<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>" "<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>"
), ),
content_url=f"/course/{circle.get_course().slug}/media", content_url=f"/course/{circle.get_course().slug}/media",
) )
LearningContentAssignmentFactory( (
title="Incarico di preparazione", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Incarico di preparazione",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-circle-introduzione-incarico-di-preparazione" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-circle-introduzione-incarico-di-preparazione"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle) LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -612,14 +617,16 @@ In questo Circle imparerai come sono strutturati i corsi interaziendali. Imparer
slug__startswith="überbetriebliche-kurse-assignment-redlichkeits" slug__startswith="überbetriebliche-kurse-assignment-redlichkeits"
), ),
) )
LearningContentAssignmentFactory( (
title="Riflessione", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Riflessione",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-riflessione" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-riflessione"
),
), ),
), )
def create_uk_circle_basis(lp, title="Basis"): def create_uk_circle_basis(lp, title="Basis"):
@ -636,22 +643,24 @@ In diesem Circle lernst du die wichtigsten Grundlagen bezüglich Versicherungswi
) )
LearningUnitFactory(title="Vorbereitung", title_hidden=True, parent=circle) LearningUnitFactory(title="Vorbereitung", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen", title="Allgemeines zu Versicherungen",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>In der Mediathek unter «Allgemeines zu Versicherungen» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>" "<p>In der Mediathek unter «Allgemeines zu Versicherungen» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>"
f"<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>" "<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>"
), ),
content_url=f"/course/überbetriebliche-kurse/media", content_url="/course/überbetriebliche-kurse/media",
) )
LearningContentAssignmentFactory( (
title="Vorbereitungsauftrag Circle Basis", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Vorbereitungsauftrag Circle Basis",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"überbetriebliche-kurse-assignment-circle-basis" content_assignment=Assignment.objects.get(
slug__startswith="überbetriebliche-kurse-assignment-circle-basis"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle) LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -724,14 +733,16 @@ In diesem Circle lernst du die wichtigsten Grundlagen bezüglich Versicherungswi
), ),
) )
LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle) LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"überbetriebliche-kurse-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith="überbetriebliche-kurse-assignment-reflexion"
),
), ),
), )
def create_uk_fr_circle_basis(lp, title="Base"): def create_uk_fr_circle_basis(lp, title="Base"):
@ -746,22 +757,24 @@ Dans ce cercle, tu apprends les bases les plus importantes en matière d'assuran
LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start") LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle) LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen", title="Allgemeines zu Versicherungen",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</p>" "<p>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</p>"
f"<p>Nous te recommandons de te familiariser avec le sujet avant de suivre les autres unités de cours.</p>" "<p>Nous te recommandons de te familiariser avec le sujet avant de suivre les autres unités de cours.</p>"
), ),
content_url=f"/course/{circle.get_course().slug}/media", content_url=f"/course/{circle.get_course().slug}/media",
) )
LearningContentAssignmentFactory( (
title="Mandats préparatoires Circle Base", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Mandats préparatoires Circle Base",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-circle-base" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-circle-base"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle) LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -833,14 +846,16 @@ Dans ce cercle, tu apprends les bases les plus importantes en matière d'assuran
extended_time_test_url="https://exam.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1691157696911,2147478636", extended_time_test_url="https://exam.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1691157696911,2147478636",
) )
LearningUnitFactory(title="Réflexion", title_hidden=True, parent=circle) LearningUnitFactory(title="Réflexion", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Réflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Réflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
def create_uk_it_circle_basis(lp, title="Base"): def create_uk_it_circle_basis(lp, title="Base"):
@ -855,22 +870,24 @@ In questo Circle imparerai le basi più importanti del settore assicurativo e de
LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start") LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle) LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen", title="Allgemeines zu Versicherungen",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>Nella mediateca, sotto il campo d'azione «Allgemeines zu Versicherungen», troverai tutte le risorse rilevanti per le tue competenze professionali." "<p>Nella mediateca, sotto il campo d'azione «Allgemeines zu Versicherungen», troverai tutte le risorse rilevanti per le tue competenze professionali."
f"<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>" "<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>"
), ),
content_url=f"/course/{circle.get_course().slug}/media", content_url=f"/course/{circle.get_course().slug}/media",
) )
LearningContentAssignmentFactory( (
title="Mandato di preparazione Circle Base", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Mandato di preparazione Circle Base",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-cercle-base" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-cercle-base"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle) LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -942,14 +959,16 @@ In questo Circle imparerai le basi più importanti del settore assicurativo e de
extended_time_test_url="https://exam.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1691157696911,2147478636", extended_time_test_url="https://exam.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1691157696911,2147478636",
) )
LearningUnitFactory(title="Riflessione", title_hidden=True, parent=circle) LearningUnitFactory(title="Riflessione", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Riflessione", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Riflessione",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-riflessione" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-riflessione"
),
), ),
), )
def create_uk_circle_fahrzeug(lp, title="Fahrzeug"): def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
@ -971,16 +990,18 @@ def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
f"<p>In der Mediathek unter dem Handlungsfeld «{title}» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>" f"<p>In der Mediathek unter dem Handlungsfeld «{title}» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</p>"
f"<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>" f"<p>Wir empfehlen dir vor der Absolvierung der weiteren Lerneinheiten dich in die Thematik einzulesen.</p>"
), ),
content_url=f"/course/überbetriebliche-kurse/media/handlungsfelder/fahrzeug", content_url="/course/überbetriebliche-kurse/media/handlungsfelder/fahrzeug",
) )
LearningContentAssignmentFactory( (
title="Fahrzeug - Mein erstes Auto", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Fahrzeug - Mein erstes Auto",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-fahrzeug-mein-erstes-auto" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-fahrzeug-mein-erstes-auto"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle) LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -1070,22 +1091,26 @@ def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Kompetenznachweis", title_hidden=True, parent=circle) LearningUnitFactory(title="Kompetenznachweis", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Überprüfen einer Motorfahrzeug-Versicherungspolice", LearningContentAssignmentFactory(
parent=circle, title="Überprüfen einer Motorfahrzeug-Versicherungspolice",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-überprüfen-einer-motorfahrzeugs" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-überprüfen-einer-motorfahrzeugs"
),
), ),
), )
LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle) LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-reflexion"
),
), ),
), )
def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"): def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
@ -1099,22 +1124,24 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start") LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle) LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Champs daction «Véhicule à moteur»", title="Champs daction «Véhicule à moteur»",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</p>" "<p>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</p>"
f"<p>Nous te recommandons de te familiariser avec le sujet avant de suivre les autres unités de cours.</p>" "<p>Nous te recommandons de te familiariser avec le sujet avant de suivre les autres unités de cours.</p>"
), ),
content_url=f"/course/{course_slug}/media", content_url=f"/course/{course_slug}/media",
) )
LearningContentAssignmentFactory( (
title="Véhicule à moteur Ma première voiture", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Véhicule à moteur Ma première voiture",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-véhicule-à-moteur-ma-première-voiture" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-véhicule-à-moteur-ma-première-voiture"
),
), ),
), )
LearningSequenceFactory(title="Training", parent=circle) LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle) LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -1206,22 +1233,26 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
LearningUnitFactory( LearningUnitFactory(
title="Contrôle de compétences", title_hidden=True, parent=circle title="Contrôle de compétences", title_hidden=True, parent=circle
) )
LearningContentAssignmentFactory( (
title="Vérification d'une police dassurance de véhicule à moteur", LearningContentAssignmentFactory(
parent=circle, title="Vérification d'une police dassurance de véhicule à moteur",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-vérification-d-une-police-d-assurance-de-véhicule-à-moteur" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-vérification-d-une-police-d-assurance-de-véhicule-à-moteur"
),
), ),
), )
LearningUnitFactory(title="Réflexion", title_hidden=True, parent=circle) LearningUnitFactory(title="Réflexion", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Réflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Réflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-reflexion"
),
), ),
), )
def create_uk_it_circle_fahrzeug(lp, title="Veicolo"): def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
@ -1237,22 +1268,24 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
) )
LearningUnitFactory(title="Preparazione", title_hidden=True, parent=circle) LearningUnitFactory(title="Preparazione", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory( LearningContentMediaLibraryFactory(
title=f"Campo dazione «Veicolo»", title="Campo dazione «Veicolo»",
parent=circle, parent=circle,
description=RichText( description=RichText(
f"<p>Nella mediateca, sotto il campo d'azione «Veicolo», troverai tutte le risorse rilevanti per le tue competenze professionali.</p>" "<p>Nella mediateca, sotto il campo d'azione «Veicolo», troverai tutte le risorse rilevanti per le tue competenze professionali.</p>"
f"<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>" "<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>"
), ),
content_url=f"/course/{course_slug}/media", content_url=f"/course/{course_slug}/media",
) )
LearningContentAssignmentFactory( (
title="Veicolo, la mia prima auto", LearningContentAssignmentFactory(
assignment_type="PREP_ASSIGNMENT", title="Veicolo, la mia prima auto",
parent=circle, assignment_type="PREP_ASSIGNMENT",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-veicolo-la-mia-prima-auto" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-veicolo-la-mia-prima-auto"
),
), ),
), )
LearningSequenceFactory(title="Formazione", parent=circle) LearningSequenceFactory(title="Formazione", parent=circle)
LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle) LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory( LearningContentAttendanceCourseFactory(
@ -1344,19 +1377,23 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
LearningUnitFactory( LearningUnitFactory(
title="Controllo delle competenze", title_hidden=True, parent=circle title="Controllo delle competenze", title_hidden=True, parent=circle
) )
LearningContentAssignmentFactory( (
title="Verifica di una polizza di assicurazione veicoli a motore", LearningContentAssignmentFactory(
parent=circle, title="Verifica di una polizza di assicurazione veicoli a motore",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-verifica-di-una-polizza-di-assicurazione-veicoli-a-motore" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-verifica-di-una-polizza-di-assicurazione-veicoli-a-motore"
),
), ),
), )
LearningUnitFactory(title="Riflessione", title_hidden=True, parent=circle) LearningUnitFactory(title="Riflessione", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Riflessione", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Riflessione",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-riflessione" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-riflessione"
),
), ),
), )

View File

@ -1,7 +1,6 @@
import graphene import graphene
from vbv_lernwelt.core.utils import get_django_content_type from vbv_lernwelt.core.utils import get_django_content_type
from vbv_lernwelt.learnpath.models import Circle
class CoursePageInterface(graphene.Interface): class CoursePageInterface(graphene.Interface):

View File

@ -30,7 +30,6 @@ from vbv_lernwelt.course_session.models import (
) )
from vbv_lernwelt.course_session_group.models import CourseSessionGroup from vbv_lernwelt.course_session_group.models import CourseSessionGroup
from vbv_lernwelt.iam.permissions import has_course_access from vbv_lernwelt.iam.permissions import has_course_access
from vbv_lernwelt.learnpath.consts import COURSE_PROFILE_ALL_ID
from vbv_lernwelt.learnpath.graphql.types import LearningPathObjectType from vbv_lernwelt.learnpath.graphql.types import LearningPathObjectType
from vbv_lernwelt.learnpath.models import Circle, CourseProfile from vbv_lernwelt.learnpath.models import Circle, CourseProfile

View File

@ -3,7 +3,7 @@ import random
from datetime import datetime, timedelta from datetime import datetime, timedelta
import djclick as click import djclick as click
from dateutil.relativedelta import MO, relativedelta, TH, TU from dateutil.relativedelta import MO, TH, TU, relativedelta
from django.utils import timezone from django.utils import timezone
from vbv_lernwelt.assignment.creators.create_assignments import ( from vbv_lernwelt.assignment.creators.create_assignments import (

View File

@ -2,7 +2,6 @@
from django.db import migrations, models from django.db import migrations, models
TEST_COURSE_ID = -1 TEST_COURSE_ID = -1
UK_COURSE_IDS = [ UK_COURSE_IDS = [

View File

@ -1,8 +1,8 @@
from rest_framework.fields import SerializerMethodField from rest_framework.fields import SerializerMethodField
from vbv_lernwelt.core.serializer_helpers import ( from vbv_lernwelt.core.serializer_helpers import (
get_it_serializer_class,
ItWagtailBaseSerializer, ItWagtailBaseSerializer,
get_it_serializer_class,
) )
from vbv_lernwelt.core.utils import StringIDField from vbv_lernwelt.core.utils import StringIDField

View File

@ -23,7 +23,7 @@ class CourseCompletionApiTestCase(APITestCase):
course_id=COURSE_TEST_ID, course_id=COURSE_TEST_ID,
title="Test Lehrgang Session", title="Test Lehrgang Session",
) )
csu = CourseSessionUser.objects.create( CourseSessionUser.objects.create(
course_session=self.cs, course_session=self.cs,
user=self.user, user=self.user,
) )
@ -34,7 +34,7 @@ class CourseCompletionApiTestCase(APITestCase):
title="Fachcheck Reisen" title="Fachcheck Reisen"
) )
mark_url = f"/api/course/completion/mark/" mark_url = "/api/course/completion/mark/"
response = self.client.post( response = self.client.post(
mark_url, mark_url,

View File

@ -24,7 +24,7 @@ class CourseCompletionApiTestCase(APITestCase):
self.client.login(username="student", password="test") self.client.login(username="student", password="test")
def test_api_noCourseSession_withoutCourseSessionUser(self): def test_api_noCourseSession_withoutCourseSessionUser(self):
response = self.client.get(f"/api/course/sessions/") response = self.client.get("/api/course/sessions/")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 0) self.assertEqual(len(response.json()), 0)
@ -34,7 +34,7 @@ class CourseCompletionApiTestCase(APITestCase):
course_session=self.course_session, course_session=self.course_session,
user=self.user, user=self.user,
) )
response = self.client.get(f"/api/course/sessions/") response = self.client.get("/api/course/sessions/")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 1) self.assertEqual(len(response.json()), 1)
@ -44,7 +44,7 @@ class CourseCompletionApiTestCase(APITestCase):
def test_api_superUser_canAccessEveryCourseSession(self): def test_api_superUser_canAccessEveryCourseSession(self):
self.client.login(username="admin", password="test") self.client.login(username="admin", password="test")
response = self.client.get(f"/api/course/sessions/") response = self.client.get("/api/course/sessions/")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 1) self.assertEqual(len(response.json()), 1)

View File

@ -56,7 +56,7 @@ class DocumentUploadApiTestCase(APITestCase):
) )
self.test_data["learning_sequence"] = ls.id self.test_data["learning_sequence"] = ls.id
response = self.client.post(f"/api/core/document/start/", self.test_data) response = self.client.post("/api/core/document/start/", self.test_data)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertNotEqual(response.data["url"], "") self.assertNotEqual(response.data["url"], "")
@ -81,7 +81,7 @@ class DocumentUploadApiTestCase(APITestCase):
slug="test-lehrgang-lp-circle-reisen-ls-analyse" slug="test-lehrgang-lp-circle-reisen-ls-analyse"
) )
self.test_data["learning_sequence"] = ls.id self.test_data["learning_sequence"] = ls.id
response = self.client.post(f"/api/core/document/start/", self.test_data) response = self.client.post("/api/core/document/start/", self.test_data)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@ -91,7 +91,7 @@ class DocumentUploadApiTestCase(APITestCase):
slug="test-lehrgang-lp-circle-fahrzeug-ls-vorbereitung" slug="test-lehrgang-lp-circle-fahrzeug-ls-vorbereitung"
) )
self.test_data["learning_sequence"] = ls.id self.test_data["learning_sequence"] = ls.id
response = self.client.post(f"/api/core/document/start/", self.test_data) response = self.client.post("/api/core/document/start/", self.test_data)
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@ -100,13 +100,13 @@ class DocumentUploadApiTestCase(APITestCase):
slug="test-lehrgang-lp-circle-fahrzeug-ls-vorbereitung" slug="test-lehrgang-lp-circle-fahrzeug-ls-vorbereitung"
) )
self.test_data["learning_sequence"] = ls.id self.test_data["learning_sequence"] = ls.id
response = self.client.post(f"/api/core/document/start/", self.test_data) response = self.client.post("/api/core/document/start/", self.test_data)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
file_id = response.data["file_id"] file_id = response.data["file_id"]
response = self.client.post( response = self.client.post(
f"/api/core/file/finish/", "/api/core/file/finish/",
{ {
"file_id": file_id, "file_id": file_id,
}, },
@ -129,7 +129,7 @@ class DocumentUploadApiTestCase(APITestCase):
file.full_clean() file.full_clean()
file.save() file.save()
response = self.client.post(f"/api/core/file/finish/", {"file_id": file.id}) response = self.client.post("/api/core/file/finish/", {"file_id": file.id})
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)

View File

@ -120,9 +120,7 @@ class CourseSessionAssignmentAdmin(admin.ModelAdmin):
# Make circle display-only in the form # Make circle display-only in the form
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
readonly_fields = super(CourseSessionAssignmentAdmin, self).get_readonly_fields( super(CourseSessionAssignmentAdmin, self).get_readonly_fields(request, obj)
request, obj
)
return ["circle_display"] return ["circle_display"]
# Override get_form to include circle_display # Override get_form to include circle_display

View File

@ -1,4 +1,3 @@
import factory
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from vbv_lernwelt.course.factories import CourseFactory from vbv_lernwelt.course.factories import CourseFactory

View File

@ -20,7 +20,7 @@ class CourseSessionQuery(object):
root, root,
info, info,
id=None, id=None,
user_id=graphene.ID(required=False), user_id=graphene.ID(required=False), # noqa: B008
): ):
if user_id is None: if user_id is None:
user_id = info.context.user.id user_id = info.context.user.id

View File

@ -4,5 +4,4 @@ from vbv_lernwelt.course_session_group.models import CourseSessionGroup
@admin.register(CourseSessionGroup) @admin.register(CourseSessionGroup)
class CourseSessionAssignmentAdmin(admin.ModelAdmin): class CourseSessionAssignmentAdmin(admin.ModelAdmin): ...
...

View File

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

View File

@ -107,7 +107,7 @@ class DashboardQuery(graphene.ObjectType):
coursesessionuser__user=user, coursesessionuser__user=user,
coursesessionuser__role=CourseSessionUser.Role.EXPERT, coursesessionuser__role=CourseSessionUser.Role.EXPERT,
).values_list("id", flat=True) ).values_list("id", flat=True)
setattr(info.context, "circle_ids", list(circle_ids)) setattr(info.context, "circle_ids", list(circle_ids)) # noqa: B010
# todo: if course_session_ids and circles are empty return none or 404 or 401 # todo: if course_session_ids and circles are empty return none or 404 or 401
@ -119,9 +119,7 @@ class DashboardQuery(graphene.ObjectType):
course_session_selection_ids=list(course_session_ids), # noqa course_session_selection_ids=list(course_session_ids), # noqa
) )
def resolve_mentor_course_statistics( def resolve_mentor_course_statistics(root, info, course_id: str, agent_role: str): # noqa
root, info, course_id: str, agent_role: str
): # noqa
user = info.context.user user = info.context.user
return _agent_course_statistics(user, course_id, role=agent_role) return _agent_course_statistics(user, course_id, role=agent_role)
@ -173,7 +171,7 @@ class DashboardQuery(graphene.ObjectType):
user = info.context.user user = info.context.user
course = Course.objects.get(id=course_id) course = Course.objects.get(id=course_id)
setattr(info.context, "course", course) setattr(info.context, "course", course) # noqa: B010
newest: CourseSession | None = None newest: CourseSession | None = None
course_session_for_user: List[str] = [] course_session_for_user: List[str] = []

View File

@ -120,7 +120,7 @@ def get_assignment_completion_metrics(
) )
key = f"CourseSessionUsers_{course_session.id}" key = f"CourseSessionUsers_{course_session.id}"
if not key in context: if key not in context:
if user_selection_ids: if user_selection_ids:
csu_qs = csu_qs.filter(user_id__in=user_selection_ids) csu_qs = csu_qs.filter(user_id__in=user_selection_ids)
@ -192,7 +192,7 @@ def create_record(
key = f"{assignment_type}_{course_session_assignment.learning_content.id}" key = f"{assignment_type}_{course_session_assignment.learning_content.id}"
if not key in context: if key not in context:
context[key] = course_session_assignment.learning_content.get_circle().id context[key] = course_session_assignment.learning_content.get_circle().id
circle_id = context[key] circle_id = context[key]

View File

@ -4,21 +4,21 @@ from graphene import Enum
from vbv_lernwelt.course.graphql.types import CourseConfigurationObjectType from vbv_lernwelt.course.graphql.types import CourseConfigurationObjectType
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.dashboard.graphql.types.assignment import ( from vbv_lernwelt.dashboard.graphql.types.assignment import (
assignments,
AssignmentsStatisticsType, AssignmentsStatisticsType,
assignments,
) )
from vbv_lernwelt.dashboard.graphql.types.attendance import ( from vbv_lernwelt.dashboard.graphql.types.attendance import (
attendance_day_presences,
AttendanceDayPresencesStatisticsType, AttendanceDayPresencesStatisticsType,
attendance_day_presences,
) )
from vbv_lernwelt.dashboard.graphql.types.competence import ( from vbv_lernwelt.dashboard.graphql.types.competence import (
CompetencePerformanceStatisticsSummaryType, CompetencePerformanceStatisticsSummaryType,
competences,
CompetencesStatisticsType, CompetencesStatisticsType,
competences,
) )
from vbv_lernwelt.dashboard.graphql.types.feedback import ( from vbv_lernwelt.dashboard.graphql.types.feedback import (
feedback_responses,
FeedbackStatisticsResponsesType, FeedbackStatisticsResponsesType,
feedback_responses,
) )
from vbv_lernwelt.learnpath.models import Circle from vbv_lernwelt.learnpath.models import Circle
@ -201,7 +201,8 @@ class CourseStatisticsType(BaseStatisticsType):
records, success_total, fail_total = competences( records, success_total, fail_total = competences(
course_slug=str(root.course_slug), course_slug=str(root.course_slug),
course_session_selection_ids=[ course_session_selection_ids=[
str(cs) for cs in root.course_session_selection_ids # noqa str(cs)
for cs in root.course_session_selection_ids # noqa
], ],
user_selection_ids=user_selection_ids, # noqa user_selection_ids=user_selection_ids, # noqa
circle_ids=root.get_circle_ids(info), # noqa circle_ids=root.get_circle_ids(info), # noqa

View File

@ -29,14 +29,14 @@ from vbv_lernwelt.learnpath.models import Circle
class AssignmentTestCase(GraphQLTestCase): class AssignmentTestCase(GraphQLTestCase):
GRAPHQL_URL = "/server/graphql/" GRAPHQL_URL = "/server/graphql/"
GRAPHQL_QUERY = f"""query($course_id: ID!) {{ GRAPHQL_QUERY = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
assignments{{ assignments{
summary{{ summary{
completed_count completed_count
average_passed average_passed
}} }
records{{ records{
course_session_id course_session_id
course_session_assignment_id course_session_assignment_id
circle_id circle_id
@ -45,17 +45,17 @@ class AssignmentTestCase(GraphQLTestCase):
assignment_type_translation_key assignment_type_translation_key
details_url details_url
deadline deadline
metrics {{ metrics {
passed_count passed_count
failed_count failed_count
unranked_count unranked_count
ranking_completed ranking_completed
average_passed average_passed
}} }
}} }
}} }
}} }
}}""" }"""
def setUp(self): def setUp(self):
self.course, self.course_page = create_course("Test Course") self.course, self.course_page = create_course("Test Course")

View File

@ -75,15 +75,15 @@ class DashboardAttendanceTestCase(GraphQLTestCase):
self.client.force_login(supervisor) self.client.force_login(supervisor)
query = f""" query = """
query($course_id: ID!) {{ query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
attendance_day_presences{{ attendance_day_presences{
summary{{ summary{
days_completed days_completed
participants_present participants_present
}} }
records{{ records{
course_session_id course_session_id
generation generation
circle_id circle_id
@ -91,10 +91,10 @@ class DashboardAttendanceTestCase(GraphQLTestCase):
participants_present participants_present
participants_total participants_total
details_url details_url
}} }
}} }
}} }
}} }
""" """
# WHEN # WHEN
@ -215,15 +215,15 @@ class DashboardExpertAttendanceTestCase(GraphQLTestCase):
self.client.force_login(e1) self.client.force_login(e1)
query = f""" query = """
query($course_id: ID!) {{ query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
attendance_day_presences{{ attendance_day_presences{
summary{{ summary{
days_completed days_completed
participants_present participants_present
}} }
records{{ records{
course_session_id course_session_id
generation generation
circle_id circle_id
@ -231,10 +231,10 @@ class DashboardExpertAttendanceTestCase(GraphQLTestCase):
participants_present participants_present
participants_total participants_total
details_url details_url
}} }
}} }
}} }
}} }
""" """
# WHEN # WHEN

View File

@ -62,10 +62,10 @@ class DashboardCompetenceTestCase(GraphQLTestCase):
self.client.force_login(supervisor) self.client.force_login(supervisor)
query = f"""query($course_id: ID!) {{ query = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
competences {{ competences {
records {{ records {
title title
course_session_id course_session_id
generation generation
@ -73,14 +73,14 @@ class DashboardCompetenceTestCase(GraphQLTestCase):
success_count success_count
fail_count fail_count
details_url details_url
}} }
summary {{ summary {
success_total success_total
fail_total fail_total
}} }
}} }
}} }
}} }
""" """
variables = {"course_id": str(course.id)} variables = {"course_id": str(course.id)}
@ -189,10 +189,10 @@ class DashboardExpertCompetenceTestCase(GraphQLTestCase):
self.client.force_login(e1) self.client.force_login(e1)
query = f"""query($course_id: ID!) {{ query = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
competences {{ competences {
records {{ records {
title title
course_session_id course_session_id
generation generation
@ -200,14 +200,14 @@ class DashboardExpertCompetenceTestCase(GraphQLTestCase):
success_count success_count
fail_count fail_count
details_url details_url
}} }
summary {{ summary {
success_total success_total
fail_total fail_total
}} }
}} }
}} }
}} }
""" """
variables = {"course_id": str(course.id)} variables = {"course_id": str(course.id)}

View File

@ -77,10 +77,10 @@ class DashboardFeedbackTestCase(GraphQLTestCase):
self.client.force_login(supervisor) self.client.force_login(supervisor)
query = f"""query($course_id: ID!) {{ query = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
feedback_responses {{ feedback_responses {
records {{ records {
course_session_id course_session_id
generation generation
circle_id circle_id
@ -88,15 +88,15 @@ class DashboardFeedbackTestCase(GraphQLTestCase):
satisfaction_max satisfaction_max
details_url details_url
experts experts
}} }
summary {{ summary {
satisfaction_average satisfaction_average
satisfaction_max satisfaction_max
total_responses total_responses
}} }
}} }
}} }
}} }
""" """
variables = {"course_id": str(course.id)} variables = {"course_id": str(course.id)}
@ -210,10 +210,10 @@ class DashboardExpertFeedbackTestCase(GraphQLTestCase):
self.client.force_login(expert1.user) self.client.force_login(expert1.user)
query = f"""query($course_id: ID!) {{ query = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
feedback_responses {{ feedback_responses {
records {{ records {
course_session_id course_session_id
generation generation
circle_id circle_id
@ -221,15 +221,15 @@ class DashboardExpertFeedbackTestCase(GraphQLTestCase):
satisfaction_max satisfaction_max
details_url details_url
experts experts
}} }
summary {{ summary {
satisfaction_average satisfaction_average
satisfaction_max satisfaction_max
total_responses total_responses
}} }
}} }
}} }
}} }
""" """
variables = {"course_id": str(course.id)} variables = {"course_id": str(course.id)}

View File

@ -77,15 +77,15 @@ class DashboardTestCase(GraphQLTestCase):
self.client.force_login(cs_1_ab_supervisor) self.client.force_login(cs_1_ab_supervisor)
# WHEN # WHEN
query = f"""query($course_id: ID!) {{ query = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {{ course_statistics(course_id: $course_id) {
course_session_selection_metrics {{ course_session_selection_metrics {
expert_count expert_count
participant_count participant_count
session_count session_count
}} }
}} }
}}""" }"""
variables = {"course_id": str(course_1.id)} variables = {"course_id": str(course_1.id)}
response = self.query(query, variables=variables) response = self.query(query, variables=variables)

View File

@ -141,7 +141,7 @@ def create_person_list_with_roles(
# add persons where request.user is mentor # add persons where request.user is mentor
for cs in course_sessions: for cs in course_sessions:
def _add_agent_relation(my_role, user_role): def _add_agent_relation(cs, relation, my_role, user_role):
course_session_entry = create_course_session_dict(cs, my_role, user_role) course_session_entry = create_course_session_dict(cs, my_role, user_role)
participant_user = relation.participant.user participant_user = relation.participant.user
@ -161,7 +161,7 @@ def create_person_list_with_roles(
participant__course_session_id=cs.id, participant__course_session_id=cs.id,
role="LEARNING_MENTOR", role="LEARNING_MENTOR",
): ):
_add_agent_relation("LEARNING_MENTOR", "PARTICIPANT") _add_agent_relation(cs, relation, "LEARNING_MENTOR", "PARTICIPANT")
if "BERUFSBILDNER" in cs.roles: if "BERUFSBILDNER" in cs.roles:
for relation in AgentParticipantRelation.objects.filter( for relation in AgentParticipantRelation.objects.filter(
@ -169,7 +169,7 @@ def create_person_list_with_roles(
participant__course_session_id=cs.id, participant__course_session_id=cs.id,
role="BERUFSBILDNER", role="BERUFSBILDNER",
): ):
_add_agent_relation("BERUFSBILDNER", "PARTICIPANT") _add_agent_relation(cs, relation, "BERUFSBILDNER", "PARTICIPANT")
# add persons where request.user is lerning mentee # add persons where request.user is lerning mentee
mentor_relation_qs = AgentParticipantRelation.objects.filter( mentor_relation_qs = AgentParticipantRelation.objects.filter(

View File

@ -31,7 +31,7 @@ from vbv_lernwelt.course_session.services.export_attendance import (
export_attendance, export_attendance,
make_export_filename, make_export_filename,
) )
from vbv_lernwelt.dashboard.person_export import export_persons, PERSONS_EXPORT_FILENAME from vbv_lernwelt.dashboard.person_export import PERSONS_EXPORT_FILENAME, export_persons
from vbv_lernwelt.dashboard.utils import ( from vbv_lernwelt.dashboard.utils import (
CourseSessionWithRoles, CourseSessionWithRoles,
create_course_session_dict, create_course_session_dict,
@ -42,8 +42,8 @@ from vbv_lernwelt.dashboard.utils import (
from vbv_lernwelt.duedate.models import DueDate from vbv_lernwelt.duedate.models import DueDate
from vbv_lernwelt.duedate.serializers import DueDateSerializer from vbv_lernwelt.duedate.serializers import DueDateSerializer
from vbv_lernwelt.feedback.export import ( from vbv_lernwelt.feedback.export import (
export_feedback_with_circle_restriction,
FEEDBACK_EXPORT_FILE_NAME, FEEDBACK_EXPORT_FILE_NAME,
export_feedback_with_circle_restriction,
) )
from vbv_lernwelt.learning_mentor.models import ( from vbv_lernwelt.learning_mentor.models import (
AgentParticipantRelation, AgentParticipantRelation,
@ -346,9 +346,7 @@ def get_mentor_open_tasks_count(request, course_id: str):
return Response( return Response(
status=200, status=200,
data={ data={
"open_task_count": _get_mentor_open_tasks_count( "open_task_count": _get_mentor_open_tasks_count(course_id, request.user) # noqa
course_id, request.user
) # noqa
}, },
) )
except PermissionDenied as e: except PermissionDenied as e:

View File

@ -1,3 +1 @@
from django.shortcuts import render
# Create your views here. # Create your views here.

View File

@ -58,7 +58,7 @@ def load_edoniq_test_results_csv_data():
if __name__ == "__main__": if __name__ == "__main__":
csv_data = load_edoniq_test_results_csv_data() csv_data = load_edoniq_test_results_csv_data()
csv_reader = csv.reader(StringIO(csv_data), delimiter=";") csv_reader = csv.reader(StringIO(csv_data), delimiter=";")
for i, row in enumerate(csv_reader): for _, row in enumerate(csv_reader):
# if len(row) > 4 and row[4] == "AG 2023 A" and row[5] == "de_üK1_KO_Testlauf": # if len(row) > 4 and row[4] == "AG 2023 A" and row[5] == "de_üK1_KO_Testlauf":
# print(row) # print(row)
if len(row) > 4 and row[6] == "1691151920116": if len(row) > 4 and row[6] == "1691151920116":

View File

@ -11,8 +11,8 @@ from vbv_lernwelt.core.constants import (
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.creators.test_course import create_test_course from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.edoniq_test.result_import.services import ( from vbv_lernwelt.edoniq_test.result_import.services import (
create_edoniq_csv_test_result,
EdoniqCsvTestResult, EdoniqCsvTestResult,
create_edoniq_csv_test_result,
filter_relevant_rows, filter_relevant_rows,
get_distinct_course_release_ids, get_distinct_course_release_ids,
upsert_edoniq_test_result, upsert_edoniq_test_result,

View File

@ -100,14 +100,6 @@ def export_students_and_trainers(request):
return generate_export_response(course_session_users) return generate_export_response(course_session_users)
def fetch_course_session_users(courses: List[int]):
# if a user is in multiple courses, he should be exported multiple times
# todo: check if this is the case otherwise use .distinct("user")
return CourseSessionUser.objects.filter(
course_session__course__id__in=courses, role=CourseSessionUser.Role.MEMBER
).order_by("user__email")
def fetch_course_session_users( def fetch_course_session_users(
courses: List[int], role=CourseSessionUser.Role.MEMBER, excluded_domains=None courses: List[int], role=CourseSessionUser.Role.MEMBER, excluded_domains=None
): ):
@ -153,9 +145,9 @@ def fetch_course_session_all_users(courses: List[int], excluded_domains=None):
def generate_export_response(cs_users: List[User]) -> HttpResponse: def generate_export_response(cs_users: List[User]) -> HttpResponse:
response = HttpResponse(content_type="text/csv; charset=utf-8") response = HttpResponse(content_type="text/csv; charset=utf-8")
response[ response["Content-Disposition"] = (
"Content-Disposition" f"attachment; filename=edoniq_user_export_{date.today().strftime('%Y%m%d')}.csv"
] = f"attachment; filename=edoniq_user_export_{date.today().strftime('%Y%m%d')}.csv" )
response.write("\ufeff".encode("utf8")) # UTF-8 BOM response.write("\ufeff".encode("utf8")) # UTF-8 BOM

View File

@ -77,7 +77,7 @@ def update_feedback_response(
def initial_data_for_feedback_page( def initial_data_for_feedback_page(
learning_content_feedback_page: Union[ learning_content_feedback_page: Union[
LearningContentFeedbackUK, LearningContentFeedbackVV LearningContentFeedbackUK, LearningContentFeedbackVV
] ],
): ):
if hasattr(learning_content_feedback_page, "learningcontentfeedbackuk"): if hasattr(learning_content_feedback_page, "learningcontentfeedbackuk"):
return { return {
@ -125,9 +125,9 @@ def _handle_feedback_export_action(course_seesions, file_name):
response = HttpResponse( response = HttpResponse(
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
) )
response[ response["Content-Disposition"] = (
"Content-Disposition" f"attachment; filename={make_export_filename(file_name)}"
] = f"attachment; filename={make_export_filename(file_name)}" )
response.write(excel_bytes) response.write(excel_bytes)
return response return response

View File

@ -92,7 +92,7 @@ def s3_generate_presigned_post(
Fields={ Fields={
"acl": acl, "acl": acl,
"Content-Type": file_type, "Content-Type": file_type,
f"Content-Disposition": f"attachment; filename={file_name}", "Content-Disposition": f"attachment; filename={file_name}",
}, },
Conditions=[ Conditions=[
{"acl": acl}, {"acl": acl},

View File

@ -1,5 +1,5 @@
from importlib import import_module from importlib import import_module
from typing import Sequence, Type, TYPE_CHECKING from typing import TYPE_CHECKING, Sequence, Type
from django.conf import settings from django.conf import settings
from django.contrib import auth from django.contrib import auth

View File

@ -8,7 +8,6 @@ from vbv_lernwelt.files.enums import FileUploadStorage
from vbv_lernwelt.files.integrations import s3_delete_file, s3_generate_presigned_url from vbv_lernwelt.files.integrations import s3_delete_file, s3_generate_presigned_url
from vbv_lernwelt.files.utils import file_generate_upload_path from vbv_lernwelt.files.utils import file_generate_upload_path
# Inspired by https://www.hacksoft.io/blog/direct-to-s3-file-upload-with-django # Inspired by https://www.hacksoft.io/blog/direct-to-s3-file-upload-with-django
# Code https://github.com/HackSoftware/Django-Styleguide-Example/tree/bdadf52b849bb5fa47854a3094f4da6fe9d54d02/styleguide_example/files # Code https://github.com/HackSoftware/Django-Styleguide-Example/tree/bdadf52b849bb5fa47854a3094f4da6fe9d54d02/styleguide_example/files

View File

@ -1,5 +1,3 @@
import os
import boto3 import boto3
import requests import requests
from django.conf import settings from django.conf import settings
@ -48,8 +46,6 @@ class TestIntegrationsIntegrationTest(TestCase):
def test_s3_generate_presigned_url(self): def test_s3_generate_presigned_url(self):
# First, manually upload a file to S3 for testing # First, manually upload a file to S3 for testing
self.s3_client.upload_fileobj
self.s3_client.upload_fileobj( self.s3_client.upload_fileobj(
self.dummy_file, settings.AWS_STORAGE_BUCKET_NAME, "testfile.txt" self.dummy_file, settings.AWS_STORAGE_BUCKET_NAME, "testfile.txt"
) )

View File

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here. # Register your models here.

View File

@ -994,7 +994,7 @@ def _get_date_of_birth(data: Dict[str, Any]) -> str:
return "" return ""
elif date_of_birth is date or date_of_birth is datetime: elif date_of_birth is date or date_of_birth is datetime:
return date_of_birth.strftime("%d.%m.%Y") return date_of_birth.strftime("%d.%m.%Y")
elif type(date_of_birth) is str: elif isinstance(date_of_birth, str):
return date_of_birth return date_of_birth

View File

@ -17,9 +17,9 @@ from vbv_lernwelt.course_session.models import (
) )
from vbv_lernwelt.duedate.models import DueDate from vbv_lernwelt.duedate.models import DueDate
from vbv_lernwelt.importer.services import ( from vbv_lernwelt.importer.services import (
DataImportError,
create_or_update_course_session, create_or_update_course_session,
create_or_update_course_session_edoniq_test, create_or_update_course_session_edoniq_test,
DataImportError,
validate_row_data, validate_row_data,
) )
from vbv_lernwelt.importer.utils import ( from vbv_lernwelt.importer.utils import (

View File

@ -142,9 +142,7 @@ class SyncT2lTestCase(TestCase):
try: try:
sync_students_from_t2l(user_dict) sync_students_from_t2l(user_dict)
updated_user = CourseSessionUser.objects.get( CourseSessionUser.objects.get(user__email=self.user_dict["Email"])
user__email=self.user_dict["Email"]
)
except Exception as e: except Exception as e:
self.fail( self.fail(
f"SyncT2lTestCase.test_ignors_wrong_contract_number: An exception was unexpectedly raised: {str(e)}" f"SyncT2lTestCase.test_ignors_wrong_contract_number: An exception was unexpectedly raised: {str(e)}"

View File

@ -27,7 +27,7 @@ def try_parse_int(x: Any, default: Optional[Any] = None) -> Tuple[bool, Any]:
def try_parse_date( def try_parse_date(
value: Union[str, datetime.date] value: Union[str, datetime.date],
) -> Tuple[bool, Union[str, datetime.date]]: ) -> Tuple[bool, Union[str, datetime.date]]:
if isinstance(value, datetime.date): if isinstance(value, datetime.date):
return True, value return True, value
@ -59,7 +59,7 @@ def try_parse_date(
def try_parse_datetime( def try_parse_datetime(
value: Union[str, datetime.datetime] value: Union[str, datetime.datetime],
) -> Tuple[bool, Union[str, datetime.datetime]]: ) -> Tuple[bool, Union[str, datetime.datetime]]:
if isinstance(value, datetime.datetime): if isinstance(value, datetime.datetime):
return True, value return True, value

View File

@ -67,7 +67,7 @@ def handle_import(request, success_msg: str, importer: Callable[[str], None]):
excel_file = request.FILES["excel_file"] excel_file = request.FILES["excel_file"]
try: try:
importer(excel_file) importer(excel_file)
except Exception as e: except Exception:
return render( return render(
# it is a "power" feature, so we will output the traceback on error # it is a "power" feature, so we will output the traceback on error
request, request,

View File

@ -32,7 +32,7 @@ from vbv_lernwelt.learnpath.tests.learning_path_factories import (
LearningUnitFactory, LearningUnitFactory,
TopicFactory, TopicFactory,
) )
from vbv_lernwelt.learnpath.vv_circle_goals import GoalsType, VV_CIRCLE_GOALS from vbv_lernwelt.learnpath.vv_circle_goals import VV_CIRCLE_GOALS, GoalsType
# todo: remove when all Handlungsfelder are ready # todo: remove when all Handlungsfelder are ready
READY_HF = ["Fahrzeug", "Reisen"] READY_HF = ["Fahrzeug", "Reisen"]
@ -271,14 +271,16 @@ def create_circle_basis(lp, title="Basis", course_page=None):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Reflexion, Feedback", parent=circle) LearningUnitFactory(title="Reflexion, Feedback", parent=circle)
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"versicherungsvermittler-in-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith="versicherungsvermittler-in-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -334,13 +336,15 @@ def create_circle_gewinnen(lp, title="Gewinnen"):
title="Vom Lead zum Termin/Telefon auf Empfehlung/Neukundengewinnung", title="Vom Lead zum Termin/Telefon auf Empfehlung/Neukundengewinnung",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Mein Kundenstamm", LearningContentAssignmentFactory(
parent=circle, title="Mein Kundenstamm",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-mein-kundenstamm" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-mein-kundenstamm"
),
), ),
), )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title="Selbsteinschätzung", title="Selbsteinschätzung",
parent=circle, parent=circle,
@ -348,14 +352,16 @@ def create_circle_gewinnen(lp, title="Gewinnen"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Reflexion, Feedback", parent=circle) LearningUnitFactory(title="Reflexion, Feedback", parent=circle)
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -653,21 +659,23 @@ def create_circle_reisen(lp, title="Reisen"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle) LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Auswandern", title="Auswandern",
parent=circle, parent=circle,
) )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Fachcheck Reisen", title="Fachcheck Reisen",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -738,29 +746,33 @@ def create_circle_einkommenssicherung(lp, title="Einkommenssicherung"):
) )
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle) LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Heirat: Was ändert sich", LearningContentAssignmentFactory(
parent=circle, title="Heirat: Was ändert sich",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-heirat-was-ändert-sich" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-heirat-was-ändert-sich"
),
), ),
), )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Familienmanagerin", title="Familienmanagerin",
parent=circle, parent=circle,
) )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title="Fachcheck Einkommenssicherung", title="Fachcheck Einkommenssicherung",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -806,14 +818,16 @@ def create_circle_wohneigentum(lp, title="Wohneigentum"):
title="Fachcheck Wohneigentum", title="Fachcheck Wohneigentum",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -885,17 +899,19 @@ def create_circle_pensionierung(lp, title="Pensionierung"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle) LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Fachcheck Pensionierung", title="Fachcheck Pensionierung",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -927,32 +943,34 @@ def create_circle_erben(lp, title="Erben/Vererben"):
parent=circle, parent=circle,
) )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Guilia und Davide machen sich Gedanken", title="Guilia und Davide machen sich Gedanken",
parent=circle, parent=circle,
) )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Selbsteinschätzung", title="Selbsteinschätzung",
parent=circle, parent=circle,
) )
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle) LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Hausverkauf mit Erbvorbezug", title="Hausverkauf mit Erbvorbezug",
parent=circle, parent=circle,
) )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Fachcheck Erben/Vererben", title="Fachcheck Erben/Vererben",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -1024,25 +1042,29 @@ def create_circle_gesundheit(lp, title="Gesundheit"):
) )
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle) LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentAssignmentFactory( (
title="Krankenversicherung: Passt die Lösung noch?", LearningContentAssignmentFactory(
parent=circle, title="Krankenversicherung: Passt die Lösung noch?",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{course_slug}-assignment-krankenversicherung-passt-die-lösung-noch" content_assignment=Assignment.objects.get(
slug__startswith=f"{course_slug}-assignment-krankenversicherung-passt-die-lösung-noch"
),
), ),
), )
LearningContentPlaceholderFactory( LearningContentPlaceholderFactory(
title=f"Fachcheck Gesundheit", title="Fachcheck Gesundheit",
parent=circle, parent=circle,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=circle, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=circle,
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=circle, parent=circle,
) )
@ -1458,14 +1480,16 @@ def create_learning_sequence_transfer(parent, title, lc_praxis_title=None):
title=f"Fachcheck {title}", title=f"Fachcheck {title}",
parent=parent, parent=parent,
) )
LearningContentAssignmentFactory( (
title="Reflexion", LearningContentAssignmentFactory(
assignment_type="REFLECTION", title="Reflexion",
parent=parent, assignment_type="REFLECTION",
content_assignment=Assignment.objects.get( parent=parent,
slug__startswith=f"versicherungsvermittler-in-assignment-reflexion" content_assignment=Assignment.objects.get(
slug__startswith="versicherungsvermittler-in-assignment-reflexion"
),
), ),
), )
LearningContentFeedbackVVFactory( LearningContentFeedbackVVFactory(
parent=parent, parent=parent,
) )

View File

@ -1,5 +1,3 @@
import random
import graphene import graphene
import structlog import structlog
from graphene_django import DjangoObjectType from graphene_django import DjangoObjectType
@ -8,7 +6,6 @@ from vbv_lernwelt.core.utils import find_first_index
from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface
from vbv_lernwelt.learnpath.models import ( from vbv_lernwelt.learnpath.models import (
Circle, Circle,
CourseProfile,
LearningContentAssignment, LearningContentAssignment,
LearningContentAttendanceCourse, LearningContentAttendanceCourse,
LearningContentDocumentList, LearningContentDocumentList,

View File

@ -2,7 +2,6 @@
from django.db import migrations from django.db import migrations
VV_COURSE_IDS_WITH_MENTOR_FEEDBACK = [ VV_COURSE_IDS_WITH_MENTOR_FEEDBACK = [
-4, # vv-de -4, # vv-de
-10, # vv-fr -10, # vv-fr

View File

@ -172,9 +172,6 @@ class LearningSequence(CourseBasePage):
def __str__(self): def __str__(self):
return f"{self.title}" return f"{self.title}"
def get_admin_display_title(self):
return f"{self.icon} {self.draft_title}"
def get_admin_display_title_html(self): def get_admin_display_title_html(self):
return f""" return f"""
<span style="display: inline-flex; align-items: center; font-size: 1.25rem; font-weight: 700;"> <span style="display: inline-flex; align-items: center; font-size: 1.25rem; font-weight: 700;">

View File

@ -4,9 +4,9 @@ from wagtail.documents.models import AbstractDocument, Document
from wagtail.images.models import ( from wagtail.images.models import (
AbstractImage, AbstractImage,
AbstractRendition, AbstractRendition,
get_upload_to,
Image, Image,
WagtailImageField, WagtailImageField,
get_upload_to,
) )
from vbv_lernwelt.core.admin import User from vbv_lernwelt.core.admin import User
@ -67,9 +67,12 @@ class ContentImage(AbstractImage):
height_field="height", height_field="height",
storage=ContentImagesStorage, storage=ContentImagesStorage,
) )
admin_form_fields = Image.admin_form_fields + ( admin_form_fields = (
# Then add the field names here to make them appear in the form: Image.admin_form_fields
# 'caption', + (
# Then add the field names here to make them appear in the form:
# 'caption',
)
) )

View File

@ -1,6 +1,5 @@
from storages.backends.s3boto3 import S3Boto3Storage from storages.backends.s3boto3 import S3Boto3Storage
# inspired by https://theyashshahs.medium.com/aws-s3-signed-urls-in-django-d9e66853a42f # inspired by https://theyashshahs.medium.com/aws-s3-signed-urls-in-django-d9e66853a42f

View File

@ -4,7 +4,7 @@ from unittest import skipIf
from django.conf import settings from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import override_settings, TestCase from django.test import TestCase, override_settings
from wagtail.models import Collection from wagtail.models import Collection
from vbv_lernwelt.media_files.models import ContentDocument from vbv_lernwelt.media_files.models import ContentDocument

View File

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here. # Register your models here.

View File

@ -1,6 +1,6 @@
from wagtail.rich_text import RichText from wagtail.rich_text import RichText
from vbv_lernwelt.course.models import Course, CoursePage from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.media_library.tests.media_library_factories import ( from vbv_lernwelt.media_library.tests.media_library_factories import (
MediaLibraryCategoryPageFactory, MediaLibraryCategoryPageFactory,
MediaLibraryContentPageFactory, MediaLibraryContentPageFactory,
@ -10,7 +10,6 @@ from vbv_lernwelt.media_library.tests.media_library_factories import (
def create_default_media_library(course_id): def create_default_media_library(course_id):
course = Course.objects.get(id=course_id)
course_page = CoursePage.objects.get(course_id=course_id) course_page = CoursePage.objects.get(course_id=course_id)
media_lib_page = MediaLibraryPageFactory( media_lib_page = MediaLibraryPageFactory(
@ -59,9 +58,9 @@ def create_default_media_library(course_id):
die der Fahrzeugbesitzer und die Fahrzeugbesitzerin in einem grösseren Schadenfall oft nur schwer selbst aufbringen kann. die der Fahrzeugbesitzer und die Fahrzeugbesitzerin in einem grösseren Schadenfall oft nur schwer selbst aufbringen kann.
""".strip(), """.strip(),
body=RichText( body=RichText(
f"<h2>Lernmedien</h2>" "<h2>Lernmedien</h2>"
f"<h3>Allgemeines</h3>" "<h3>Allgemeines</h3>"
f"<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>" "<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>"
), ),
) )
@ -80,8 +79,8 @@ def create_default_media_library(course_id):
title=cat, title=cat,
parent=media_lib_allgemeines, parent=media_lib_allgemeines,
body=RichText( body=RichText(
f"<h2>Lernmedien</h2>" "<h2>Lernmedien</h2>"
f"<h3>Allgemeines</h3>" "<h3>Allgemeines</h3>"
f"<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>" "<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>"
), ),
) )

View File

@ -5,7 +5,6 @@ from django.utils.text import slugify
from wagtail.admin.panels import FieldPanel from wagtail.admin.panels import FieldPanel
from wagtail.documents.models import AbstractDocument, Document from wagtail.documents.models import AbstractDocument, Document
from wagtail.fields import RichTextField from wagtail.fields import RichTextField
from wagtail.models import Page
from vbv_lernwelt.core.constants import ( from vbv_lernwelt.core.constants import (
DEFAULT_RICH_TEXT_FEATURES, DEFAULT_RICH_TEXT_FEATURES,

View File

@ -12,8 +12,9 @@ class NotificationCategory(models.TextChoices):
class NotificationTrigger(models.TextChoices): class NotificationTrigger(models.TextChoices):
ATTENDANCE_COURSE_REMINDER = "ATTENDANCE_COURSE_REMINDER", _( ATTENDANCE_COURSE_REMINDER = (
"Attendance Course Reminder" "ATTENDANCE_COURSE_REMINDER",
_("Attendance Course Reminder"),
) )
ASSIGNMENT_REMINDER = "ASSIGNMENT_REMINDER", _("Assignment Reminder") ASSIGNMENT_REMINDER = "ASSIGNMENT_REMINDER", _("Assignment Reminder")
CASEWORK_EXPERT_EVALUATION_REMINDER = ( CASEWORK_EXPERT_EVALUATION_REMINDER = (
@ -24,11 +25,13 @@ class NotificationTrigger(models.TextChoices):
CASEWORK_EVALUATED = "CASEWORK_EVALUATED", _("Casework Evaluated") CASEWORK_EVALUATED = "CASEWORK_EVALUATED", _("Casework Evaluated")
NEW_FEEDBACK = "NEW_FEEDBACK", _("New Feedback") NEW_FEEDBACK = "NEW_FEEDBACK", _("New Feedback")
SELF_EVALUATION_FEEDBACK_REQUESTED = "SELF_EVALUATION_FEEDBACK_REQUESTED", _( SELF_EVALUATION_FEEDBACK_REQUESTED = (
"Self Evaluation Feedback Requested" "SELF_EVALUATION_FEEDBACK_REQUESTED",
_("Self Evaluation Feedback Requested"),
) )
SELF_EVALUATION_FEEDBACK_PROVIDED = "SELF_EVALUATION_FEEDBACK_PROVIDED", _( SELF_EVALUATION_FEEDBACK_PROVIDED = (
"Self Evaluation Feedback Provided" "SELF_EVALUATION_FEEDBACK_PROVIDED",
_("Self Evaluation Feedback Provided"),
) )

View File

@ -13,8 +13,8 @@ from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSession from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course_session.models import CourseSessionAssignment from vbv_lernwelt.course_session.models import CourseSessionAssignment
from vbv_lernwelt.notify.email.email_services import ( from vbv_lernwelt.notify.email.email_services import (
create_template_data_from_course_session_attendance_course,
EmailTemplate, EmailTemplate,
create_template_data_from_course_session_attendance_course,
format_swiss_datetime, format_swiss_datetime,
send_email, send_email,
) )

View File

@ -142,7 +142,7 @@ class TestAssignmentCourseRemindersTest(TestCase):
email_template = notification.data["email_template"] email_template = notification.data["email_template"]
# make sure we have the correct email template # make sure we have the correct email template
if type(action_object) == CourseSessionAssignment: if action_object is CourseSessionAssignment:
assignment_type = AssignmentType( assignment_type = AssignmentType(
action_object.learning_content.assignment_type action_object.learning_content.assignment_type
) )
@ -157,7 +157,7 @@ class TestAssignmentCourseRemindersTest(TestCase):
EmailTemplate.ASSIGNMENT_REMINDER_PREP_ASSIGNMENT_MEMBER.name, EmailTemplate.ASSIGNMENT_REMINDER_PREP_ASSIGNMENT_MEMBER.name,
email_template, email_template,
) )
elif type(action_object) == CourseSessionEdoniqTest: elif action_object is CourseSessionEdoniqTest:
self.assertEqual( self.assertEqual(
EmailTemplate.ASSIGNMENT_REMINDER_EDONIQ_MEMBER.name, EmailTemplate.ASSIGNMENT_REMINDER_EDONIQ_MEMBER.name,
email_template, email_template,

View File

@ -61,7 +61,7 @@ class TestNotificationApi(APITestCase):
def test_get_all_pagination(self): def test_get_all_pagination(self):
num_notifications = 322 num_notifications = 322
for i in range(num_notifications): for _ in range(num_notifications):
NotificationFactory( NotificationFactory(
recipient=self.alice, recipient=self.alice,
actor=self.john, actor=self.john,
@ -77,7 +77,7 @@ class TestNotificationApi(APITestCase):
def test_get_unread_pagination(self): def test_get_unread_pagination(self):
unread_notifications = 120 unread_notifications = 120
for i in range(unread_notifications): for _ in range(unread_notifications):
NotificationFactory( NotificationFactory(
recipient=self.alice, recipient=self.alice,
actor=self.john, actor=self.john,

View File

@ -65,9 +65,9 @@ class TestNotificationService(TestCase):
self.assertFalse(notification.emailed) self.assertFalse(notification.emailed)
def test_send_notification_with_email(self): def test_send_notification_with_email(self):
self.recipient.additional_json_data[ self.recipient.additional_json_data["email_notification_categories"] = (
"email_notification_categories" json.dumps(["USER_INTERACTION"])
] = json.dumps(["USER_INTERACTION"]) )
self.recipient.save() self.recipient.save()
verb = "Anne hat deinen Auftrag bewertet" verb = "Anne hat deinen Auftrag bewertet"
@ -146,9 +146,9 @@ class TestNotificationService(TestCase):
self.assertFalse(notification.emailed) self.assertFalse(notification.emailed)
# when the email was not sent, yet it will still send it afterwards... # when the email was not sent, yet it will still send it afterwards...
self.recipient.additional_json_data[ self.recipient.additional_json_data["email_notification_categories"] = (
"email_notification_categories" json.dumps(["USER_INTERACTION"])
] = json.dumps(["USER_INTERACTION"]) )
self.recipient.save() self.recipient.save()
result = self.notification_service._send_notification( result = self.notification_service._send_notification(
@ -188,9 +188,9 @@ class TestNotificationService(TestCase):
self.assertFalse(self._has_sent_emails()) self.assertFalse(self._has_sent_emails())
# Assert mail is sent if corresponding email notification type is enabled # Assert mail is sent if corresponding email notification type is enabled
self.recipient.additional_json_data[ self.recipient.additional_json_data["email_notification_categories"] = (
"email_notification_categories" json.dumps(["USER_INTERACTION"])
] = json.dumps(["USER_INTERACTION"]) )
self.recipient.save() self.recipient.save()
self.notification_service._send_notification( self.notification_service._send_notification(
sender=self.sender, sender=self.sender,

View File

@ -7,7 +7,7 @@ from vbv_lernwelt.self_evaluation_feedback.models import (
@admin.register(SelfEvaluationFeedback) @admin.register(SelfEvaluationFeedback)
class CourseSessionAdmin(admin.ModelAdmin): class SelfEvaluationFeedbackAdmin(admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"feedback_submitted", "feedback_submitted",
@ -30,7 +30,7 @@ class CourseSessionAdmin(admin.ModelAdmin):
@admin.register(CourseCompletionFeedback) @admin.register(CourseCompletionFeedback)
class CourseSessionAdmin(admin.ModelAdmin): class CourseCompletionFeedbackAdmin(admin.ModelAdmin):
list_display = ( list_display = (
"id", "id",
"feedback", "feedback",

View File

@ -39,9 +39,9 @@ class SelfEvaluationFeedbackSerializer(serializers.ModelSerializer):
return obj.learning_unit.get_circle().title return obj.learning_unit.get_circle().title
def get_criteria(self, obj): def get_criteria(self, obj):
performance_criteria: List[ performance_criteria: List[PerformanceCriteria] = (
PerformanceCriteria obj.learning_unit.performancecriteria_set.all()
] = obj.learning_unit.performancecriteria_set.all() )
criteria = [] criteria = []

View File

@ -28,7 +28,7 @@ class CheckoutInformationAdmin(admin.ModelAdmin):
success = False success = False
if not success: if not success:
self.message_user( self.message_user(
request, f"Beim SFTP upload ist ein Fehler aufgetreten", level="error" request, "Beim SFTP upload ist ein Fehler aufgetreten", level="error"
) )
@admin.action(description="Buchungsbestätigung: Bestätigung erneut senden") @admin.action(description="Buchungsbestätigung: Bestätigung erneut senden")

View File

@ -88,15 +88,15 @@ class AbacusInvoiceTestCase(TestCase):
<SalesOrderHeader mode="SAVE"> <SalesOrderHeader mode="SAVE">
<SalesOrderHeaderFields mode="SAVE"> <SalesOrderHeaderFields mode="SAVE">
<CustomerNumber>60000012</CustomerNumber> <CustomerNumber>60000012</CustomerNumber>
<ProcessFlowNumber>30</ProcessFlowNumber> <ProcessFlowNumber>30</ProcessFlowNumber>
<PaymentCode>9999</PaymentCode> <PaymentCode>9999</PaymentCode>
<PurchaseOrderDate>2024-02-15</PurchaseOrderDate> <PurchaseOrderDate>2024-02-15</PurchaseOrderDate>
<ReferencePurchaseOrder>24021508331287484</ReferencePurchaseOrder> <ReferencePurchaseOrder>24021508331287484</ReferencePurchaseOrder>
<GroupingNumberAscii1>6000000001</GroupingNumberAscii1> <GroupingNumberAscii1>6000000001</GroupingNumberAscii1>
</SalesOrderHeaderFields> </SalesOrderHeaderFields>
<Item mode="SAVE"> <Item mode="SAVE">
<ItemFields mode="SAVE"> <ItemFields mode="SAVE">
<DeliveryDate>2024-02-15</DeliveryDate> <DeliveryDate>2024-02-15</DeliveryDate>
<ItemNumber>1</ItemNumber> <ItemNumber>1</ItemNumber>
<ProductNumber>30202</ProductNumber> <ProductNumber>30202</ProductNumber>
<QuantityOrdered>1</QuantityOrdered> <QuantityOrdered>1</QuantityOrdered>

View File

@ -1,13 +1,13 @@
import uuid import uuid
from unittest.mock import patch from unittest.mock import patch
from django.test import override_settings, TestCase from django.test import TestCase, override_settings
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User
from vbv_lernwelt.shop.services import ( from vbv_lernwelt.shop.services import (
InitTransactionException,
get_payment_url, get_payment_url,
init_datatrans_transaction, init_datatrans_transaction,
InitTransactionException,
) )
REDIRECT_URL = "http://testserver/redirect-url" REDIRECT_URL = "http://testserver/redirect-url"

View File

@ -19,12 +19,12 @@ from vbv_lernwelt.shop.const import (
) )
from vbv_lernwelt.shop.models import CheckoutInformation, CheckoutState, Product from vbv_lernwelt.shop.models import CheckoutInformation, CheckoutState, Product
from vbv_lernwelt.shop.services import ( from vbv_lernwelt.shop.services import (
InitTransactionException,
create_context_data_log, create_context_data_log,
datatrans_state_to_checkout_state, datatrans_state_to_checkout_state,
get_payment_url, get_payment_url,
get_vv_payment_email_template, get_vv_payment_email_template,
init_datatrans_transaction, init_datatrans_transaction,
InitTransactionException,
is_signature_valid, is_signature_valid,
) )

View File

@ -1,5 +1,6 @@
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.auth import admin as auth_admin, get_user_model from django.contrib.auth import admin as auth_admin
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from keycloak.exceptions import KeycloakDeleteError, KeycloakPostError from keycloak.exceptions import KeycloakDeleteError, KeycloakPostError

View File

@ -1,6 +1,6 @@
from unittest.mock import patch from unittest.mock import patch
from django.test import override_settings, TestCase from django.test import TestCase, override_settings
from keycloak.exceptions import KeycloakDeleteError, KeycloakPostError from keycloak.exceptions import KeycloakDeleteError, KeycloakPostError
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User

View File

@ -5,7 +5,7 @@ from unittest.mock import ANY, MagicMock, patch
from authlib.integrations.base_client import OAuthError from authlib.integrations.base_client import OAuthError
from django.shortcuts import redirect from django.shortcuts import redirect
from django.test import override_settings, TestCase from django.test import TestCase, override_settings
from django.urls import reverse from django.urls import reverse
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User

View File

@ -1,7 +1,6 @@
from django.urls import path from django.urls import path
from ..core.middleware.auth import django_view_authentication_exempt from ..core.middleware.auth import django_view_authentication_exempt
from . import views from . import views
app_name = "sso" app_name = "sso"