VBV-193 refactored course completion for course sessions

This commit is contained in:
Daniel Egger 2023-03-31 18:25:06 +02:00
parent ddc7a3bd70
commit 8d41d3d3a2
44 changed files with 446 additions and 1744 deletions

View File

@ -61,7 +61,7 @@ function selectCourseSession(courseSession: CourseSession) {
courseSessionsStore.switchCourseSession(courseSession); courseSessionsStore.switchCourseSession(courseSession);
} }
function popoverClick(event) { function popoverClick(event: Event) {
if (breakpoints.smaller("lg").value) { if (breakpoints.smaller("lg").value) {
event.preventDefault(); event.preventDefault();
state.showMobileProfileMenu = true; state.showMobileProfileMenu = true;

View File

@ -163,6 +163,15 @@ const router = createRouter({
router.beforeEach(updateLoggedIn); router.beforeEach(updateLoggedIn);
router.beforeEach(redirectToLoginIfRequired); router.beforeEach(redirectToLoginIfRequired);
router.beforeEach((to) => {
const appStore = useAppStore();
if (to.params.courseSlug) {
appStore.currentCourseSlug = to.params.courseSlug as string;
} else {
appStore.currentCourseSlug = "";
}
});
router.afterEach(() => { router.afterEach(() => {
const appStore = useAppStore(); const appStore = useAppStore();
appStore.routingFinished = true; appStore.routingFinished = true;

View File

@ -4,6 +4,7 @@ export type AppState = {
userLoaded: boolean; userLoaded: boolean;
routingFinished: boolean; routingFinished: boolean;
showMainNavigationBar: boolean; showMainNavigationBar: boolean;
currentCourseSlug: string;
}; };
const showMainNavigationBarInitialState = () => { const showMainNavigationBarInitialState = () => {
@ -31,6 +32,7 @@ export const useAppStore = defineStore({
showMainNavigationBar: showMainNavigationBarInitialState(), showMainNavigationBar: showMainNavigationBarInitialState(),
userLoaded: false, userLoaded: false,
routingFinished: false, routingFinished: false,
currentCourseSlug: "",
} as AppState), } as AppState),
getters: {}, getters: {},
actions: {}, actions: {},

View File

@ -1,5 +1,6 @@
import { itGetCached } from "@/fetchHelpers"; import { itGetCached } from "@/fetchHelpers";
import { useCompletionStore } from "@/stores/completion"; import { useCompletionStore } from "@/stores/completion";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import type { import type {
CircleLight, CircleLight,
@ -164,8 +165,14 @@ export const useCompetenceStore = defineStore({
const competenceProfilePage = this.competenceProfilePages.get(userId); const competenceProfilePage = this.competenceProfilePages.get(userId);
if (competenceProfilePage) { if (competenceProfilePage) {
const completionStore = useCompletionStore(); const completionStore = useCompletionStore();
const courseSessionsStore = useCourseSessionsStore();
const courseSession = courseSessionsStore.courseSessionForCourse(
competenceProfilePage.course.slug
);
if (courseSession) {
const completionData = await completionStore.loadCompletionData( const completionData = await completionStore.loadCompletionData(
competenceProfilePage.course.id, courseSession.id,
userId userId
); );
@ -189,6 +196,7 @@ export const useCompetenceStore = defineStore({
this.competenceProfilePages.set(userId, competenceProfilePage); this.competenceProfilePages.set(userId, competenceProfilePage);
} }
} }
}
}, },
}, },
}); });

View File

@ -1,4 +1,6 @@
import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers"; import { bustItGetCache, itGetCached, itPost } from "@/fetchHelpers";
import { useAppStore } from "@/stores/app";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import type { BaseCourseWagtailPage, CourseCompletion } from "@/types"; import type { BaseCourseWagtailPage, CourseCompletion } from "@/types";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
@ -10,26 +12,41 @@ export const useCompletionStore = defineStore({
}, },
getters: {}, getters: {},
actions: { actions: {
async loadCompletionData(courseId: number, userId: number, reload = false) { async loadCompletionData(courseSessionId: number, userId: number, reload = false) {
const userCompletionData = (await itGetCached( const userCompletionData = (await itGetCached(
`/api/course/completion/${courseId}/${userId}/`, `/api/course/completion/${courseSessionId}/${userId}/`,
{ {
reload: reload, reload: reload,
} }
)) as CourseCompletion[]; )) as CourseCompletion[];
if (userCompletionData === undefined) { if (userCompletionData === undefined) {
throw `No completionData found with: ${courseId}, ${userId}`; throw `No completionData found with: ${courseSessionId}, ${userId}`;
} }
return userCompletionData || []; return userCompletionData || [];
}, },
async markPage( async markPage(
page: BaseCourseWagtailPage, page: BaseCourseWagtailPage,
userId: number | undefined = undefined userId: number | undefined = undefined,
courseSessionId: number | undefined = undefined
) { ) {
if (!courseSessionId) {
const appStore = useAppStore();
const courseSlug = appStore.currentCourseSlug;
if (courseSlug) {
const courseSessionsStore = useCourseSessionsStore();
const courseSession = courseSessionsStore.courseSessionForCourse(courseSlug);
if (courseSession) {
courseSessionId = courseSession.id;
}
}
}
if (courseSessionId) {
const completionData = await itPost("/api/course/completion/mark/", { const completionData = await itPost("/api/course/completion/mark/", {
page_key: page.translation_key, page_key: page.translation_key,
completion_status: page.completion_status, completion_status: page.completion_status,
course_session_id: courseSessionId,
}); });
if (completionData && completionData.length > 0) { if (completionData && completionData.length > 0) {
@ -37,10 +54,15 @@ export const useCompletionStore = defineStore({
const userStore = useUserStore(); const userStore = useUserStore();
userId = userStore.id; userId = userStore.id;
} }
bustItGetCache(`/api/course/completion/${completionData[0].course}/${userId}/`); bustItGetCache(
`/api/course/completion/${completionData[0].course}/${userId}/`
);
} }
return completionData as CourseCompletion[]; return completionData as CourseCompletion[];
}
return [];
}, },
}, },
}); });

View File

@ -218,6 +218,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
courseSessions, courseSessions,
userCourses, userCourses,
courseSessionForRoute, courseSessionForRoute,
courseSessionForCourse,
courseSessionsForRoute, courseSessionsForRoute,
courseSessionsForCourse, courseSessionsForCourse,
switchCourseSession, switchCourseSession,

View File

@ -1,7 +1,9 @@
import { itGetCached } from "@/fetchHelpers"; import { itGetCached } from "@/fetchHelpers";
import { LearningPath } from "@/services/learningPath"; import { LearningPath } from "@/services/learningPath";
import { useCompletionStore } from "@/stores/completion"; import { useCompletionStore } from "@/stores/completion";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import type { CourseCompletion } from "@/types";
import cloneDeep from "lodash/cloneDeep"; import cloneDeep from "lodash/cloneDeep";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
@ -65,10 +67,20 @@ export const useLearningPathStore = defineStore({
} }
const completionStore = useCompletionStore(); const completionStore = useCompletionStore();
const completionData = await completionStore.loadCompletionData(
learningPathData.course.id, let completionData: CourseCompletion[] = [];
if (userId) {
const courseSessionsStore = useCourseSessionsStore();
const courseSession = courseSessionsStore.courseSessionForCourse(
learningPathData.course.slug
);
if (courseSession) {
completionData = await completionStore.loadCompletionData(
courseSession.id,
userId userId
); );
}
}
const learningPath = LearningPath.fromJson( const learningPath = LearningPath.fromJson(
cloneDeep(learningPathData), cloneDeep(learningPathData),

View File

@ -87,9 +87,9 @@ urlpatterns = [
name="course_page_api_view"), name="course_page_api_view"),
path(r"api/course/completion/mark/", mark_course_completion_view, path(r"api/course/completion/mark/", mark_course_completion_view,
name="mark_course_completion"), name="mark_course_completion"),
path(r"api/course/completion/<course_id>/", request_course_completion, path(r"api/course/completion/<course_session_id>/", request_course_completion,
name="request_course_completion"), name="request_course_completion"),
path(r"api/course/completion/<course_id>/<int:user_id>/", path(r"api/course/completion/<course_session_id>/<int:user_id>/",
request_course_completion_for_user, request_course_completion_for_user,
name="request_course_completion_for_user"), name="request_course_completion_for_user"),

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-09-28 12:51 # Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion import django.db.models.deletion
import wagtail.blocks import wagtail.blocks
@ -7,6 +7,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [

View File

@ -1,10 +1,11 @@
# Generated by Django 3.2.13 on 2022-09-28 12:51 # Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [

View File

@ -58,7 +58,9 @@ def command(course):
if COURSE_UK in course: if COURSE_UK in course:
create_course_uk_de() create_course_uk_de()
create_course_uk_de_completion_data() create_course_uk_de_completion_data(
CourseSession.objects.get(title="Bern 2023 a")
)
if COURSE_UK_FR in course: if COURSE_UK_FR in course:
create_course_uk_fr() create_course_uk_fr()
@ -278,7 +280,7 @@ def create_course_uk_fr():
csu.expert.add(fr_circle) csu.expert.add(fr_circle)
def create_course_uk_de_completion_data(): def create_course_uk_de_completion_data(course_session):
# initial completion data # initial completion data
for slug, status, email in [ for slug, status, email in [
( (
@ -1045,5 +1047,6 @@ def create_course_uk_de_completion_data():
mark_course_completion( mark_course_completion(
Page.objects.get(slug=slug).translation_key, Page.objects.get(slug=slug).translation_key,
User.objects.get(email=email), User.objects.get(email=email),
status, course_session=course_session,
completion_status=status,
) )

View File

@ -1,19 +1,34 @@
# Generated by Django 3.2.13 on 2022-09-28 12:51 # Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("wagtailcore", "0069_log_entry_jsonfield"), ("wagtailcore", "0069_log_entry_jsonfield"),
] ]
operations = [ operations = [
migrations.CreateModel(
name="CircleDocument",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("name", models.CharField(max_length=100)),
],
),
migrations.CreateModel( migrations.CreateModel(
name="Course", name="Course",
fields=[ fields=[
@ -35,36 +50,42 @@ class Migration(migrations.Migration):
verbose_name="Kategorie-Name", verbose_name="Kategorie-Name",
), ),
), ),
(
"slug",
models.SlugField(
allow_unicode=True,
blank=True,
max_length=255,
unique=True,
verbose_name="Slug",
),
),
], ],
options={ options={
"verbose_name": "Lehrgang", "verbose_name": "Lehrgang",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name="CoursePage", name="CourseCategory",
fields=[ fields=[
( (
"page_ptr", "id",
models.OneToOneField( models.BigAutoField(
auto_created=True, auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
to="wagtailcore.page", verbose_name="ID",
), ),
), ),
( (
"course", "title",
models.ForeignKey( models.CharField(blank=True, max_length=255, verbose_name="Titel"),
on_delete=django.db.models.deletion.PROTECT, to="course.course"
), ),
(
"general",
models.BooleanField(default=False, verbose_name="Allgemein"),
), ),
], ],
options={
"verbose_name": "Lehrgang-Seite",
},
bases=("wagtailcore.page",),
), ),
migrations.CreateModel( migrations.CreateModel(
name="CourseCompletion", name="CourseCompletion",
@ -96,23 +117,30 @@ class Migration(migrations.Migration):
), ),
), ),
("additional_json_data", models.JSONField(default=dict)), ("additional_json_data", models.JSONField(default=dict)),
(
"course",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.course"
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name="CourseCategory", name="CoursePage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
],
options={
"verbose_name": "Lehrgang-Seite",
},
bases=("wagtailcore.page",),
),
migrations.CreateModel(
name="CourseSession",
fields=[ fields=[
( (
"id", "id",
@ -123,27 +151,47 @@ class Migration(migrations.Migration):
verbose_name="ID", verbose_name="ID",
), ),
), ),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("title", models.TextField()),
("start_date", models.DateField(blank=True, null=True)),
("end_date", models.DateField(blank=True, null=True)),
("additional_json_data", models.JSONField(default=dict)),
],
),
migrations.CreateModel(
name="CourseSessionUser",
fields=[
( (
"title", "id",
models.CharField(blank=True, max_length=255, verbose_name="Titel"), models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"role",
models.CharField(
choices=[
("MEMBER", "Teilnehmer"),
("EXPERT", "Experte/Trainer"),
("TUTOR", "Lernbegleitung"),
],
default="MEMBER",
max_length=255,
),
), ),
( (
"general", "course_session",
models.BooleanField(default=False, verbose_name="Allgemein"),
),
(
"course",
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.course" on_delete=django.db.models.deletion.CASCADE,
to="course.coursesession",
), ),
), ),
], ],
), ),
migrations.AddConstraint(
model_name="coursecompletion",
constraint=models.UniqueConstraint(
fields=("user", "page_key"),
name="course_completion_unique_user_page_key",
),
),
] ]

