diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue b/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
index 7af5a9b3..41a3e020 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
@@ -14,9 +14,9 @@ import {
useCurrentCourseSession,
} from "@/composables";
import CourseSessionDueDatesList from "@/components/dueDates/CourseSessionDueDatesList.vue";
-import { useMutation, useQuery } from "@urql/vue";
+import { useMutation } from "@urql/vue";
import { UPDATE_COURSE_PROFILE_MUTATION } from "@/graphql/mutations";
-import { COURSE_QUERY } from "@/graphql/queries";
+import { filterCircles, useCourseFilter } from "./utils";
const props = defineProps<{
courseSlug: string;
@@ -37,25 +37,17 @@ const course = computed(() => lpQueryResult.course.value);
const courseSession = useCurrentCourseSession();
-// todo: we do not use the courseStore, because the returned object has lost its reactivity and does not reflect cache changes. maybe this could be fixed in there, then we can use the same object here
-// todo: this could maybe go somewhere else, but useQuery must be used inside of a setup function. is there a better place?
-const courseReactiveResult = useQuery({
- query: COURSE_QUERY,
- variables: { slug: props.courseSlug },
-});
-const courseReactive = computed(() => courseReactiveResult.data.value?.course);
-const courseSessionUser = computed(() => {
- return courseReactive.value?.course_session_users.find(
- (e) => e?.course_session.id === courseSession.value.id
- );
-});
-const filter = computed(() => {
- return courseSessionUser.value?.chosen_profile || "";
+const { filter } = useCourseFilter(props.courseSlug);
+
+const filteredCircles = computed(() => {
+ if (lpQueryResult.circles.value === undefined) {
+ return [];
+ }
+ return filterCircles(filter.value, lpQueryResult.circles.value);
});
-const { inProgressCirclesCount, circlesCount } = useCourseCircleProgress(
- lpQueryResult.circles
-);
+const { inProgressCirclesCount, circlesCount } =
+ useCourseCircleProgress(filteredCircles);
const updateCourseProfileMutation = useMutation(UPDATE_COURSE_PROFILE_MUTATION);
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue b/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
index 3c739185..58a72639 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
@@ -3,6 +3,7 @@ import { computed } from "vue";
import type { LearningContentWithCompletion, TopicType } from "@/types";
import LearningPathCircleColumn from "./LearningPathCircleColumn.vue";
import { COURSE_PROFILE_ALL_FILTER } from "@/constants";
+import { filterCircles } from "./utils";
interface Props {
topic: TopicType;
@@ -22,17 +23,7 @@ const isLastCircle = (circleIndex: number, numCircles: number) =>
props.isLastTopic && circleIndex === numCircles - 1;
const filteredCircles = computed(() => {
- if (
- props.filter === undefined ||
- props.filter === "" ||
- props.filter === COURSE_PROFILE_ALL_FILTER
- ) {
- return props.topic.circles;
- }
- return props.topic.circles.filter(
- (circle) =>
- circle.profiles.indexOf(props.filter as string) > -1 || circle.is_base_circle
- );
+ return filterCircles(props.filter, props.topic.circles);
});
diff --git a/client/src/pages/learningPath/learningPathPage/utils.ts b/client/src/pages/learningPath/learningPathPage/utils.ts
index 46410d94..d27f27f8 100644
--- a/client/src/pages/learningPath/learningPathPage/utils.ts
+++ b/client/src/pages/learningPath/learningPathPage/utils.ts
@@ -1,3 +1,6 @@
+import { useCurrentCourseSession } from "@/composables";
+import { COURSE_PROFILE_ALL_FILTER } from "@/constants";
+import { COURSE_QUERY } from "@/graphql/queries";
import type {
CircleSectorData,
CircleSectorProgress,
@@ -7,6 +10,8 @@ import {
someFinishedInLearningSequence,
} from "@/services/circle";
import type { CircleType } from "@/types";
+import { useQuery } from "@urql/vue";
+import { computed } from "vue";
export function calculateCircleSectorData(circle: CircleType): CircleSectorData[] {
return circle.learning_sequences.map((ls) => {
@@ -21,3 +26,42 @@ export function calculateCircleSectorData(circle: CircleType): CircleSectorData[
};
});
}
+
+export function useCourseFilter(courseSlug: string, courseSessionId?: string) {
+ const csId = computed(() => {
+ if (courseSessionId) {
+ return courseSessionId;
+ }
+ // assume we're on a page with a current course session
+ const courseSession = useCurrentCourseSession();
+ return courseSession.value.id;
+ });
+ const courseReactiveResult = useQuery({
+ query: COURSE_QUERY,
+ variables: { slug: courseSlug },
+ });
+ const courseReactive = computed(() => courseReactiveResult.data.value?.course);
+ const courseSessionUser = computed(() => {
+ return courseReactive.value?.course_session_users.find(
+ (e) => e?.course_session.id === csId.value
+ );
+ });
+ const filter = computed(() => {
+ return courseSessionUser.value?.chosen_profile || "";
+ });
+
+ return {
+ filter,
+ courseReactive,
+ courseSessionUser,
+ };
+}
+
+export function filterCircles(filter: string | undefined, circles: CircleType[]) {
+ if (filter === undefined || filter === "" || filter === COURSE_PROFILE_ALL_FILTER) {
+ return circles;
+ }
+ return circles.filter(
+ (circle) => circle.profiles.indexOf(filter as string) > -1 || circle.is_base_circle
+ );
+}
diff --git a/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py b/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
new file mode 100644
index 00000000..66ba4aec
--- /dev/null
+++ b/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
@@ -0,0 +1,20 @@
+# Generated by Django 4.2.13 on 2024-07-25 14:27
+
+from django.db import migrations
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("learnpath", "0020_auto_20240711_1736"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="circle",
+ name="profiles",
+ field=modelcluster.fields.ParentalManyToManyField(
+ related_name="circles", to="learnpath.courseprofile"
+ ),
+ ),
+ ]
From 488dc0843f6bead0eaadcdbc6302a6eb025a7208 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Thu, 25 Jul 2024 22:31:44 +0200
Subject: [PATCH 50/71] Fix linting issue in python code
---
.../learnpath/migrations/0021_alter_circle_profiles.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py b/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
index 66ba4aec..b4c51e5c 100644
--- a/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
+++ b/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
@@ -1,7 +1,7 @@
# Generated by Django 4.2.13 on 2024-07-25 14:27
-from django.db import migrations
import modelcluster.fields
+from django.db import migrations
class Migration(migrations.Migration):
From dc689bd20a23b4c31f618965ce1022c454c708de Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Thu, 25 Jul 2024 22:33:12 +0200
Subject: [PATCH 51/71] Fix linting issue in client code
---
.../learningPath/learningPathPage/LearningPathPathTopic.vue | 1 -
1 file changed, 1 deletion(-)
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue b/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
index 58a72639..ef3baaad 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
@@ -2,7 +2,6 @@
import { computed } from "vue";
import type { LearningContentWithCompletion, TopicType } from "@/types";
import LearningPathCircleColumn from "./LearningPathCircleColumn.vue";
-import { COURSE_PROFILE_ALL_FILTER } from "@/constants";
import { filterCircles } from "./utils";
interface Props {
From f6e459fafe41217dd6fe93d8db0939af4ab33b48 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Mon, 29 Jul 2024 14:15:49 +0200
Subject: [PATCH 52/71] Add additional checks in cypress test
---
.../src/pages/onboarding/vv/AccountCourseProfile.vue | 2 +-
cypress/e2e/checkout-vv/checkout.cy.js | 12 +++++++++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/client/src/pages/onboarding/vv/AccountCourseProfile.vue b/client/src/pages/onboarding/vv/AccountCourseProfile.vue
index 529babdc..c101a0e2 100644
--- a/client/src/pages/onboarding/vv/AccountCourseProfile.vue
+++ b/client/src/pages/onboarding/vv/AccountCourseProfile.vue
@@ -42,7 +42,7 @@ const courseProfilesToDropdown = computed(() => {
-
+
{{ $t("a.Zulassungsprofil auswählen") }}
diff --git a/cypress/e2e/checkout-vv/checkout.cy.js b/cypress/e2e/checkout-vv/checkout.cy.js
index 75c1d253..d00c6cca 100644
--- a/cypress/e2e/checkout-vv/checkout.cy.js
+++ b/cypress/e2e/checkout-vv/checkout.cy.js
@@ -2,7 +2,7 @@ import {
COURSE_PROFILE_ALL_ID,
COURSE_PROFILE_NICHTLEBEN_ID,
TEST_COURSE_SESSION_VV_ID,
- TEST_USER_EMPTY_ID
+ TEST_USER_EMPTY_ID,
} from "../../consts";
import { login } from "../helpers";
@@ -37,6 +37,11 @@ describe("checkout.cy.js", () => {
cy.get("#organisationDetailName").type("FdH GmbH");
cy.get('[data-cy="continue-button"]').click();
+ cy.get('[data-cy="account-course-profile-title"]').should(
+ "have.text",
+ "Zulassungsprofil auswählen",
+ );
+
cy.get('[data-cy="dropdown-select"]').click();
cy.get('[data-cy="dropdown-select-option-Nichtleben"]').click();
cy.get('[data-cy="continue-button"]').click();
@@ -158,6 +163,11 @@ describe("checkout.cy.js", () => {
cy.get('[data-cy="dropdown-select-option-Baloise"]').click();
cy.get('[data-cy="continue-button"]').click();
+ cy.get('[data-cy="account-course-profile-title"]').should(
+ "have.text",
+ "Zulassungsprofil auswählen",
+ );
+
cy.get('[data-cy="dropdown-select"]').click();
cy.get('[data-cy="dropdown-select-option-Allbranche"]').click();
cy.get('[data-cy="continue-button"]').click();
From d0ef9bd5fde9948320b7f765722c7a15209493f2 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Mon, 29 Jul 2024 20:43:24 +0200
Subject: [PATCH 53/71] Add unit test for course profile update
---
.../tests/test_update_course_profile.py | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 server/vbv_lernwelt/course/tests/test_update_course_profile.py
diff --git a/server/vbv_lernwelt/course/tests/test_update_course_profile.py b/server/vbv_lernwelt/course/tests/test_update_course_profile.py
new file mode 100644
index 00000000..c0cd7a1f
--- /dev/null
+++ b/server/vbv_lernwelt/course/tests/test_update_course_profile.py
@@ -0,0 +1,94 @@
+from django.test import RequestFactory, TestCase
+from graphene.test import Client
+
+from vbv_lernwelt.core.admin import User
+from vbv_lernwelt.core.create_default_users import create_default_users
+from vbv_lernwelt.core.schema import schema
+from vbv_lernwelt.course.management.commands.create_default_courses import (
+ create_versicherungsvermittlerin_course,
+)
+from vbv_lernwelt.learnpath.creators import create_course_profiles
+
+
+class CourseGraphQLTestCase(TestCase):
+ def setUp(self) -> None:
+ create_default_users()
+ create_course_profiles()
+ create_versicherungsvermittlerin_course()
+ user = User.objects.get(username="student-vv@eiger-versicherungen.ch")
+ request = RequestFactory().get("/")
+ request.user = user
+ self.client = Client(schema=schema, context_value=request)
+
+ def test_query(self):
+ query = """
+ query CourseQuery($slug: String!) {
+ course(slug: $slug){
+ id
+ profiles
+ course_session_users {
+ id
+ __typename
+ chosen_profile
+ course_session {
+ id
+ }
+ }
+ }
+ }
+ """
+ slug = "versicherungsvermittler-in"
+ variables = {"slug": slug}
+ result = self.client.execute(query, variables=variables)
+
+ self.assertIsNone(result.get("errors"))
+ data = result.get("data")
+ course = data.get("course")
+ profiles = course.get("profiles")
+ self.assertEqual(
+ set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ )
+ course_session_user = course.get("course_session_users")[0]
+ chosen_profile = course_session_user.get("chosen_profile")
+
+ self.assertEqual(chosen_profile, "")
+
+ mutation = """
+ mutation UpdateCourseSessionProfile($input: CourseSessionProfileMutationInput!) {
+ update_course_session_profile(input: $input) {
+ clientMutationId
+ result {
+ __typename
+ ... on UpdateCourseProfileSuccess {
+ user {
+ id
+ chosen_profile
+ }
+ }
+ ... on UpdateCourseProfileError {
+ message
+ }
+ }
+ }
+ }
+ """
+
+ profile = "nichtleben"
+ input = {"course_profile": profile, "course_slug": slug}
+
+ mutation_result = self.client.execute(mutation, variables={"input": input})
+
+ self.assertIsNone(mutation_result.get("errors"))
+
+ second_query_result = self.client.execute(query, variables=variables)
+
+ self.assertIsNone(second_query_result.get("errors"))
+ data = second_query_result.get("data")
+ course = data.get("course")
+ profiles = course.get("profiles")
+ self.assertEqual(
+ set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ )
+ course_session_user = course.get("course_session_users")[0]
+ chosen_profile = course_session_user.get("chosen_profile")
+ self.assertEqual(chosen_profile, profile)
From a1228f7753313814d96c8ab2e9bea30a5784cb57 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Mon, 29 Jul 2024 22:53:04 +0200
Subject: [PATCH 54/71] Add another unit test
---
.../tests/test_update_course_profile.py | 78 +++++++++++++++++--
1 file changed, 72 insertions(+), 6 deletions(-)
diff --git a/server/vbv_lernwelt/course/tests/test_update_course_profile.py b/server/vbv_lernwelt/course/tests/test_update_course_profile.py
index c0cd7a1f..2ed4cb71 100644
--- a/server/vbv_lernwelt/course/tests/test_update_course_profile.py
+++ b/server/vbv_lernwelt/course/tests/test_update_course_profile.py
@@ -7,7 +7,9 @@ from vbv_lernwelt.core.schema import schema
from vbv_lernwelt.course.management.commands.create_default_courses import (
create_versicherungsvermittlerin_course,
)
+from vbv_lernwelt.course.models import CourseSessionUser
from vbv_lernwelt.learnpath.creators import create_course_profiles
+from vbv_lernwelt.learnpath.models import CourseProfile
class CourseGraphQLTestCase(TestCase):
@@ -15,12 +17,12 @@ class CourseGraphQLTestCase(TestCase):
create_default_users()
create_course_profiles()
create_versicherungsvermittlerin_course()
+
+ def test_update_course_profile(self):
user = User.objects.get(username="student-vv@eiger-versicherungen.ch")
request = RequestFactory().get("/")
request.user = user
- self.client = Client(schema=schema, context_value=request)
-
- def test_query(self):
+ client = Client(schema=schema, context_value=request)
query = """
query CourseQuery($slug: String!) {
course(slug: $slug){
@@ -39,7 +41,7 @@ class CourseGraphQLTestCase(TestCase):
"""
slug = "versicherungsvermittler-in"
variables = {"slug": slug}
- result = self.client.execute(query, variables=variables)
+ result = client.execute(query, variables=variables)
self.assertIsNone(result.get("errors"))
data = result.get("data")
@@ -76,11 +78,11 @@ class CourseGraphQLTestCase(TestCase):
profile = "nichtleben"
input = {"course_profile": profile, "course_slug": slug}
- mutation_result = self.client.execute(mutation, variables={"input": input})
+ mutation_result = client.execute(mutation, variables={"input": input})
self.assertIsNone(mutation_result.get("errors"))
- second_query_result = self.client.execute(query, variables=variables)
+ second_query_result = client.execute(query, variables=variables)
self.assertIsNone(second_query_result.get("errors"))
data = second_query_result.get("data")
@@ -92,3 +94,67 @@ class CourseGraphQLTestCase(TestCase):
course_session_user = course.get("course_session_users")[0]
chosen_profile = course_session_user.get("chosen_profile")
self.assertEqual(chosen_profile, profile)
+
+ def test_mentor_profile_view(self):
+ user = User.objects.get(username="test-mentor1@example.com")
+ request = RequestFactory().get("/")
+ request.user = user
+ client = Client(schema=schema, context_value=request)
+
+ query = """
+ query courseQuery($slug: String!, $user: String) {
+ course(slug: $slug) {
+ id
+ title
+ slug
+ category_name
+ profiles
+ course_session_users(id: $user) {
+ id
+ __typename
+ chosen_profile
+ course_session {
+ id
+ __typename
+ }
+ }
+ __typename
+ }
+ }
+ """
+ student = User.objects.get(username="student-vv@eiger-versicherungen.ch")
+
+ slug = "versicherungsvermittler-in"
+ student_id = str(student.id)
+ variables = {"slug": slug, "user": student_id}
+ print(variables)
+ result = client.execute(query, variables=variables)
+ self.assertIsNone(result.get("errors"))
+ data = result.get("data")
+ course = data.get("course")
+ profiles = course.get("profiles")
+ self.assertEqual(
+ set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ )
+ course_session_user = course.get("course_session_users")[0]
+ chosen_profile = course_session_user.get("chosen_profile")
+ self.assertEqual(chosen_profile, "")
+
+ csu = CourseSessionUser.objects.get(
+ course_session__course__slug=slug, user=student
+ )
+ course_profile = CourseProfile.objects.get(code="nichtleben")
+ csu.chosen_profile = course_profile
+ csu.save()
+
+ second_result = client.execute(query, variables=variables)
+ self.assertIsNone(second_result.get("errors"))
+ data = second_result.get("data")
+ course = data.get("course")
+ profiles = course.get("profiles")
+ self.assertEqual(
+ set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ )
+ course_session_user = course.get("course_session_users")[0]
+ chosen_profile = course_session_user.get("chosen_profile")
+ self.assertEqual(chosen_profile, "nichtleben")
From b0909c52d3c99bb54d8df95df6c6ed511edfc2ea Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 30 Jul 2024 09:29:34 +0200
Subject: [PATCH 55/71] Add ordering to course profiles
---
server/vbv_lernwelt/learnpath/creators.py | 11 +++---
..._options_circle_is_base_circle_and_more.py | 34 +++++++++++++++++++
...711_1527.py => 0019_auto_20240730_0904.py} | 7 ++--
.../migrations/0019_circle_is_base_circle.py | 17 ----------
...711_1736.py => 0020_auto_20240730_0905.py} | 4 +--
.../migrations/0021_alter_circle_profiles.py | 20 -----------
server/vbv_lernwelt/learnpath/models.py | 6 ++++
...0017_checkoutinformation_chosen_profile.py | 9 +++--
8 files changed, 60 insertions(+), 48 deletions(-)
create mode 100644 server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py
rename server/vbv_lernwelt/learnpath/migrations/{0018_auto_20240711_1527.py => 0019_auto_20240730_0904.py} (62%)
delete mode 100644 server/vbv_lernwelt/learnpath/migrations/0019_circle_is_base_circle.py
rename server/vbv_lernwelt/learnpath/migrations/{0020_auto_20240711_1736.py => 0020_auto_20240730_0905.py} (74%)
delete mode 100644 server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
diff --git a/server/vbv_lernwelt/learnpath/creators.py b/server/vbv_lernwelt/learnpath/creators.py
index 372b17dc..360a9252 100644
--- a/server/vbv_lernwelt/learnpath/creators.py
+++ b/server/vbv_lernwelt/learnpath/creators.py
@@ -18,17 +18,20 @@ logger = structlog.get_logger(__name__)
def create_course_profiles():
from vbv_lernwelt.learnpath.models import CourseProfile
+ # Allbranche, Krankenzusatzversicherung, nicht Leben, Leben
CourseProfile.objects.get_or_create(
- id=COURSE_PROFILE_LEBEN_ID, code=COURSE_PROFILE_LEBEN_CODE
+ id=COURSE_PROFILE_ALL_ID, code=COURSE_PROFILE_ALL_CODE, order=1
)
CourseProfile.objects.get_or_create(
- id=COURSE_PROFILE_NICHTLEBEN_ID, code=COURSE_PROFILE_NICHTLEBEN_CODE
+ id=COURSE_PROFILE_KRANKENZUSATZ_ID,
+ code=COURSE_PROFILE_KRANKENZUSATZ_CODE,
+ order=2,
)
CourseProfile.objects.get_or_create(
- id=COURSE_PROFILE_KRANKENZUSATZ_ID, code=COURSE_PROFILE_KRANKENZUSATZ_CODE
+ id=COURSE_PROFILE_NICHTLEBEN_ID, code=COURSE_PROFILE_NICHTLEBEN_CODE, order=3
)
CourseProfile.objects.get_or_create(
- id=COURSE_PROFILE_ALL_ID, code=COURSE_PROFILE_ALL_CODE
+ id=COURSE_PROFILE_LEBEN_ID, code=COURSE_PROFILE_LEBEN_CODE, order=4
)
diff --git a/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py b/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py
new file mode 100644
index 00000000..f2702b68
--- /dev/null
+++ b/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py
@@ -0,0 +1,34 @@
+# Generated by Django 4.2.13 on 2024-07-30 07:03
+
+from django.db import migrations, models
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("learnpath", "0017_auto_20240711_1100"),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name="courseprofile",
+ options={"ordering": ["order"]},
+ ),
+ migrations.AddField(
+ model_name="circle",
+ name="is_base_circle",
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name="courseprofile",
+ name="order",
+ field=models.IntegerField(default=999),
+ ),
+ migrations.AlterField(
+ model_name="circle",
+ name="profiles",
+ field=modelcluster.fields.ParentalManyToManyField(
+ related_name="circles", to="learnpath.courseprofile"
+ ),
+ ),
+ ]
diff --git a/server/vbv_lernwelt/learnpath/migrations/0018_auto_20240711_1527.py b/server/vbv_lernwelt/learnpath/migrations/0019_auto_20240730_0904.py
similarity index 62%
rename from server/vbv_lernwelt/learnpath/migrations/0018_auto_20240711_1527.py
rename to server/vbv_lernwelt/learnpath/migrations/0019_auto_20240730_0904.py
index d4cb42a1..46464f1e 100644
--- a/server/vbv_lernwelt/learnpath/migrations/0018_auto_20240711_1527.py
+++ b/server/vbv_lernwelt/learnpath/migrations/0019_auto_20240730_0904.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.2.20 on 2024-07-11 13:27
+# Generated by Django 4.2.13 on 2024-07-30 07:04
from django.db import migrations
@@ -11,7 +11,10 @@ def migrate(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
- ("learnpath", "0017_auto_20240711_1100"),
+ (
+ "learnpath",
+ "0018_alter_courseprofile_options_circle_is_base_circle_and_more",
+ ),
]
operations = [migrations.RunPython(migrate)]
diff --git a/server/vbv_lernwelt/learnpath/migrations/0019_circle_is_base_circle.py b/server/vbv_lernwelt/learnpath/migrations/0019_circle_is_base_circle.py
deleted file mode 100644
index faa5981c..00000000
--- a/server/vbv_lernwelt/learnpath/migrations/0019_circle_is_base_circle.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated by Django 3.2.20 on 2024-07-11 15:36
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
- dependencies = [
- ("learnpath", "0018_auto_20240711_1527"),
- ]
-
- operations = [
- migrations.AddField(
- model_name="circle",
- name="is_base_circle",
- field=models.BooleanField(default=False),
- ),
- ]
diff --git a/server/vbv_lernwelt/learnpath/migrations/0020_auto_20240711_1736.py b/server/vbv_lernwelt/learnpath/migrations/0020_auto_20240730_0905.py
similarity index 74%
rename from server/vbv_lernwelt/learnpath/migrations/0020_auto_20240711_1736.py
rename to server/vbv_lernwelt/learnpath/migrations/0020_auto_20240730_0905.py
index 2b7df592..edac10fc 100644
--- a/server/vbv_lernwelt/learnpath/migrations/0020_auto_20240711_1736.py
+++ b/server/vbv_lernwelt/learnpath/migrations/0020_auto_20240730_0905.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.2.20 on 2024-07-11 15:36
+# Generated by Django 4.2.13 on 2024-07-30 07:05
from django.db import migrations
@@ -11,7 +11,7 @@ def migrate(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
- ("learnpath", "0019_circle_is_base_circle"),
+ ("learnpath", "0019_auto_20240730_0904"),
]
operations = [migrations.RunPython(migrate)]
diff --git a/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py b/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
deleted file mode 100644
index b4c51e5c..00000000
--- a/server/vbv_lernwelt/learnpath/migrations/0021_alter_circle_profiles.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generated by Django 4.2.13 on 2024-07-25 14:27
-
-import modelcluster.fields
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
- dependencies = [
- ("learnpath", "0020_auto_20240711_1736"),
- ]
-
- operations = [
- migrations.AlterField(
- model_name="circle",
- name="profiles",
- field=modelcluster.fields.ParentalManyToManyField(
- related_name="circles", to="learnpath.courseprofile"
- ),
- ),
- ]
diff --git a/server/vbv_lernwelt/learnpath/models.py b/server/vbv_lernwelt/learnpath/models.py
index bc423504..a0a76f03 100644
--- a/server/vbv_lernwelt/learnpath/models.py
+++ b/server/vbv_lernwelt/learnpath/models.py
@@ -69,10 +69,16 @@ class Topic(CourseBasePage):
class CourseProfile(models.Model):
code = models.CharField(max_length=255)
+ order = models.IntegerField(default=999)
def __str__(self) -> str:
return self.code
+ class Meta:
+ ordering = [
+ "order",
+ ]
+
class CourseProfileToCircle(models.Model):
# this connects the course profile to a circle, because a circle can be in multiple profiles
diff --git a/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py b/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py
index 766f994e..66d74fe0 100644
--- a/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py
+++ b/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py
@@ -1,12 +1,15 @@
-# Generated by Django 4.2.13 on 2024-07-22 19:45
+# Generated by Django 4.2.13 on 2024-07-30 07:03
-import django.db.models.deletion
from django.db import migrations, models
+import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
- ("learnpath", "0020_auto_20240711_1736"),
+ (
+ "learnpath",
+ "0018_alter_courseprofile_options_circle_is_base_circle_and_more",
+ ),
("shop", "0016_alter_checkoutinformation_refno2"),
]
From 129070309517965fc979ea28ff2df3ae4c80710d Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 30 Jul 2024 10:33:37 +0200
Subject: [PATCH 56/71] Make course profile filter more mobile friendly
---
.../pages/learningPath/learningPathPage/LearningPathPage.vue | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue b/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
index 41a3e020..e8a4bcf9 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
@@ -69,7 +69,9 @@ const changeViewType = (viewType: ViewType) => {
-
+
From 708e24785d8a9fbf9c41d2f0481ca395ee846360 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 30 Jul 2024 10:51:46 +0200
Subject: [PATCH 57/71] Fix formatting
---
...lter_courseprofile_options_circle_is_base_circle_and_more.py | 2 +-
.../shop/migrations/0017_checkoutinformation_chosen_profile.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py b/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py
index f2702b68..8d9f3b72 100644
--- a/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py
+++ b/server/vbv_lernwelt/learnpath/migrations/0018_alter_courseprofile_options_circle_is_base_circle_and_more.py
@@ -1,7 +1,7 @@
# Generated by Django 4.2.13 on 2024-07-30 07:03
-from django.db import migrations, models
import modelcluster.fields
+from django.db import migrations, models
class Migration(migrations.Migration):
diff --git a/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py b/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py
index 66d74fe0..091915d3 100644
--- a/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py
+++ b/server/vbv_lernwelt/shop/migrations/0017_checkoutinformation_chosen_profile.py
@@ -1,7 +1,7 @@
# Generated by Django 4.2.13 on 2024-07-30 07:03
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
From 537c614a57aeef2cfebdd774ac9a5dcb2a677478 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 30 Jul 2024 10:59:50 +0200
Subject: [PATCH 58/71] Add bullet point to VV start page
---
client/src/pages/start/VVStartPage.vue | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/client/src/pages/start/VVStartPage.vue b/client/src/pages/start/VVStartPage.vue
index 7cf3f310..1b55cde8 100644
--- a/client/src/pages/start/VVStartPage.vue
+++ b/client/src/pages/start/VVStartPage.vue
@@ -47,6 +47,14 @@ const { t } = useTranslation();
$t("Füge dein Profilbild hinzu und ergänze die fehlenden Angaben.")
}}
+
+ {{ $t("a.Zulassungsprofil auswählen") }}:
+ {{
+ $t(
+ "a.Wähle ein Zulassungsprofil, damit du deinen Lehrgang an der richtigen Stelle beginnen kannst."
+ )
+ }}
+
{{ $t("a.Lehrgang kaufen") }}:
{{
From 17b466ea295bee844acd6e72887f68ecd140963a Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Tue, 30 Jul 2024 11:06:14 +0200
Subject: [PATCH 59/71] Fix layout of topics when there is enough space
---
.../learningPath/learningPathPage/LearningPathPathTopic.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue b/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
index ef3baaad..dbcbded5 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathPathTopic.vue
@@ -27,7 +27,7 @@ const filteredCircles = computed(() => {
-
+
Date: Wed, 31 Jul 2024 15:20:07 +0200
Subject: [PATCH 60/71] Replace the course profile filter pills with a dropdown
---
client/src/components/ui/ItDropdownSelect.vue | 7 +--
.../LearningPathProfileFilter.vue | 47 +++++++++++--------
server/vbv_lernwelt/course/graphql/types.py | 4 +-
3 files changed, 31 insertions(+), 27 deletions(-)
diff --git a/client/src/components/ui/ItDropdownSelect.vue b/client/src/components/ui/ItDropdownSelect.vue
index 8a9c3139..b1cb47df 100644
--- a/client/src/components/ui/ItDropdownSelect.vue
+++ b/client/src/components/ui/ItDropdownSelect.vue
@@ -5,17 +5,14 @@ import { computed } from "vue"; // https://stackoverflow.com/questions/64775876/
// https://stackoverflow.com/questions/64775876/vue-3-pass-reactive-object-to-component-with-two-way-binding
interface Props {
- modelValue?: {
- id: string | number;
- name: string;
- };
+ modelValue?: DropdownSelectable;
items?: DropdownSelectable[];
borderless?: boolean;
placeholderText?: string | null;
}
const emit = defineEmits<{
- (e: "update:modelValue", data: object): void;
+ (e: "update:modelValue", data: DropdownSelectable): void;
}>();
const props = withDefaults(defineProps(), {
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue b/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue
index cad73d41..4dce5785 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue
@@ -1,35 +1,44 @@
diff --git a/server/vbv_lernwelt/course/graphql/types.py b/server/vbv_lernwelt/course/graphql/types.py
index cbec6854..934fa119 100644
--- a/server/vbv_lernwelt/course/graphql/types.py
+++ b/server/vbv_lernwelt/course/graphql/types.py
@@ -136,9 +136,7 @@ class CourseObjectType(DjangoObjectType):
@staticmethod
def resolve_profiles(root: Course, info, **kwargs):
if root.configuration.is_vv:
- return CourseProfile.objects.exclude(id=COURSE_PROFILE_ALL_ID).values_list(
- "code", flat=True
- )
+ return CourseProfile.objects.values_list("code", flat=True)
return []
@staticmethod
From dff81c0a6bc163205c06a12fab7c8915a38785eb Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Wed, 31 Jul 2024 15:20:39 +0200
Subject: [PATCH 61/71] Display profile filter on mobile also
---
.../pages/learningPath/learningPathPage/LearningPathPage.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue b/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
index e8a4bcf9..3d8aecc8 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathPage.vue
@@ -98,7 +98,7 @@ const changeViewType = (viewType: ViewType) => {
Date: Wed, 31 Jul 2024 15:44:15 +0200
Subject: [PATCH 62/71] Update lint scripts
---
client/package.json | 3 ++-
git-pre-push.sh | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/client/package.json b/client/package.json
index 72a3765f..f5296e99 100644
--- a/client/package.json
+++ b/client/package.json
@@ -10,8 +10,9 @@
"cypress:open": "cypress open",
"dev": "concurrently \"vite\" \"npm run codegen:watch\"",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
+ "lint:errors": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --quiet --ignore-path .gitignore",
"prettier": "prettier . --write",
- "prettier:check": "prettier . --check",
+ "prettier:check": "prettier . --check --ignore-unknown",
"tailwind": "tailwindcss -i tailwind.css -o ../server/vbv_lernwelt/static/css/tailwind.css --watch",
"test": "vitest run",
"typecheck": "npm run codegen && vue-tsc --noEmit -p tsconfig.app.json --composite false",
diff --git a/git-pre-push.sh b/git-pre-push.sh
index 8cb53b69..fcf48120 100755
--- a/git-pre-push.sh
+++ b/git-pre-push.sh
@@ -7,7 +7,7 @@ echo 'prettier:check'
(cd client && npm run prettier:check)
echo 'lint and typecheck'
-(cd client && npm run lint && npm run typecheck)
+(cd client && npm run lint:errors && npm run typecheck)
echo 'python ufmt check'
ufmt check server
From c50b19d0d7fcbf803cb373615dc53f8dc990f2c6 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Wed, 31 Jul 2024 15:55:10 +0200
Subject: [PATCH 63/71] Fix unit tests
---
.../course/tests/test_update_course_profile.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/server/vbv_lernwelt/course/tests/test_update_course_profile.py b/server/vbv_lernwelt/course/tests/test_update_course_profile.py
index 2ed4cb71..c4a4b12c 100644
--- a/server/vbv_lernwelt/course/tests/test_update_course_profile.py
+++ b/server/vbv_lernwelt/course/tests/test_update_course_profile.py
@@ -48,7 +48,8 @@ class CourseGraphQLTestCase(TestCase):
course = data.get("course")
profiles = course.get("profiles")
self.assertEqual(
- set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ set(profiles),
+ set(["all", "nichtleben", "leben", "krankenzusatzversicherung"]),
)
course_session_user = course.get("course_session_users")[0]
chosen_profile = course_session_user.get("chosen_profile")
@@ -89,7 +90,8 @@ class CourseGraphQLTestCase(TestCase):
course = data.get("course")
profiles = course.get("profiles")
self.assertEqual(
- set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ set(profiles),
+ set(["all", "nichtleben", "leben", "krankenzusatzversicherung"]),
)
course_session_user = course.get("course_session_users")[0]
chosen_profile = course_session_user.get("chosen_profile")
@@ -134,7 +136,8 @@ class CourseGraphQLTestCase(TestCase):
course = data.get("course")
profiles = course.get("profiles")
self.assertEqual(
- set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ set(profiles),
+ set(["all", "nichtleben", "leben", "krankenzusatzversicherung"]),
)
course_session_user = course.get("course_session_users")[0]
chosen_profile = course_session_user.get("chosen_profile")
@@ -153,7 +156,8 @@ class CourseGraphQLTestCase(TestCase):
course = data.get("course")
profiles = course.get("profiles")
self.assertEqual(
- set(profiles), set(["nichtleben", "leben", "krankenzusatzversicherung"])
+ set(profiles),
+ set(["all", "nichtleben", "leben", "krankenzusatzversicherung"]),
)
course_session_user = course.get("course_session_users")[0]
chosen_profile = course_session_user.get("chosen_profile")
From 4d3ab9ce39ad9d94e3671cd6934f289441df76d3 Mon Sep 17 00:00:00 2001
From: Ramon Wenger
Date: Mon, 5 Aug 2024 22:05:20 +0200
Subject: [PATCH 64/71] Display correct profile filter when none is chosen yet
---
.../learningPathPage/LearningPathProfileFilter.vue | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue b/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue
index 4dce5785..675c5715 100644
--- a/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue
+++ b/client/src/pages/learningPath/learningPathPage/LearningPathProfileFilter.vue
@@ -1,5 +1,6 @@