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
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'
(cd client && npm run lint:errors && npm run typecheck)
echo 'python ufmt check'
ufmt check server
echo 'ruff check'
ruff check server
echo 'ruff format --check'
ruff format server --check
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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ from .base import * # noqa
# GENERAL
# ------------------------------------------------------------------------------
# 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_PAY_URL = "http://localhost:8001/server/fakeapi/datatrans/pay"
@ -26,7 +26,7 @@ CYPRESS_TEST = True
# Your stuff...
# ------------------------------------------------------------------------------
REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = {
REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = { # noqa F405
"anon": "10000/day",
"hour-throttle": "40000/hour",
"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_ratelimit.exceptions import Ratelimited
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.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_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):
@ -99,7 +99,7 @@ def raise_example_error(request):
"""
raise Exception("Test Error: I know python!")
# pylint: disable=unreachable
return HttpResponse("no error?")
return HttpResponse("no error?") # noqa F821
# fmt: off
@ -241,7 +241,7 @@ urlpatterns = [
# testing and debug
path('server/raise_error/',
user_passes_test(lambda u: u.is_superuser, login_url='/login/')(
raise_example_error), ),
raise_example_error) ),
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):

View File

@ -15,7 +15,7 @@ if __name__ == "__main__":
try:
import django # noqa
except ImportError:
raise ImportError(
raise ImportError( # noqa
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"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 (
AssignmentListPage,
AssignmentType,
@ -21,9 +25,6 @@ from vbv_lernwelt.course.consts import (
)
from vbv_lernwelt.course.models import CoursePage
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(

View File

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

View File

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

View File

@ -222,7 +222,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
self.course_session,
)
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
@ -268,7 +268,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
),
)
ac = AssignmentCompletion.objects.create(
AssignmentCompletion.objects.create(
assignment_user=self.student,
assignment=self.assignment,
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(
assignment_user=self.user,
assignment=self.assignment,
@ -403,7 +403,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
),
)
ac = AssignmentCompletion.objects.create(
AssignmentCompletion.objects.create(
assignment_user=self.user,
assignment=self.assignment,
course_session=self.course_session,
@ -471,7 +471,7 @@ class UpdateAssignmentCompletionTestCase(TestCase):
evaluation_user=self.trainer,
)
with self.assertRaises(serializers.ValidationError) as error:
with self.assertRaises(serializers.ValidationError):
# not setting grade will raise an error
update_assignment_completion(
assignment_user=self.user,

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
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 vbv_lernwelt.core.models import (
@ -44,13 +45,13 @@ def create_or_sync_berufsbildner(modeladmin, request, queryset):
messages.add_message(
request,
messages.SUCCESS,
f"Berufsbildner erfolgreich erstellt oder synchronisiert",
"Berufsbildner erfolgreich erstellt oder synchronisiert",
)
else:
messages.add_message(
request,
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 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 (
ADMIN_USER_ID,
TEST_BERUFSBILDNER1_USER_ID,
@ -25,7 +19,12 @@ from vbv_lernwelt.core.constants import (
TEST_USER_DATATRANS_HANNA_ID,
TEST_USER_EMPTY_ID,
)
from vbv_lernwelt.core.model_utils import add_countries
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"
@ -432,7 +431,6 @@ def create_default_users(default_password="test", set_avatar=False):
def _get_or_create_user(user_model, *args, **kwargs):
username = kwargs.get("username", None)
password = kwargs.get("password", None)
language = kwargs.get("language", "de")
id = kwargs.get("id", None)
created = False

View File

@ -1,7 +1,7 @@
from datetime import datetime
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.db import connection
from django.utils import timezone

View File

@ -23,7 +23,12 @@ from vbv_lernwelt.course_session.models import (
CourseSessionEdoniqTest,
)
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 (
AgentParticipantRelation,
AgentParticipantRoleType,
@ -32,12 +37,6 @@ from vbv_lernwelt.learnpath.models import Circle
from vbv_lernwelt.notify.models import Notification
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_UK_TEST_COURSE = "Iterativ üK Testkurs"
@ -113,7 +112,7 @@ def delete_cs_data(cs: CourseSession):
else:
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(

View File

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

View File

@ -1,7 +1,7 @@
from collections import deque
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 slugify import slugify
from wagtail.rich_text import RichText
@ -454,9 +454,9 @@ def create_edoniq_test_result_data(
max_points=24,
evaluation_points_deducted=0,
):
assignment.assignment.evaluation_tasks.raw_data[0]["value"][
"max_points"
] = max_points
assignment.assignment.evaluation_tasks.raw_data[0]["value"]["max_points"] = (
max_points
)
assignment.assignment.save()
if assignment and course_session and assignment_user:
ac, _ = update_assignment_completion(
@ -855,7 +855,6 @@ def create_test_competence_navi():
def create_test_media_library():
course = Course.objects.get(id=COURSE_TEST_ID)
course_page = CoursePage.objects.get(course_id=COURSE_TEST_ID)
media_lib_page = MediaLibraryPageFactory(

View File

@ -30,11 +30,6 @@ from vbv_lernwelt.learnpath.tests.learning_path_factories import (
LearningUnitFactory,
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 (
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>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(
@ -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)
LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen",
title="Allgemeines zu Versicherungen",
parent=circle,
description=RichText(
f"<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>In der Mediathek unter «Allgemeines zu Versicherungen» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</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",
assignment_type="PREP_ASSIGNMENT",
parent=circle,
content_assignment=Assignment.objects.get(
slug__startswith=f"überbetriebliche-kurse-assignment-circle-kickoff"
slug__startswith="überbetriebliche-kurse-assignment-circle-kickoff"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -382,14 +379,16 @@ In diesem Circle erfährst du wie die überbetrieblichen Kurse aufgebaut sind. Z
slug__startswith="überbetriebliche-kurse-assignment-redlichkeits"
),
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
parent=circle,
content_assignment=Assignment.objects.get(
slug__startswith=f"überbetriebliche-kurse-assignment-reflexion"
slug__startswith="überbetriebliche-kurse-assignment-reflexion"
),
),
)
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")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen",
title="Allgemeines zu Versicherungen",
parent=circle,
description=RichText(
f"<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>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</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",
)
(
LearningContentAssignmentFactory(
title="Mission de préparation",
assignment_type="PREP_ASSIGNMENT",
parent=circle,
content_assignment=Assignment.objects.get(
slug__startswith=f"cours-interentreprises-assignment-circle-lancement",
slug__startswith="cours-interentreprises-assignment-circle-lancement",
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -497,6 +498,7 @@ Dans ce cercle, tu apprendras comment les cours interentreprises sont structuré
slug__startswith=f"{circle.get_course().slug}-assignment-redlichkeits"
),
)
(
LearningContentAssignmentFactory(
title="Réflexion",
assignment_type="REFLECTION",
@ -505,6 +507,7 @@ Dans ce cercle, tu apprendras comment les cours interentreprises sont structuré
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
def create_uk_it_circle_kickoff(lp, title="Introduzione"):
@ -521,14 +524,15 @@ In questo Circle imparerai come sono strutturati i corsi interaziendali. Imparer
)
LearningUnitFactory(title="Preparazione", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen",
title="Allgemeines zu Versicherungen",
parent=circle,
description=RichText(
f"<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>Nella mediateca, sotto il campo d'azione «Allgemeines zu Versicherungen», troverai tutte le risorse rilevanti per le tue competenze professionali."
"<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",
)
(
LearningContentAssignmentFactory(
title="Incarico di preparazione",
assignment_type="PREP_ASSIGNMENT",
@ -537,6 +541,7 @@ In questo Circle imparerai come sono strutturati i corsi interaziendali. Imparer
slug__startswith=f"{circle.get_course().slug}-assignment-circle-introduzione-incarico-di-preparazione"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -612,6 +617,7 @@ In questo Circle imparerai come sono strutturati i corsi interaziendali. Imparer
slug__startswith="überbetriebliche-kurse-assignment-redlichkeits"
),
)
(
LearningContentAssignmentFactory(
title="Riflessione",
assignment_type="REFLECTION",
@ -620,6 +626,7 @@ In questo Circle imparerai come sono strutturati i corsi interaziendali. Imparer
slug__startswith=f"{circle.get_course().slug}-assignment-riflessione"
),
),
)
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)
LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen",
title="Allgemeines zu Versicherungen",
parent=circle,
description=RichText(
f"<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>In der Mediathek unter «Allgemeines zu Versicherungen» findest du alle relevanten Ressourcen für deine Fachkompetenzen.</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",
assignment_type="PREP_ASSIGNMENT",
parent=circle,
content_assignment=Assignment.objects.get(
slug__startswith=f"überbetriebliche-kurse-assignment-circle-basis"
slug__startswith="überbetriebliche-kurse-assignment-circle-basis"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -724,14 +733,16 @@ In diesem Circle lernst du die wichtigsten Grundlagen bezüglich Versicherungswi
),
)
LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
parent=circle,
content_assignment=Assignment.objects.get(
slug__startswith=f"überbetriebliche-kurse-assignment-reflexion"
slug__startswith="überbetriebliche-kurse-assignment-reflexion"
),
),
)
def create_uk_fr_circle_basis(lp, title="Base"):
@ -746,14 +757,15 @@ 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")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen",
title="Allgemeines zu Versicherungen",
parent=circle,
description=RichText(
f"<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>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</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",
)
(
LearningContentAssignmentFactory(
title="Mandats préparatoires Circle Base",
assignment_type="PREP_ASSIGNMENT",
@ -762,6 +774,7 @@ Dans ce cercle, tu apprends les bases les plus importantes en matière d'assuran
slug__startswith=f"{circle.get_course().slug}-assignment-circle-base"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -833,6 +846,7 @@ 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",
)
LearningUnitFactory(title="Réflexion", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Réflexion",
assignment_type="REFLECTION",
@ -841,6 +855,7 @@ Dans ce cercle, tu apprends les bases les plus importantes en matière d'assuran
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
def create_uk_it_circle_basis(lp, title="Base"):
@ -855,14 +870,15 @@ In questo Circle imparerai le basi più importanti del settore assicurativo e de
LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory(
title=f"Allgemeines zu Versicherungen",
title="Allgemeines zu Versicherungen",
parent=circle,
description=RichText(
f"<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>Nella mediateca, sotto il campo d'azione «Allgemeines zu Versicherungen», troverai tutte le risorse rilevanti per le tue competenze professionali."
"<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",
)
(
LearningContentAssignmentFactory(
title="Mandato di preparazione Circle Base",
assignment_type="PREP_ASSIGNMENT",
@ -871,6 +887,7 @@ In questo Circle imparerai le basi più importanti del settore assicurativo e de
slug__startswith=f"{circle.get_course().slug}-assignment-cercle-base"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -942,6 +959,7 @@ 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",
)
LearningUnitFactory(title="Riflessione", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Riflessione",
assignment_type="REFLECTION",
@ -950,6 +968,7 @@ In questo Circle imparerai le basi più importanti del settore assicurativo e de
slug__startswith=f"{circle.get_course().slug}-assignment-riflessione"
),
),
)
def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
@ -971,8 +990,9 @@ 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>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",
assignment_type="PREP_ASSIGNMENT",
@ -981,6 +1001,7 @@ def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
slug__startswith=f"{course_slug}-assignment-fahrzeug-mein-erstes-auto"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Präsenzkurs", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -1070,6 +1091,7 @@ def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Kompetenznachweis", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Überprüfen einer Motorfahrzeug-Versicherungspolice",
parent=circle,
@ -1077,7 +1099,9 @@ def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
slug__startswith=f"{course_slug}-assignment-überprüfen-einer-motorfahrzeugs"
),
),
)
LearningUnitFactory(title="Reflexion", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -1086,6 +1110,7 @@ def create_uk_circle_fahrzeug(lp, title="Fahrzeug"):
slug__startswith=f"{course_slug}-assignment-reflexion"
),
),
)
def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
@ -1099,14 +1124,15 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
LearningSequenceFactory(title="Préparation", parent=circle, icon="it-icon-ls-start")
LearningUnitFactory(title="Préparation", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory(
title=f"Champs daction «Véhicule à moteur»",
title="Champs daction «Véhicule à moteur»",
parent=circle,
description=RichText(
f"<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>Trouve toutes les ressources des champs daction, comme les outils didactiques, les liens et autres informations utiles.</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",
)
(
LearningContentAssignmentFactory(
title="Véhicule à moteur Ma première voiture",
assignment_type="PREP_ASSIGNMENT",
@ -1115,6 +1141,7 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
slug__startswith=f"{course_slug}-assignment-véhicule-à-moteur-ma-première-voiture"
),
),
)
LearningSequenceFactory(title="Training", parent=circle)
LearningUnitFactory(title="Cours de présence", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -1206,6 +1233,7 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
LearningUnitFactory(
title="Contrôle de compétences", title_hidden=True, parent=circle
)
(
LearningContentAssignmentFactory(
title="Vérification d'une police dassurance de véhicule à moteur",
parent=circle,
@ -1213,7 +1241,9 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
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)
(
LearningContentAssignmentFactory(
title="Réflexion",
assignment_type="REFLECTION",
@ -1222,6 +1252,7 @@ def create_uk_fr_circle_fahrzeug(lp, title="Véhicule"):
slug__startswith=f"{course_slug}-assignment-reflexion"
),
),
)
def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
@ -1237,14 +1268,15 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
)
LearningUnitFactory(title="Preparazione", title_hidden=True, parent=circle)
LearningContentMediaLibraryFactory(
title=f"Campo dazione «Veicolo»",
title="Campo dazione «Veicolo»",
parent=circle,
description=RichText(
f"<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>Nella mediateca, sotto il campo d'azione «Veicolo», troverai tutte le risorse rilevanti per le tue competenze professionali.</p>"
"<p>Si consiglia di leggere l'argomento prima di completare le altre unità di apprendimento.</p>"
),
content_url=f"/course/{course_slug}/media",
)
(
LearningContentAssignmentFactory(
title="Veicolo, la mia prima auto",
assignment_type="PREP_ASSIGNMENT",
@ -1253,6 +1285,7 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
slug__startswith=f"{course_slug}-assignment-veicolo-la-mia-prima-auto"
),
),
)
LearningSequenceFactory(title="Formazione", parent=circle)
LearningUnitFactory(title="Corso di presenza", title_hidden=True, parent=circle)
LearningContentAttendanceCourseFactory(
@ -1344,6 +1377,7 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
LearningUnitFactory(
title="Controllo delle competenze", title_hidden=True, parent=circle
)
(
LearningContentAssignmentFactory(
title="Verifica di una polizza di assicurazione veicoli a motore",
parent=circle,
@ -1351,7 +1385,9 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
slug__startswith=f"{course_slug}-assignment-verifica-di-una-polizza-di-assicurazione-veicoli-a-motore"
),
),
)
LearningUnitFactory(title="Riflessione", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Riflessione",
assignment_type="REFLECTION",
@ -1360,3 +1396,4 @@ def create_uk_it_circle_fahrzeug(lp, title="Veicolo"):
slug__startswith=f"{course_slug}-assignment-riflessione"
),
),
)

View File

@ -1,7 +1,6 @@
import graphene
from vbv_lernwelt.core.utils import get_django_content_type
from vbv_lernwelt.learnpath.models import Circle
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.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.models import Circle, CourseProfile

View File

@ -3,7 +3,7 @@ import random
from datetime import datetime, timedelta
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 vbv_lernwelt.assignment.creators.create_assignments import (

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ class CourseCompletionApiTestCase(APITestCase):
self.client.login(username="student", password="test")
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(len(response.json()), 0)
@ -34,7 +34,7 @@ class CourseCompletionApiTestCase(APITestCase):
course_session=self.course_session,
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(len(response.json()), 1)
@ -44,7 +44,7 @@ class CourseCompletionApiTestCase(APITestCase):
def test_api_superUser_canAccessEveryCourseSession(self):
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(len(response.json()), 1)

View File

@ -56,7 +56,7 @@ class DocumentUploadApiTestCase(APITestCase):
)
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.assertNotEqual(response.data["url"], "")
@ -81,7 +81,7 @@ class DocumentUploadApiTestCase(APITestCase):
slug="test-lehrgang-lp-circle-reisen-ls-analyse"
)
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)
@ -91,7 +91,7 @@ class DocumentUploadApiTestCase(APITestCase):
slug="test-lehrgang-lp-circle-fahrzeug-ls-vorbereitung"
)
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)
@ -100,13 +100,13 @@ class DocumentUploadApiTestCase(APITestCase):
slug="test-lehrgang-lp-circle-fahrzeug-ls-vorbereitung"
)
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)
file_id = response.data["file_id"]
response = self.client.post(
f"/api/core/file/finish/",
"/api/core/file/finish/",
{
"file_id": file_id,
},
@ -129,7 +129,7 @@ class DocumentUploadApiTestCase(APITestCase):
file.full_clean()
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)

View File

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

View File

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

View File

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

View File

@ -4,5 +4,4 @@ from vbv_lernwelt.course_session_group.models import 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.

View File

@ -107,7 +107,7 @@ class DashboardQuery(graphene.ObjectType):
coursesessionuser__user=user,
coursesessionuser__role=CourseSessionUser.Role.EXPERT,
).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
@ -119,9 +119,7 @@ class DashboardQuery(graphene.ObjectType):
course_session_selection_ids=list(course_session_ids), # noqa
)
def resolve_mentor_course_statistics(
root, info, course_id: str, agent_role: str
): # noqa
def resolve_mentor_course_statistics(root, info, course_id: str, agent_role: str): # noqa
user = info.context.user
return _agent_course_statistics(user, course_id, role=agent_role)
@ -173,7 +171,7 @@ class DashboardQuery(graphene.ObjectType):
user = info.context.user
course = Course.objects.get(id=course_id)
setattr(info.context, "course", course)
setattr(info.context, "course", course) # noqa: B010
newest: CourseSession | None = None
course_session_for_user: List[str] = []

View File

@ -120,7 +120,7 @@ def get_assignment_completion_metrics(
)
key = f"CourseSessionUsers_{course_session.id}"
if not key in context:
if key not in context:
if 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}"
if not key in context:
if key not in context:
context[key] = course_session_assignment.learning_content.get_circle().id
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.models import CourseSession, CourseSessionUser
from vbv_lernwelt.dashboard.graphql.types.assignment import (
assignments,
AssignmentsStatisticsType,
assignments,
)
from vbv_lernwelt.dashboard.graphql.types.attendance import (
attendance_day_presences,
AttendanceDayPresencesStatisticsType,
attendance_day_presences,
)
from vbv_lernwelt.dashboard.graphql.types.competence import (
CompetencePerformanceStatisticsSummaryType,
competences,
CompetencesStatisticsType,
competences,
)
from vbv_lernwelt.dashboard.graphql.types.feedback import (
feedback_responses,
FeedbackStatisticsResponsesType,
feedback_responses,
)
from vbv_lernwelt.learnpath.models import Circle
@ -201,7 +201,8 @@ class CourseStatisticsType(BaseStatisticsType):
records, success_total, fail_total = competences(
course_slug=str(root.course_slug),
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
circle_ids=root.get_circle_ids(info), # noqa

View File

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

View File

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

View File

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

View File

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

View File

@ -77,15 +77,15 @@ class DashboardTestCase(GraphQLTestCase):
self.client.force_login(cs_1_ab_supervisor)
# WHEN
query = f"""query($course_id: ID!) {{
course_statistics(course_id: $course_id) {{
course_session_selection_metrics {{
query = """query($course_id: ID!) {
course_statistics(course_id: $course_id) {
course_session_selection_metrics {
expert_count
participant_count
session_count
}}
}}
}}"""
}
}
}"""
variables = {"course_id": str(course_1.id)}
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
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)
participant_user = relation.participant.user
@ -161,7 +161,7 @@ def create_person_list_with_roles(
participant__course_session_id=cs.id,
role="LEARNING_MENTOR",
):
_add_agent_relation("LEARNING_MENTOR", "PARTICIPANT")
_add_agent_relation(cs, relation, "LEARNING_MENTOR", "PARTICIPANT")
if "BERUFSBILDNER" in cs.roles:
for relation in AgentParticipantRelation.objects.filter(
@ -169,7 +169,7 @@ def create_person_list_with_roles(
participant__course_session_id=cs.id,
role="BERUFSBILDNER",
):
_add_agent_relation("BERUFSBILDNER", "PARTICIPANT")
_add_agent_relation(cs, relation, "BERUFSBILDNER", "PARTICIPANT")
# add persons where request.user is lerning mentee
mentor_relation_qs = AgentParticipantRelation.objects.filter(

View File

@ -31,7 +31,7 @@ from vbv_lernwelt.course_session.services.export_attendance import (
export_attendance,
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 (
CourseSessionWithRoles,
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.serializers import DueDateSerializer
from vbv_lernwelt.feedback.export import (
export_feedback_with_circle_restriction,
FEEDBACK_EXPORT_FILE_NAME,
export_feedback_with_circle_restriction,
)
from vbv_lernwelt.learning_mentor.models import (
AgentParticipantRelation,
@ -346,9 +346,7 @@ def get_mentor_open_tasks_count(request, course_id: str):
return Response(
status=200,
data={
"open_task_count": _get_mentor_open_tasks_count(
course_id, request.user
) # noqa
"open_task_count": _get_mentor_open_tasks_count(course_id, request.user) # noqa
},
)
except PermissionDenied as e:

View File

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

View File

@ -58,7 +58,7 @@ def load_edoniq_test_results_csv_data():
if __name__ == "__main__":
csv_data = load_edoniq_test_results_csv_data()
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":
# print(row)
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.course.creators.test_course import create_test_course
from vbv_lernwelt.edoniq_test.result_import.services import (
create_edoniq_csv_test_result,
EdoniqCsvTestResult,
create_edoniq_csv_test_result,
filter_relevant_rows,
get_distinct_course_release_ids,
upsert_edoniq_test_result,

View File

@ -100,14 +100,6 @@ def export_students_and_trainers(request):
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(
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:
response = HttpResponse(content_type="text/csv; charset=utf-8")
response[
"Content-Disposition"
] = f"attachment; filename=edoniq_user_export_{date.today().strftime('%Y%m%d')}.csv"
response["Content-Disposition"] = (
f"attachment; filename=edoniq_user_export_{date.today().strftime('%Y%m%d')}.csv"
)
response.write("\ufeff".encode("utf8")) # UTF-8 BOM

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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.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.utils import file_generate_upload_path
# 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

View File

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

View File

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

View File

@ -994,7 +994,7 @@ def _get_date_of_birth(data: Dict[str, Any]) -> str:
return ""
elif date_of_birth is date or date_of_birth is datetime:
return date_of_birth.strftime("%d.%m.%Y")
elif type(date_of_birth) is str:
elif isinstance(date_of_birth, str):
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.importer.services import (
DataImportError,
create_or_update_course_session,
create_or_update_course_session_edoniq_test,
DataImportError,
validate_row_data,
)
from vbv_lernwelt.importer.utils import (

View File

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

View File

@ -27,7 +27,7 @@ def try_parse_int(x: Any, default: Optional[Any] = None) -> Tuple[bool, Any]:
def try_parse_date(
value: Union[str, datetime.date]
value: Union[str, datetime.date],
) -> Tuple[bool, Union[str, datetime.date]]:
if isinstance(value, datetime.date):
return True, value
@ -59,7 +59,7 @@ def try_parse_date(
def try_parse_datetime(
value: Union[str, datetime.datetime]
value: Union[str, datetime.datetime],
) -> Tuple[bool, Union[str, datetime.datetime]]:
if isinstance(value, datetime.datetime):
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"]
try:
importer(excel_file)
except Exception as e:
except Exception:
return render(
# it is a "power" feature, so we will output the traceback on error
request,

View File

@ -32,7 +32,7 @@ from vbv_lernwelt.learnpath.tests.learning_path_factories import (
LearningUnitFactory,
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
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")
LearningUnitFactory(title="Reflexion, Feedback", parent=circle)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
parent=circle,
content_assignment=Assignment.objects.get(
slug__startswith=f"versicherungsvermittler-in-assignment-reflexion"
slug__startswith="versicherungsvermittler-in-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -334,6 +336,7 @@ def create_circle_gewinnen(lp, title="Gewinnen"):
title="Vom Lead zum Termin/Telefon auf Empfehlung/Neukundengewinnung",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Mein Kundenstamm",
parent=circle,
@ -341,6 +344,7 @@ def create_circle_gewinnen(lp, title="Gewinnen"):
slug__startswith=f"{course_slug}-assignment-mein-kundenstamm"
),
),
)
LearningContentPlaceholderFactory(
title="Selbsteinschätzung",
parent=circle,
@ -348,6 +352,7 @@ def create_circle_gewinnen(lp, title="Gewinnen"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Reflexion, Feedback", parent=circle)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -356,6 +361,7 @@ def create_circle_gewinnen(lp, title="Gewinnen"):
slug__startswith=f"{course_slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -653,13 +659,14 @@ def create_circle_reisen(lp, title="Reisen"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentPlaceholderFactory(
title=f"Auswandern",
title="Auswandern",
parent=circle,
)
LearningContentPlaceholderFactory(
title=f"Fachcheck Reisen",
title="Fachcheck Reisen",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -668,6 +675,7 @@ def create_circle_reisen(lp, title="Reisen"):
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -738,6 +746,7 @@ def create_circle_einkommenssicherung(lp, title="Einkommenssicherung"):
)
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Heirat: Was ändert sich",
parent=circle,
@ -745,14 +754,16 @@ def create_circle_einkommenssicherung(lp, title="Einkommenssicherung"):
slug__startswith=f"{course_slug}-assignment-heirat-was-ändert-sich"
),
),
)
LearningContentPlaceholderFactory(
title=f"Familienmanagerin",
title="Familienmanagerin",
parent=circle,
)
LearningContentPlaceholderFactory(
title="Fachcheck Einkommenssicherung",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -761,6 +772,7 @@ def create_circle_einkommenssicherung(lp, title="Einkommenssicherung"):
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -806,6 +818,7 @@ def create_circle_wohneigentum(lp, title="Wohneigentum"):
title="Fachcheck Wohneigentum",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -814,6 +827,7 @@ def create_circle_wohneigentum(lp, title="Wohneigentum"):
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -885,9 +899,10 @@ def create_circle_pensionierung(lp, title="Pensionierung"):
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentPlaceholderFactory(
title=f"Fachcheck Pensionierung",
title="Fachcheck Pensionierung",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -896,6 +911,7 @@ def create_circle_pensionierung(lp, title="Pensionierung"):
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -927,24 +943,25 @@ def create_circle_erben(lp, title="Erben/Vererben"):
parent=circle,
)
LearningContentPlaceholderFactory(
title=f"Guilia und Davide machen sich Gedanken",
title="Guilia und Davide machen sich Gedanken",
parent=circle,
)
LearningContentPlaceholderFactory(
title=f"Selbsteinschätzung",
title="Selbsteinschätzung",
parent=circle,
)
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
LearningContentPlaceholderFactory(
title=f"Hausverkauf mit Erbvorbezug",
title="Hausverkauf mit Erbvorbezug",
parent=circle,
)
LearningContentPlaceholderFactory(
title=f"Fachcheck Erben/Vererben",
title="Fachcheck Erben/Vererben",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -953,6 +970,7 @@ def create_circle_erben(lp, title="Erben/Vererben"):
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -1024,6 +1042,7 @@ def create_circle_gesundheit(lp, title="Gesundheit"):
)
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", title_hidden=True, parent=circle)
(
LearningContentAssignmentFactory(
title="Krankenversicherung: Passt die Lösung noch?",
parent=circle,
@ -1031,10 +1050,12 @@ def create_circle_gesundheit(lp, title="Gesundheit"):
slug__startswith=f"{course_slug}-assignment-krankenversicherung-passt-die-lösung-noch"
),
),
)
LearningContentPlaceholderFactory(
title=f"Fachcheck Gesundheit",
title="Fachcheck Gesundheit",
parent=circle,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
@ -1043,6 +1064,7 @@ def create_circle_gesundheit(lp, title="Gesundheit"):
slug__startswith=f"{circle.get_course().slug}-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=circle,
)
@ -1458,14 +1480,16 @@ def create_learning_sequence_transfer(parent, title, lc_praxis_title=None):
title=f"Fachcheck {title}",
parent=parent,
)
(
LearningContentAssignmentFactory(
title="Reflexion",
assignment_type="REFLECTION",
parent=parent,
content_assignment=Assignment.objects.get(
slug__startswith=f"versicherungsvermittler-in-assignment-reflexion"
slug__startswith="versicherungsvermittler-in-assignment-reflexion"
),
),
)
LearningContentFeedbackVVFactory(
parent=parent,
)

View File

@ -1,5 +1,3 @@
import random
import graphene
import structlog
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.learnpath.models import (
Circle,
CourseProfile,
LearningContentAssignment,
LearningContentAttendanceCourse,
LearningContentDocumentList,

View File

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

View File

@ -172,9 +172,6 @@ class LearningSequence(CourseBasePage):
def __str__(self):
return f"{self.title}"
def get_admin_display_title(self):
return f"{self.icon} {self.draft_title}"
def get_admin_display_title_html(self):
return f"""
<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 (
AbstractImage,
AbstractRendition,
get_upload_to,
Image,
WagtailImageField,
get_upload_to,
)
from vbv_lernwelt.core.admin import User
@ -67,10 +67,13 @@ class ContentImage(AbstractImage):
height_field="height",
storage=ContentImagesStorage,
)
admin_form_fields = Image.admin_form_fields + (
admin_form_fields = (
Image.admin_form_fields
+ (
# Then add the field names here to make them appear in the form:
# 'caption',
)
)
class UserImage(AbstractImage):

View File

@ -1,6 +1,5 @@
from storages.backends.s3boto3 import S3Boto3Storage
# 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.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 vbv_lernwelt.media_files.models import ContentDocument

View File

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

View File

@ -1,6 +1,6 @@
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 (
MediaLibraryCategoryPageFactory,
MediaLibraryContentPageFactory,
@ -10,7 +10,6 @@ from vbv_lernwelt.media_library.tests.media_library_factories import (
def create_default_media_library(course_id):
course = Course.objects.get(id=course_id)
course_page = CoursePage.objects.get(course_id=course_id)
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.
""".strip(),
body=RichText(
f"<h2>Lernmedien</h2>"
f"<h3>Allgemeines</h3>"
f"<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>"
"<h2>Lernmedien</h2>"
"<h3>Allgemeines</h3>"
"<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,
parent=media_lib_allgemeines,
body=RichText(
f"<h2>Lernmedien</h2>"
f"<h3>Allgemeines</h3>"
f"<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>"
"<h2>Lernmedien</h2>"
"<h3>Allgemeines</h3>"
"<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.documents.models import AbstractDocument, Document
from wagtail.fields import RichTextField
from wagtail.models import Page
from vbv_lernwelt.core.constants import (
DEFAULT_RICH_TEXT_FEATURES,

View File

@ -12,8 +12,9 @@ class NotificationCategory(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")
CASEWORK_EXPERT_EVALUATION_REMINDER = (
@ -24,11 +25,13 @@ class NotificationTrigger(models.TextChoices):
CASEWORK_EVALUATED = "CASEWORK_EVALUATED", _("Casework Evaluated")
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_session.models import CourseSessionAssignment
from vbv_lernwelt.notify.email.email_services import (
create_template_data_from_course_session_attendance_course,
EmailTemplate,
create_template_data_from_course_session_attendance_course,
format_swiss_datetime,
send_email,
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@ class CheckoutInformationAdmin(admin.ModelAdmin):
success = False
if not success:
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")

View File

@ -1,13 +1,13 @@
import uuid
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.shop.services import (
InitTransactionException,
get_payment_url,
init_datatrans_transaction,
InitTransactionException,
)
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.services import (
InitTransactionException,
create_context_data_log,
datatrans_state_to_checkout_state,
get_payment_url,
get_vv_payment_email_template,
init_datatrans_transaction,
InitTransactionException,
is_signature_valid,
)

View File

@ -1,5 +1,6 @@
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 keycloak.exceptions import KeycloakDeleteError, KeycloakPostError

View File

@ -1,6 +1,6 @@
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 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 django.shortcuts import redirect
from django.test import override_settings, TestCase
from django.test import TestCase, override_settings
from django.urls import reverse
from vbv_lernwelt.core.models import User

View File

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