View File

@ -1,78 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-14 07:33
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("course", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="CourseSession",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("title", models.TextField()),
("start_date", models.DateField(blank=True, null=True)),
("end_date", models.DateField(blank=True, null=True)),
("additional_json_data", models.JSONField(default=dict)),
(
"course",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.course"
),
),
],
),
migrations.CreateModel(
name="CourseSessionUser",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"course_session",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="course.coursesession",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.AddConstraint(
model_name="coursesessionuser",
constraint=models.UniqueConstraint(
fields=("course_session", "user"),
name="course_session_user_unique_course_session_user",
),
),
]

View File

@ -0,0 +1,105 @@
# Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("course", "0001_initial"),
("learnpath", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("files", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="coursesessionuser",
name="expert",
field=models.ManyToManyField(
blank=True, related_name="expert", to="learnpath.Circle"
),
),
migrations.AddField(
model_name="coursesessionuser",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
migrations.AddField(
model_name="coursesession",
name="course",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.course"
),
),
migrations.AddField(
model_name="coursepage",
name="course",
field=models.OneToOneField(
on_delete=django.db.models.deletion.PROTECT, to="course.course"
),
),
migrations.AddField(
model_name="coursecompletion",
name="course_session",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.coursesession"
),
),
migrations.AddField(
model_name="coursecompletion",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
),
),
migrations.AddField(
model_name="coursecategory",
name="course",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.course"
),
),
migrations.AddField(
model_name="circledocument",
name="course_session",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="course.coursesession"
),
),
migrations.AddField(
model_name="circledocument",
name="file",
field=models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE, to="files.uploadfile"
),
),
migrations.AddField(
model_name="circledocument",
name="learning_sequence",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="learnpath.learningsequence",
),
),
migrations.AddConstraint(
model_name="coursesessionuser",
constraint=models.UniqueConstraint(
fields=("course_session", "user"),
name="course_session_user_unique_course_session_user",
),
),
migrations.AddConstraint(
model_name="coursecompletion",
constraint=models.UniqueConstraint(
fields=("user", "page_key", "course_session"),
name="course_completion_unique_user_page_key",
),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 3.2.13 on 2022-11-07 13:30
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("course", "0002_auto_20221014_0933"),
]
operations = [
migrations.AlterField(
model_name="coursepage",
name="course",
field=models.OneToOneField(
on_delete=django.db.models.deletion.PROTECT, to="course.course"
),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.13 on 2022-11-07 15:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0008_alter_learningcontent_contents"),
("course", "0003_alter_coursepage_course"),
]
operations = [
migrations.AddField(
model_name="coursesessionuser",
name="expert",
field=models.ManyToManyField(related_name="expert", to="learnpath.Circle"),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 3.2.13 on 2022-11-07 15:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0008_alter_learningcontent_contents"),
("course", "0004_coursesessionuser_expert"),
]
operations = [
migrations.AlterField(
model_name="coursesessionuser",
name="expert",
field=models.ManyToManyField(
blank=True, related_name="expert", to="learnpath.Circle"
),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 3.2.13 on 2022-12-02 09:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("course", "0005_alter_coursesessionuser_expert"),
]
operations = [
migrations.AddField(
model_name="course",
name="slug",
field=models.SlugField(
allow_unicode=True,
blank=True,
max_length=255,
unique=True,
verbose_name="Slug",
),
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 3.2.13 on 2022-12-02 12:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("course", "0006_course_slug"),
]
operations = [
migrations.AddField(
model_name="coursesessionuser",
name="role",
field=models.CharField(
choices=[
("MEMBER", "Teilnehmer"),
("EXPERT", "Experte/Trainer"),
("TUTOR", "Lernbegleitung"),
],
default="MEMBER",
max_length=255,
),
),
]

View File

@ -1,52 +0,0 @@
# Generated by Django 3.2.13 on 2022-12-24 20:34
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("files", "0001_initial"),
("learnpath", "0008_alter_learningcontent_contents"),
("course", "0007_coursesessionuser_role"),
]
operations = [
migrations.CreateModel(
name="CircleDocument",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("name", models.CharField(max_length=100)),
(
"course_session",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="course.coursesession",
),
),
(
"file",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to="files.uploadfile",
),
),
(
"learning_sequence",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="learnpath.learningsequence",
),
),
],
),
]

View File

@ -146,7 +146,7 @@ class CourseCompletion(models.Model):
page_type = models.CharField(max_length=255, default="", blank=True) page_type = models.CharField(max_length=255, default="", blank=True)
page_slug = models.CharField(max_length=255, default="", blank=True) page_slug = models.CharField(max_length=255, default="", blank=True)
course = models.ForeignKey("course.Course", on_delete=models.CASCADE) course_session = models.ForeignKey("course.CourseSession", on_delete=models.CASCADE)
completion_status = models.CharField( completion_status = models.CharField(
max_length=255, max_length=255,
@ -162,10 +162,7 @@ class CourseCompletion(models.Model):
class Meta: class Meta:
constraints = [ constraints = [
UniqueConstraint( UniqueConstraint(
fields=[ fields=["user", "page_key", "course_session"],
"user",
"page_key",
],
name="course_completion_unique_user_page_key", name="course_completion_unique_user_page_key",
) )
] ]

View File

@ -36,7 +36,7 @@ class CourseCompletionSerializer(serializers.ModelSerializer):
"page_key", "page_key",
"page_type", "page_type",
"page_slug", "page_slug",
"course", "course_session",
"completion_status", "completion_status",
"additional_json_data", "additional_json_data",
] ]

View File

@ -4,14 +4,14 @@ from vbv_lernwelt.course.models import CourseCompletion
from vbv_lernwelt.learnpath.utils import get_wagtail_type from vbv_lernwelt.learnpath.utils import get_wagtail_type
def mark_course_completion(page_key, user, completion_status="success"): def mark_course_completion(page_key, user, course_session, completion_status="success"):
page = Page.objects.get(translation_key=page_key, locale__language_code="de-CH") page = Page.objects.get(translation_key=page_key, locale__language_code="de-CH")
page_type = get_wagtail_type(page.specific) page_type = get_wagtail_type(page.specific)
course = page.specific.get_course() course = page.specific.get_course()
cc, created = CourseCompletion.objects.get_or_create( cc, created = CourseCompletion.objects.get_or_create(
user=user, user=user,
page_key=page_key, page_key=page_key,
course_id=course.id, course_session_id=course_session.id,
) )
cc.page_slug = page.slug cc.page_slug = page.slug
cc.page_type = page_type cc.page_type = page_type

View File

@ -6,7 +6,11 @@ from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.models import User from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.consts import COURSE_TEST_ID from vbv_lernwelt.course.consts import COURSE_TEST_ID
from vbv_lernwelt.course.creators.test_course import create_test_course from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseCompletion from vbv_lernwelt.course.models import (
CourseCompletion,
CourseSession,
CourseSessionUser,
)
from vbv_lernwelt.learnpath.models import LearningContent from vbv_lernwelt.learnpath.models import LearningContent
@ -15,6 +19,14 @@ class CourseCompletionApiTestCase(APITestCase):
create_default_users() create_default_users()
create_test_course() create_test_course()
self.user = User.objects.get(username="admin") self.user = User.objects.get(username="admin")
self.cs = CourseSession.objects.create(
course_id=COURSE_TEST_ID,
title="Test Lehrgang Session",
)
csu = CourseSessionUser.objects.create(
course_session=self.cs,
user=self.user,
)
self.client.login(username="admin", password="test") self.client.login(username="admin", password="test")
def test_completeLearningContent_works(self): def test_completeLearningContent_works(self):
@ -27,6 +39,7 @@ class CourseCompletionApiTestCase(APITestCase):
mark_url, mark_url,
{ {
"page_key": learning_content_key, "page_key": learning_content_key,
"course_session_id": self.cs.id,
}, },
) )
response_json = response.json() response_json = response.json()
@ -38,12 +51,12 @@ class CourseCompletionApiTestCase(APITestCase):
self.assertEqual(response_json[0]["completion_status"], "success") self.assertEqual(response_json[0]["completion_status"], "success")
db_entry = CourseCompletion.objects.get( db_entry = CourseCompletion.objects.get(
user=self.user, course_id=COURSE_TEST_ID, page_key=learning_content_key user=self.user, course_session_id=self.cs.id, page_key=learning_content_key
) )
self.assertEqual(db_entry.completion_status, "success") self.assertEqual(db_entry.completion_status, "success")
# test getting the circle data # test getting the circle data
response = self.client.get(f"/api/course/completion/{COURSE_TEST_ID}/") response = self.client.get(f"/api/course/completion/{self.cs.id}/")
print(response.status_code) print(response.status_code)
response_json = response.json() response_json = response.json()
print(json.dumps(response.json(), indent=2)) print(json.dumps(response.json(), indent=2))
@ -59,6 +72,7 @@ class CourseCompletionApiTestCase(APITestCase):
{ {
"page_key": learning_content_key, "page_key": learning_content_key,
"completion_status": "fail", "completion_status": "fail",
"course_session_id": self.cs.id,
}, },
) )
@ -69,6 +83,6 @@ class CourseCompletionApiTestCase(APITestCase):
self.assertEqual(response_json[0]["completion_status"], "fail") self.assertEqual(response_json[0]["completion_status"], "fail")
db_entry = CourseCompletion.objects.get( db_entry = CourseCompletion.objects.get(
user=self.user, course_id=COURSE_TEST_ID, page_key=learning_content_key user=self.user, course_session_id=self.cs.id, page_key=learning_content_key
) )
self.assertEqual(db_entry.completion_status, "fail") self.assertEqual(db_entry.completion_status, "fail")

View File

@ -8,6 +8,7 @@ from wagtail.models import Page
from vbv_lernwelt.course.models import ( from vbv_lernwelt.course.models import (
CircleDocument, CircleDocument,
CourseCompletion, CourseCompletion,
CourseSession,
CourseSessionUser, CourseSessionUser,
) )
from vbv_lernwelt.course.permissions import ( from vbv_lernwelt.course.permissions import (
@ -48,10 +49,12 @@ def course_page_api_view(request, slug):
return Response({"error": str(e)}, status=404) return Response({"error": str(e)}, status=404)
def _request_course_completion(course_id, user_id): def _request_course_completion(course_session_id, user_id):
try: try:
response_data = CourseCompletionSerializer( response_data = CourseCompletionSerializer(
CourseCompletion.objects.filter(user_id=user_id, course_id=course_id), CourseCompletion.objects.filter(
user_id=user_id, course_session_id=course_session_id
),
many=True, many=True,
).data ).data
@ -64,16 +67,18 @@ def _request_course_completion(course_id, user_id):
@api_view(["GET"]) @api_view(["GET"])
def request_course_completion(request, course_id): def request_course_completion(request, course_session_id):
course_id = get_object_or_404(CourseSession, id=course_session_id).course_id
if has_course_access(request.user, course_id): if has_course_access(request.user, course_id):
return _request_course_completion(course_id, request.user.id) return _request_course_completion(course_session_id, request.user.id)
raise PermissionDenied() raise PermissionDenied()
@api_view(["GET"]) @api_view(["GET"])
def request_course_completion_for_user(request, course_id, user_id): def request_course_completion_for_user(request, course_session_id, user_id):
course_id = get_object_or_404(CourseSession, id=course_session_id).course_id
if request.user.id == user_id or is_course_expert(request.user, course_id): if request.user.id == user_id or is_course_expert(request.user, course_id):
return _request_course_completion(course_id, user_id) return _request_course_completion(course_session_id, user_id)
raise PermissionDenied() raise PermissionDenied()
@ -82,6 +87,7 @@ def mark_course_completion_view(request):
try: try:
page_key = request.data.get("page_key") page_key = request.data.get("page_key")
completion_status = request.data.get("completion_status", "success") completion_status = request.data.get("completion_status", "success")
course_session_id = request.data.get("course_session_id")
page = Page.objects.get(translation_key=page_key, locale__language_code="de-CH") page = Page.objects.get(translation_key=page_key, locale__language_code="de-CH")
if not has_course_access_by_page_request(request, page): if not has_course_access_by_page_request(request, page):
@ -91,11 +97,16 @@ def mark_course_completion_view(request):
course = page.specific.get_course() course = page.specific.get_course()
mark_course_completion( mark_course_completion(
page_key, request.user, completion_status=completion_status page_key,
request.user,
course_session=CourseSession.objects.get(id=course_session_id),
completion_status=completion_status,
) )
response_data = CourseCompletionSerializer( response_data = CourseCompletionSerializer(
CourseCompletion.objects.filter(user=request.user, course_id=course.id), CourseCompletion.objects.filter(
user=request.user, course_session_id=course_session_id
),
many=True, many=True,
).data ).data
@ -107,7 +118,7 @@ def mark_course_completion_view(request):
page_slug=page.slug, page_slug=page.slug,
page_title=page.title, page_title=page.title,
user_id=request.user.id, user_id=request.user.id,
course_id=course.id, course_session_id=course_session_id,
completion_status=completion_status, completion_status=completion_status,
) )
@ -115,7 +126,7 @@ def mark_course_completion_view(request):
except PermissionDenied as e: except PermissionDenied as e:
raise e raise e
except Exception as e: except Exception as e:
logger.error(e) logger.error(e, exc_info=True)
return Response({"error": str(e)}, status=404) return Response({"error": str(e)}, status=404)

View File

@ -1,19 +1,13 @@
# Generated by Django 3.2.13 on 2022-12-27 14:58 # Generated by Django 3.2.13 on 2023-03-31 16:22
import django.core.validators
import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
import vbv_lernwelt.feedback.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
("learnpath", "0009_alter_learningcontent_contents"),
("course", "0007_coursesessionuser_role"),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
@ -28,86 +22,8 @@ class Migration(migrations.Migration):
verbose_name="ID", verbose_name="ID",
), ),
), ),
( ("data", models.JSONField(default=dict)),
"satisfaction", ("created_at", models.DateTimeField(auto_now_add=True)),
vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
(
"goal_attainment",
vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
("proficiency", models.IntegerField(null=True)),
("received_materials", models.BooleanField(null=True)),
(
"materials_rating",
vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
(
"instructor_competence",
vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
(
"instructor_respect",
vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
("instructor_open_feedback", models.TextField(blank=True)),
("would_recommend", models.BooleanField(null=True)),
("course_positive_feedback", models.TextField(blank=True)),
("course_negative_feedback", models.TextField(blank=True)),
(
"circle",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="learnpath.circle",
),
),
(
"course_session",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="course.coursesession",
),
),
], ],
), ),
] ]

View File

@ -1,90 +0,0 @@
# Generated by Django 3.2.13 on 2023-01-11 09:44
import django.core.validators
from django.db import migrations
import vbv_lernwelt.feedback.models
class Migration(migrations.Migration):
dependencies = [
("feedback", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="feedbackresponse",
name="goal_attainment",
field=vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
migrations.AlterField(
model_name="feedbackresponse",
name="instructor_competence",
field=vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
migrations.AlterField(
model_name="feedbackresponse",
name="instructor_respect",
field=vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
migrations.AlterField(
model_name="feedbackresponse",
name="materials_rating",
field=vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
migrations.AlterField(
model_name="feedbackresponse",
name="satisfaction",
field=vbv_lernwelt.feedback.models.FeedbackIntegerField(
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(4),
],
),
),
]

View File

@ -0,0 +1,32 @@
# Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("feedback", "0001_initial"),
("course", "0001_initial"),
("learnpath", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="feedbackresponse",
name="circle",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="learnpath.circle"
),
),
migrations.AddField(
model_name="feedbackresponse",
name="course_session",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="course.coursesession"
),
),
]

View File

@ -1,66 +0,0 @@
# Generated by Django 3.2.13 on 2023-02-06 10:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("feedback", "0002_auto_20230111_1044"),
]
operations = [
migrations.RemoveField(
model_name="feedbackresponse",
name="course_negative_feedback",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="course_positive_feedback",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="goal_attainment",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="instructor_competence",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="instructor_open_feedback",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="instructor_respect",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="materials_rating",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="proficiency",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="received_materials",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="satisfaction",
),
migrations.RemoveField(
model_name="feedbackresponse",
name="would_recommend",
),
migrations.AddField(
model_name="feedbackresponse",
name="data",
field=models.JSONField(default=dict),
),
migrations.AddField(
model_name="feedbackresponse",
name="created_at",
field=models.DateTimeField(auto_now_add=True),
),
]

View File

@ -1,13 +1,13 @@
# Generated by Django 3.2.13 on 2022-09-28 12:51 # Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion import django.db.models.deletion
import wagtail.blocks import wagtail.blocks
import wagtail.fields import wagtail.fields
import wagtail.images.blocks
from django.db import migrations, models from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -31,49 +31,7 @@ class Migration(migrations.Migration):
), ),
), ),
("description", models.TextField(blank=True, default="")), ("description", models.TextField(blank=True, default="")),
( ("goals", wagtail.fields.RichTextField()),
"goals",
wagtail.fields.StreamField(
[("goal", wagtail.blocks.TextBlock())], use_json_field=True
),
),
(
"job_situations",
wagtail.fields.StreamField(
[("job_situation", wagtail.blocks.CharBlock())],
use_json_field=True,
),
),
(
"experts",
wagtail.fields.StreamField(
[
(
"person",
wagtail.blocks.StructBlock(
[
("first_name", wagtail.blocks.CharBlock()),
("last_name", wagtail.blocks.CharBlock()),
("email", wagtail.blocks.EmailBlock()),
(
"photo",
wagtail.images.blocks.ImageChooserBlock(
required=False
),
),
(
"biography",
wagtail.blocks.RichTextBlock(
required=False
),
),
]
),
)
],
use_json_field=True,
),
),
], ],
options={ options={
"verbose_name": "Circle", "verbose_name": "Circle",
@ -104,7 +62,7 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -113,7 +71,13 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
(
"text",
wagtail.blocks.RichTextBlock(
required=False
),
),
] ]
), ),
), ),
@ -122,7 +86,16 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
]
),
),
(
"learningmodule",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -131,7 +104,7 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -140,7 +113,7 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -149,7 +122,7 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -158,7 +131,7 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -167,7 +140,7 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
] ]
), ),
), ),
@ -176,10 +149,26 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("description", wagtail.blocks.TextBlock()), ("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()), ("url", wagtail.blocks.TextBlock()),
(
"text",
wagtail.blocks.RichTextBlock(
required=False
),
),
] ]
), ),
), ),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
("feedback", wagtail.blocks.StructBlock([])),
], ],
use_json_field=None, use_json_field=None,
), ),

View File

@ -1,113 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-04 13:34
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="learningcontent",
name="contents",
field=wagtail.fields.StreamField(
[
(
"video",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"resource",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"exercise",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"online_training",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"media_library",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"document",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"test",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"book",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"assignment",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.URLBlock()),
]
),
),
],
use_json_field=None,
),
),
]

View File

@ -1,113 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-05 10:06
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0002_alter_learningcontent_contents"),
]
operations = [
migrations.AlterField(
model_name="learningcontent",
name="contents",
field=wagtail.fields.StreamField(
[
(
"video",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"resource",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"exercise",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"online_training",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"media_library",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"document",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"test",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"book",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"assignment",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
],
use_json_field=None,
),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-14 10:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0003_alter_learningcontent_contents"),
]
operations = [
migrations.AddField(
model_name="circle",
name="goal_description",
field=models.TextField(blank=True, default=""),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-14 10:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0004_circle_goal_description"),
]
operations = [
migrations.AddField(
model_name="circle",
name="job_situation_description",
field=models.TextField(blank=True, default=""),
),
]

View File

@ -1,114 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-14 12:03
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0005_circle_job_situation_description"),
]
operations = [
migrations.AlterField(
model_name="learningcontent",
name="contents",
field=wagtail.fields.StreamField(
[
(
"video",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"resource",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock()),
]
),
),
(
"exercise",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"online_training",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"media_library",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"document",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"test",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"book",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"assignment",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
],
use_json_field=None,
),
),
]

View File

@ -1,115 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-14 16:02
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0006_alter_learningcontent_contents"),
]
operations = [
migrations.AlterField(
model_name="learningcontent",
name="contents",
field=wagtail.fields.StreamField(
[
(
"video",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"resource",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock(required=False)),
]
),
),
(
"exercise",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"online_training",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"media_library",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"document",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"test",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"book",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"assignment",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock(required=False)),
]
),
),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
],
use_json_field=None,
),
),
]

View File

@ -1,124 +0,0 @@
# Generated by Django 3.2.13 on 2022-11-07 13:30
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0007_alter_learningcontent_contents"),
]
operations = [
migrations.AlterField(
model_name="learningcontent",
name="contents",
field=wagtail.fields.StreamField(
[
(
"video",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"resource",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock(required=False)),
]
),
),
(
"exercise",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"learningmodule",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"online_training",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"media_library",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"document",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"test",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"book",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"assignment",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock(required=False)),
]
),
),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
],
use_json_field=None,
),
),
]

View File

@ -1,125 +0,0 @@
# Generated by Django 3.2.13 on 2022-12-08 09:55
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0008_alter_learningcontent_contents"),
]
operations = [
migrations.AlterField(
model_name="learningcontent",
name="contents",
field=wagtail.fields.StreamField(
[
(
"video",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"resource",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock(required=False)),
]
),
),
(
"exercise",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"learningmodule",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"online_training",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"media_library",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"document",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"test",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"book",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
(
"assignment",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
("text", wagtail.blocks.RichTextBlock(required=False)),
]
),
),
(
"placeholder",
wagtail.blocks.StructBlock(
[
("description", wagtail.blocks.TextBlock()),
("url", wagtail.blocks.TextBlock()),
]
),
),
("feedback", wagtail.blocks.StructBlock([])),
],
use_json_field=None,
),
),
]

View File

@ -1,16 +0,0 @@
# Generated by Django 3.2.13 on 2023-01-11 09:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0009_alter_learningcontent_contents"),
]
operations = [
migrations.RemoveField(
model_name="circle",
name="experts",
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.13 on 2023-03-08 08:21
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0010_remove_circle_experts"),
]
operations = [
migrations.AlterField(
model_name="circle",
name="goals",
field=wagtail.fields.RichTextField(),
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 3.2.13 on 2023-03-09 06:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("learnpath", "0011_alter_circle_goals"),
]
operations = [
migrations.RemoveField(
model_name="circle",
name="goal_description",
),
migrations.RemoveField(
model_name="circle",
name="job_situation_description",
),
migrations.RemoveField(
model_name="circle",
name="job_situations",
),
]

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-10-03 14:18 # Generated by Django 3.2.13 on 2023-03-31 16:22
import django.db.models.deletion import django.db.models.deletion
import taggit.managers import taggit.managers
@ -11,12 +11,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
("course", "0001_initial"), ("course", "0002_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("taggit", "0004_alter_taggeditem_content_type_alter_taggeditem_tag"), ("taggit", "0004_alter_taggeditem_content_type_alter_taggeditem_tag"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("wagtailcore", "0069_log_entry_jsonfield"), ("wagtailcore", "0069_log_entry_jsonfield"),
] ]
@ -73,6 +74,10 @@ class Migration(migrations.Migration):
"overview_icon", "overview_icon",
models.CharField(default="icon-hf-fahrzeug", max_length=255), models.CharField(default="icon-hf-fahrzeug", max_length=255),
), ),
(
"detail_image",
models.CharField(default="image-hf-fahrzeug", max_length=255),
),
( (
"body", "body",
wagtail.fields.StreamField( wagtail.fields.StreamField(
@ -82,6 +87,12 @@ class Migration(migrations.Migration):
wagtail.blocks.StructBlock( wagtail.blocks.StructBlock(
[ [
("title", wagtail.blocks.TextBlock()), ("title", wagtail.blocks.TextBlock()),
(
"description",
wagtail.blocks.TextBlock(
default="", required=False
),
),
( (
"contents", "contents",
wagtail.blocks.StreamBlock( wagtail.blocks.StreamBlock(
@ -92,10 +103,7 @@ class Migration(migrations.Migration):
[ [
( (
"title", "title",
wagtail.blocks.TextBlock( wagtail.blocks.TextBlock(),
blank=False,
null=False,
),
), ),
( (
"description", "description",
@ -149,10 +157,7 @@ class Migration(migrations.Migration):
[ [
( (
"title", "title",
wagtail.blocks.TextBlock( wagtail.blocks.TextBlock(),
blank=False,
null=False,
),
), ),
( (
"description", "description",
@ -206,10 +211,7 @@ class Migration(migrations.Migration):
[ [
( (
"title", "title",
wagtail.blocks.TextBlock( wagtail.blocks.TextBlock(),
blank=False,
null=False,
),
), ),
( (
"description", "description",
@ -263,10 +265,7 @@ class Migration(migrations.Migration):
[ [
( (
"title", "title",
wagtail.blocks.TextBlock( wagtail.blocks.TextBlock(),
blank=False,
null=False,
),
), ),
( (
"description", "description",

View File

@ -1,261 +0,0 @@
# Generated by Django 3.2.13 on 2022-10-05 12:18
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("media_library", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="mediacategorypage",
name="body",
field=wagtail.fields.StreamField(
[
(
"content_collection",
wagtail.blocks.StructBlock(
[
("title", wagtail.blocks.TextBlock()),
(
"description",
wagtail.blocks.TextBlock(
default="", required=False
),
),
(
"contents",
wagtail.blocks.StreamBlock(
[
(
"learn_media",
wagtail.blocks.StructBlock(
[
(
"title",
wagtail.blocks.TextBlock(),
),
(
"description",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"icon_url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"link_display_text",
wagtail.blocks.CharBlock(
default="Link öffnen",
max_length=255,
),
),
(
"url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"open_window",
wagtail.blocks.BooleanBlock(
default=False
),
),
(
"page",
wagtail.blocks.PageChooserBlock(
page_type=[
"learnpath.LearningContent"
],
required=False,
),
),
]
),
),
(
"external_link",
wagtail.blocks.StructBlock(
[
(
"title",
wagtail.blocks.TextBlock(),
),
(
"description",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"icon_url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"link_display_text",
wagtail.blocks.CharBlock(
default="Link öffnen",
max_length=255,
),
),
(
"url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"open_window",
wagtail.blocks.BooleanBlock(
default=False
),
),
(
"page",
wagtail.blocks.PageChooserBlock(
page_type=[
"learnpath.LearningContent"
],
required=False,
),
),
]
),
),
(
"internal_link",
wagtail.blocks.StructBlock(
[
(
"title",
wagtail.blocks.TextBlock(),
),
(
"description",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"icon_url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"link_display_text",
wagtail.blocks.CharBlock(
default="Link öffnen",
max_length=255,
),
),
(
"url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"open_window",
wagtail.blocks.BooleanBlock(
default=False
),
),
(
"page",
wagtail.blocks.PageChooserBlock(
page_type=[
"learnpath.LearningContent"
],
required=False,
),
),
]
),
),
(
"relative_link",
wagtail.blocks.StructBlock(
[
(
"title",
wagtail.blocks.TextBlock(),
),
(
"description",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"icon_url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"link_display_text",
wagtail.blocks.CharBlock(
default="Link öffnen",
max_length=255,
),
),
(
"url",
wagtail.blocks.TextBlock(
default="",
required=False,
),
),
(
"open_window",
wagtail.blocks.BooleanBlock(
default=False
),
),
(
"page",
wagtail.blocks.PageChooserBlock(
page_type=[
"learnpath.LearningContent"
],
required=False,
),
),
]
),
),
]
),
),
]
),
)
],
null=True,
use_json_field=True,
),
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 4.0.8 on 2022-11-07 09:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("media_library", "0002_alter_mediacategorypage_body"),
]
operations = [
migrations.AddField(
model_name="mediacategorypage",
name="detail_image",
field=models.CharField(default="image-hf-fahrzeug", max_length=255),
),
]