Merged in feature/VBV-289-kn-auftrag-datenmodell-definieren-rebase1 (pull request #53)
Feature/VBV-289 kn auftrag datenmodell definieren rebase1 Approved-by: Elia Bieri
This commit is contained in:
commit
87a3676ca2
|
|
@ -6,6 +6,7 @@ import log from "loglevel";
|
||||||
import type { Component } from "vue";
|
import type { Component } from "vue";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
import AssignmentBlock from "@/pages/learningPath/learningContentPage/blocks/AssignmentBlock.vue";
|
||||||
import AttendanceDayBlock from "@/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue";
|
import AttendanceDayBlock from "@/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue";
|
||||||
import DescriptionBlock from "./blocks/DescriptionBlock.vue";
|
import DescriptionBlock from "./blocks/DescriptionBlock.vue";
|
||||||
import DescriptionTextBlock from "./blocks/DescriptionTextBlock.vue";
|
import DescriptionTextBlock from "./blocks/DescriptionTextBlock.vue";
|
||||||
|
|
@ -35,7 +36,7 @@ const block = computed(() => {
|
||||||
const COMPONENTS: Record<LearningContentType, Component> = {
|
const COMPONENTS: Record<LearningContentType, Component> = {
|
||||||
placeholder: PlaceholderBlock,
|
placeholder: PlaceholderBlock,
|
||||||
video: VideoBlock,
|
video: VideoBlock,
|
||||||
assignment: DescriptionTextBlock,
|
assignment: AssignmentBlock,
|
||||||
resource: DescriptionTextBlock,
|
resource: DescriptionTextBlock,
|
||||||
exercise: IframeBlock,
|
exercise: IframeBlock,
|
||||||
test: IframeBlock,
|
test: IframeBlock,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useAssignmentStore } from "@/stores/assignmentStore";
|
||||||
|
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||||
|
import type {
|
||||||
|
Assignment,
|
||||||
|
CourseSessionAssignmentDetails,
|
||||||
|
LearningContent,
|
||||||
|
} from "@/types";
|
||||||
|
import * as log from "loglevel";
|
||||||
|
import { onMounted, reactive } from "vue";
|
||||||
|
|
||||||
|
const assignmentStore = useAssignmentStore();
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
assignment: Assignment | undefined;
|
||||||
|
courseSessionAssignmentDetails: CourseSessionAssignmentDetails | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state: State = reactive({
|
||||||
|
assignment: undefined,
|
||||||
|
courseSessionAssignmentDetails: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
assignmentId: number;
|
||||||
|
learningContent: LearningContent;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
log.debug("AssignmentView mounted", props.assignmentId, props.learningContent);
|
||||||
|
|
||||||
|
const courseSessionsStore = useCourseSessionsStore();
|
||||||
|
|
||||||
|
try {
|
||||||
|
state.assignment = await assignmentStore.loadAssignment(props.assignmentId);
|
||||||
|
state.courseSessionAssignmentDetails = courseSessionsStore.findAssignmentDetails(
|
||||||
|
props.learningContent.id
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="container-medium">
|
||||||
|
<div v-if="state.assignment" class="lg:mt-12">
|
||||||
|
<h2>Einleitung</h2>
|
||||||
|
|
||||||
|
<h3 class="mt-8">Ausgangslage</h3>
|
||||||
|
<p>{{ state.assignment.starting_position }}</p>
|
||||||
|
|
||||||
|
<h3 class="mt-8">Abgabetermin</h3>
|
||||||
|
<p v-if="state.courseSessionAssignmentDetails">
|
||||||
|
{{ state.courseSessionAssignmentDetails }}
|
||||||
|
</p>
|
||||||
|
<p v-else>Keine Abgabedaten erfasst für diese Durchführung</p>
|
||||||
|
|
||||||
|
<pre class="mt-16">
|
||||||
|
{{ state.assignment }}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<AssignmentView
|
||||||
|
:assignment-id="props.value.assignment"
|
||||||
|
:learning-content="props.content"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import AssignmentView from "@/pages/learningPath/learningContentPage/assignment/AssignmentView.vue";
|
||||||
|
import type { LearningContent } from "@/types";
|
||||||
|
|
||||||
|
interface Value {
|
||||||
|
description: string;
|
||||||
|
assignment: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
value: Value;
|
||||||
|
content: LearningContent;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { itGet } from "@/fetchHelpers";
|
||||||
|
import type { Assignment } from "@/types";
|
||||||
|
import log from "loglevel";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
export type AssignmentStoreState = {
|
||||||
|
assignment: Assignment | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAssignmentStore = defineStore({
|
||||||
|
id: "assignmentStore",
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
assignment: undefined,
|
||||||
|
} as AssignmentStoreState;
|
||||||
|
},
|
||||||
|
getters: {},
|
||||||
|
actions: {
|
||||||
|
async loadAssignment(assignmentId: number) {
|
||||||
|
log.debug("load assignment", assignmentId);
|
||||||
|
const assignmentData = await itGet(`/api/course/page/${assignmentId}/`);
|
||||||
|
|
||||||
|
if (!assignmentData) {
|
||||||
|
throw `No assignment found with: ${assignmentId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.assignment = assignmentData;
|
||||||
|
return this.assignment;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -3,6 +3,7 @@ import { deleteCircleDocument } from "@/services/files";
|
||||||
import type {
|
import type {
|
||||||
CircleDocument,
|
CircleDocument,
|
||||||
CourseSession,
|
CourseSession,
|
||||||
|
CourseSessionAssignmentDetails,
|
||||||
CourseSessionAttendanceDay,
|
CourseSessionAttendanceDay,
|
||||||
CourseSessionUser,
|
CourseSessionUser,
|
||||||
ExpertSessionUser,
|
ExpertSessionUser,
|
||||||
|
|
@ -224,6 +225,16 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findAssignmentDetails(
|
||||||
|
contentId: number
|
||||||
|
): CourseSessionAssignmentDetails | undefined {
|
||||||
|
if (currentCourseSession.value) {
|
||||||
|
return currentCourseSession.value.assignment_details_list.find(
|
||||||
|
(assignmentDetails) => assignmentDetails.learningContentId === contentId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uniqueCourseSessionsByCourse,
|
uniqueCourseSessionsByCourse,
|
||||||
currentCourseSession,
|
currentCourseSession,
|
||||||
|
|
@ -238,6 +249,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
startUpload,
|
startUpload,
|
||||||
removeDocument,
|
removeDocument,
|
||||||
findAttendanceDay,
|
findAttendanceDay,
|
||||||
|
findAssignmentDetails,
|
||||||
|
|
||||||
// TODO: only used to be changed by router.afterEach
|
// TODO: only used to be changed by router.afterEach
|
||||||
currentCourseSlug,
|
currentCourseSlug,
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,63 @@ export interface MediaLibraryPage extends BaseCourseWagtailPage {
|
||||||
readonly children: MediaCategoryPage[];
|
readonly children: MediaCategoryPage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AssignmentPerformanceObjective {
|
||||||
|
readonly type: "performance_objective";
|
||||||
|
readonly id: string;
|
||||||
|
readonly value: {
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssignmentTaskBlockExplanation {
|
||||||
|
readonly type: "explanation";
|
||||||
|
readonly id: string;
|
||||||
|
readonly value: {
|
||||||
|
readonly text: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssignmentTaskBlockUserConfirmation {
|
||||||
|
readonly type: "user_confirmation";
|
||||||
|
readonly id: string;
|
||||||
|
readonly value: {
|
||||||
|
readonly text: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssignmentTaskBlockUserTextInput {
|
||||||
|
readonly type: "user_text_input";
|
||||||
|
readonly id: string;
|
||||||
|
readonly value: {
|
||||||
|
readonly text?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AssignmentTaskBlock =
|
||||||
|
| AssignmentTaskBlockExplanation
|
||||||
|
| AssignmentTaskBlockUserConfirmation
|
||||||
|
| AssignmentTaskBlockUserTextInput;
|
||||||
|
|
||||||
|
export interface AssignmentTask {
|
||||||
|
readonly type: "task";
|
||||||
|
readonly id: string;
|
||||||
|
readonly value: {
|
||||||
|
title: string;
|
||||||
|
file_submission_required: boolean;
|
||||||
|
content: AssignmentTaskBlock[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Assignment extends BaseCourseWagtailPage {
|
||||||
|
readonly type: "assignment.Assignment";
|
||||||
|
readonly starting_position: string;
|
||||||
|
readonly effort_required: string;
|
||||||
|
readonly performance_objectives: AssignmentPerformanceObjective[];
|
||||||
|
readonly assessment_description: string;
|
||||||
|
readonly assessment_document_url: string;
|
||||||
|
readonly tasks: AssignmentTask[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface PerformanceCriteria extends BaseCourseWagtailPage {
|
export interface PerformanceCriteria extends BaseCourseWagtailPage {
|
||||||
readonly type: "competence.PerformanceCriteria";
|
readonly type: "competence.PerformanceCriteria";
|
||||||
readonly competence_id: string;
|
readonly competence_id: string;
|
||||||
|
|
@ -348,6 +405,11 @@ export interface CourseSessionAttendanceDay {
|
||||||
trainer: string;
|
trainer: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CourseSessionAssignmentDetails {
|
||||||
|
learningContentId: number;
|
||||||
|
deadlineDateTimeUtc: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CourseSession {
|
export interface CourseSession {
|
||||||
id: number;
|
id: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|
@ -361,6 +423,7 @@ export interface CourseSession {
|
||||||
course_url: string;
|
course_url: string;
|
||||||
media_library_url: string;
|
media_library_url: string;
|
||||||
attendance_days: CourseSessionAttendanceDay[];
|
attendance_days: CourseSessionAttendanceDay[];
|
||||||
|
assignment_details_list: CourseSessionAssignmentDetails[];
|
||||||
documents: CircleDocument[];
|
documents: CircleDocument[];
|
||||||
users: CourseSessionUser[];
|
users: CourseSessionUser[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ LOCAL_APPS = [
|
||||||
"vbv_lernwelt.feedback",
|
"vbv_lernwelt.feedback",
|
||||||
"vbv_lernwelt.files",
|
"vbv_lernwelt.files",
|
||||||
"vbv_lernwelt.notify",
|
"vbv_lernwelt.notify",
|
||||||
|
"vbv_lernwelt.assignment",
|
||||||
]
|
]
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ urlpatterns = [
|
||||||
path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"),
|
path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"),
|
||||||
path(r"api/course/sessions/<course_slug>/users/", get_course_session_users,
|
path(r"api/course/sessions/<course_slug>/users/", get_course_session_users,
|
||||||
name="get_course_session_users"),
|
name="get_course_session_users"),
|
||||||
path(r"api/course/page/<slug>/", course_page_api_view,
|
path(r"api/course/page/<slug_or_id>/", course_page_api_view,
|
||||||
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"),
|
||||||
|
|
|
||||||
|
|
@ -540,7 +540,7 @@ wagtail==3.0.1
|
||||||
# wagtail-grapple
|
# wagtail-grapple
|
||||||
# wagtail-headless-preview
|
# wagtail-headless-preview
|
||||||
# wagtail-localize
|
# wagtail-localize
|
||||||
wagtail-factories==2.0.1
|
wagtail-factories==4.0.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
wagtail-grapple==0.18.0
|
wagtail-grapple==0.18.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ python-json-logger
|
||||||
concurrent-log-handler
|
concurrent-log-handler
|
||||||
|
|
||||||
wagtail>=3,<4
|
wagtail>=3,<4
|
||||||
wagtail-factories
|
wagtail-factories>=4
|
||||||
wagtail-localize
|
wagtail-localize
|
||||||
wagtail_grapple
|
wagtail_grapple
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,7 @@ wagtail==3.0.1
|
||||||
# wagtail-grapple
|
# wagtail-grapple
|
||||||
# wagtail-headless-preview
|
# wagtail-headless-preview
|
||||||
# wagtail-localize
|
# wagtail-localize
|
||||||
wagtail-factories==2.0.1
|
wagtail-factories==4.0.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
wagtail-grapple==0.18.0
|
wagtail-grapple==0.18.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "vbv_lernwelt.assignment"
|
||||||
|
|
@ -0,0 +1,285 @@
|
||||||
|
from vbv_lernwelt.assignment.models import TaskContentStreamBlock
|
||||||
|
from vbv_lernwelt.assignment.tests.assignment_factories import (
|
||||||
|
AssignmentFactory,
|
||||||
|
AssignmentListPageFactory,
|
||||||
|
ExplanationBlockFactory,
|
||||||
|
PerformanceObjectiveBlockFactory,
|
||||||
|
TaskBlockFactory,
|
||||||
|
UserTextInputBlockFactory,
|
||||||
|
)
|
||||||
|
from vbv_lernwelt.core.utils import replace_whitespace
|
||||||
|
from vbv_lernwelt.course.consts import COURSE_UK
|
||||||
|
from vbv_lernwelt.course.models import CoursePage
|
||||||
|
from wagtail.blocks import StreamValue
|
||||||
|
|
||||||
|
|
||||||
|
def create_uk_assignments(course_id=COURSE_UK):
|
||||||
|
course_page = CoursePage.objects.get(course_id=course_id)
|
||||||
|
assignment_page = AssignmentListPageFactory(
|
||||||
|
parent=course_page,
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment = AssignmentFactory(
|
||||||
|
parent=assignment_page,
|
||||||
|
title="Überprüfen einer Motorfahrzeugs-Versicherungspolice",
|
||||||
|
effort_required="ca. 5 Stunden",
|
||||||
|
starting_position=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Jemand aus deiner Familie oder aus deinem Freundeskreis möchte sein
|
||||||
|
Versicherungspolice überprüfen lassen. Diese Person kommt nun mit ihrer Police auf dich zu
|
||||||
|
und bittet dich als Versicherungsprofi, diese kritisch zu überprüfen und ihr ggf. Anpassungsvorschläge
|
||||||
|
zu unterbreiten. In diesem Kompetenznachweis kannst du nun dein Wissen und Können im Bereich
|
||||||
|
der Motorfahrzeugversicherung unter Beweis stellen.
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
performance_objectives=[
|
||||||
|
(
|
||||||
|
"performance_objective",
|
||||||
|
PerformanceObjectiveBlockFactory(
|
||||||
|
text="Sie erläutern die Leistungen und Produkte im Versicherungsbereich."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"performance_objective",
|
||||||
|
PerformanceObjectiveBlockFactory(
|
||||||
|
text="Sie beurteilen gängige Versicherungslösungen fachkundig."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
assessment_document_url="https://www.vbv.ch",
|
||||||
|
assessment_description="Diese geleitete Fallarbeit wird auf Grund des folgenden Beurteilungsintrument bewertet.",
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.tasks = []
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 1: Beispiel einer Versicherungspolice finden",
|
||||||
|
# it is hard to create a StreamValue programmatically, we have to
|
||||||
|
# create a `StreamValue` manually. Ask the Daniel and/or Ramon
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
ExplanationBlockFactory(text="Dies ist ein Beispieltext."),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_confirmation",
|
||||||
|
ExplanationBlockFactory(
|
||||||
|
text="Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 2: Kundensituation und Ausgangslage",
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
ExplanationBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Erläutere die Kundensituation und die Ausgangslage.
|
||||||
|
* Hast du alle Informationen, die du für den Policen-Check benötigst?
|
||||||
|
* Halte die wichtigsten Eckwerte des aktuellen Versicherungsverhältnisse in deiner Dokumentation fest (z.B wie lang wo versichert, Alter des Fahrzeugs, Kundenprofil, etc.)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("user_text_input", UserTextInputBlockFactory()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 3: Aktuelle Versicherung",
|
||||||
|
# TODO: add document upload
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
ExplanationBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Zeige nun detailliert auf, wie dein Kundenbeispiel momentan versichert ist.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("user_text_input", UserTextInputBlockFactory()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 4: Deine Empfehlungen",
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
ExplanationBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Erarbeite nun basierend auf deinen Erkenntnissen eine Empfehlung für die Person.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest? Begründe deine Empfehlung
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Gibt es Deckungen, die du streichen würdest? Begründe deine Empfehlung.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Wenn die Person gemäss deiner Einschätzung genau richtig versichert ist, argumentiere, warum dies der Fall ist.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 5: Reflexion",
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
ExplanationBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Reflektiere dein Handeln und halte deine Erkenntnisse fest. Frage dich dabei:
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
War die Bearbeitung dieser geleiteten Fallarbeit erfolgreich? Begründe deine Einschätzung.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Was ist dir bei der Bearbeitung des Auftrags gut gelungen?
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Was ist dir bei der Bearbeitung des Auftrags weniger gut gelungen?
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 6: Learnings",
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
ExplanationBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Leite aus der Teilaufgabe 5 deine persönlichen Learnings ab.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Was würdest du beim nächsten Mal anders machen?
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=replace_whitespace(
|
||||||
|
"""
|
||||||
|
Was hast du beim Bearbeiten des Auftrags Neues gelernt?
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assignment.save()
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
# Generated by Django 3.2.13 on 2023-04-11 09:30
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import wagtail.blocks
|
||||||
|
import wagtail.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import vbv_lernwelt.assignment.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("wagtailcore", "0069_log_entry_jsonfield"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Assignment",
|
||||||
|
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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"starting_position",
|
||||||
|
models.TextField(help_text="Erläuterung der Ausgangslage"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"effort_required",
|
||||||
|
models.CharField(
|
||||||
|
blank=True, help_text="Zeitaufwand als Text", max_length=100
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"performance_objectives",
|
||||||
|
wagtail.fields.StreamField(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"performance_objective",
|
||||||
|
wagtail.blocks.StructBlock(
|
||||||
|
[("text", wagtail.blocks.TextBlock())]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
blank=True,
|
||||||
|
help_text="Leistungsziele des Auftrags",
|
||||||
|
use_json_field=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"assessment_description",
|
||||||
|
models.TextField(
|
||||||
|
blank=True, help_text="Beschreibung der Bewertung"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"assessment_document_url",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
help_text="URL zum Beurteilungsinstrument",
|
||||||
|
max_length=255,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"tasks",
|
||||||
|
wagtail.fields.StreamField(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
wagtail.blocks.StructBlock(
|
||||||
|
[
|
||||||
|
("title", wagtail.blocks.TextBlock()),
|
||||||
|
(
|
||||||
|
"file_submission_required",
|
||||||
|
wagtail.blocks.BooleanBlock(required=False),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"content",
|
||||||
|
wagtail.blocks.StreamBlock(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"explanation",
|
||||||
|
wagtail.blocks.StructBlock(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"text",
|
||||||
|
wagtail.blocks.TextBlock(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
vbv_lernwelt.assignment.models.UserTextInputBlock(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_confirmation",
|
||||||
|
wagtail.blocks.StructBlock(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"text",
|
||||||
|
wagtail.blocks.TextBlock(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
blank=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
blank=True,
|
||||||
|
help_text="Teilaufgaben",
|
||||||
|
use_json_field=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Auftrag",
|
||||||
|
},
|
||||||
|
bases=("wagtailcore.page",),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="AssignmentListPage",
|
||||||
|
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={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
bases=("wagtailcore.page",),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
from django.db import models
|
||||||
|
from slugify import slugify
|
||||||
|
from wagtail import blocks
|
||||||
|
from wagtail.admin.panels import FieldPanel
|
||||||
|
from wagtail.fields import StreamField
|
||||||
|
from wagtail.models import Page
|
||||||
|
|
||||||
|
from vbv_lernwelt.core.model_utils import find_available_slug
|
||||||
|
from vbv_lernwelt.course.models import CourseBasePage
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentListPage(CourseBasePage):
|
||||||
|
subpage_types = ["assignment.Assignment"]
|
||||||
|
parent_page_types = ["course.CoursePage"]
|
||||||
|
|
||||||
|
def save(self, clean=True, user=None, log_action=False, **kwargs):
|
||||||
|
self.slug = find_available_slug(
|
||||||
|
slugify(f"{self.get_parent().slug}-assignment", allow_unicode=True)
|
||||||
|
)
|
||||||
|
super(AssignmentListPage, self).save(clean, user, log_action, **kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title}"
|
||||||
|
|
||||||
|
|
||||||
|
# class AssignmentSubmission(modModel):
|
||||||
|
# created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ExplanationBlock(blocks.StructBlock):
|
||||||
|
text = blocks.TextBlock()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
icon = "comment"
|
||||||
|
|
||||||
|
|
||||||
|
class PerformanceObjectiveBlock(blocks.StructBlock):
|
||||||
|
text = blocks.TextBlock()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
icon = "tick"
|
||||||
|
|
||||||
|
|
||||||
|
class UserTextInputBlock(blocks.StaticBlock):
|
||||||
|
text = blocks.TextBlock(blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
icon = "edit"
|
||||||
|
|
||||||
|
|
||||||
|
class UserConfirmationBlock(blocks.StructBlock):
|
||||||
|
text = blocks.TextBlock()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
icon = "tick-inverse"
|
||||||
|
|
||||||
|
|
||||||
|
class TaskContentStreamBlock(blocks.StreamBlock):
|
||||||
|
explanation = ExplanationBlock()
|
||||||
|
user_text_input = UserTextInputBlock()
|
||||||
|
user_confirmation = UserConfirmationBlock()
|
||||||
|
|
||||||
|
|
||||||
|
class TaskBlock(blocks.StructBlock):
|
||||||
|
title = blocks.TextBlock()
|
||||||
|
file_submission_required = blocks.BooleanBlock(required=False)
|
||||||
|
content = TaskContentStreamBlock(
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
icon = "tasks"
|
||||||
|
label = "Teilauftrag"
|
||||||
|
|
||||||
|
|
||||||
|
class Assignment(CourseBasePage):
|
||||||
|
serialize_field_names = [
|
||||||
|
"starting_position",
|
||||||
|
"effort_required",
|
||||||
|
"performance_objectives",
|
||||||
|
"assessment_description",
|
||||||
|
"assessment_document_url",
|
||||||
|
"tasks",
|
||||||
|
]
|
||||||
|
|
||||||
|
starting_position = models.TextField(help_text="Erläuterung der Ausgangslage")
|
||||||
|
effort_required = models.CharField(
|
||||||
|
max_length=100, help_text="Zeitaufwand als Text", blank=True
|
||||||
|
)
|
||||||
|
|
||||||
|
performance_objectives = StreamField(
|
||||||
|
[
|
||||||
|
("performance_objective", PerformanceObjectiveBlock()),
|
||||||
|
],
|
||||||
|
use_json_field=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Leistungsziele des Auftrags",
|
||||||
|
)
|
||||||
|
assessment_description = models.TextField(
|
||||||
|
blank=True, help_text="Beschreibung der Bewertung"
|
||||||
|
)
|
||||||
|
assessment_document_url = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
blank=True,
|
||||||
|
help_text="URL zum Beurteilungsinstrument",
|
||||||
|
)
|
||||||
|
|
||||||
|
tasks = StreamField(
|
||||||
|
[
|
||||||
|
("task", TaskBlock()),
|
||||||
|
],
|
||||||
|
use_json_field=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Teilaufgaben",
|
||||||
|
)
|
||||||
|
|
||||||
|
content_panels = Page.content_panels + [
|
||||||
|
FieldPanel("starting_position"),
|
||||||
|
FieldPanel("effort_required"),
|
||||||
|
FieldPanel("performance_objectives"),
|
||||||
|
FieldPanel("assessment_description"),
|
||||||
|
FieldPanel("assessment_document_url"),
|
||||||
|
FieldPanel("tasks"),
|
||||||
|
]
|
||||||
|
|
||||||
|
subpage_types = []
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Auftrag"
|
||||||
|
|
||||||
|
def save(self, clean=True, user=None, log_action=False, **kwargs):
|
||||||
|
self.slug = find_available_slug(
|
||||||
|
slugify(f"{self.get_parent().slug}-{self.title}", allow_unicode=True)
|
||||||
|
)
|
||||||
|
super(Assignment, self).save(clean, user, log_action, **kwargs)
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
import wagtail_factories
|
||||||
|
from factory import SubFactory
|
||||||
|
|
||||||
|
from vbv_lernwelt.assignment.models import (
|
||||||
|
Assignment,
|
||||||
|
AssignmentListPage,
|
||||||
|
ExplanationBlock,
|
||||||
|
PerformanceObjectiveBlock,
|
||||||
|
TaskBlock,
|
||||||
|
TaskContentStreamBlock,
|
||||||
|
UserConfirmationBlock,
|
||||||
|
UserTextInputBlock,
|
||||||
|
)
|
||||||
|
from vbv_lernwelt.core.utils import replace_whitespace
|
||||||
|
|
||||||
|
|
||||||
|
class ExplanationBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
|
text = "Dies ist ein Beispieltext."
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ExplanationBlock
|
||||||
|
|
||||||
|
|
||||||
|
class UserConfirmationBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
|
text = "Ja, ich habe Motorfahrzeugversicherungspolice von jemandem aus meiner Familie oder meinem Freundeskreis erhalten."
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = UserConfirmationBlock
|
||||||
|
|
||||||
|
|
||||||
|
class TaskContentStreamBlockFactory(wagtail_factories.StreamBlockFactory):
|
||||||
|
explanation = SubFactory(ExplanationBlockFactory)
|
||||||
|
user_confirmation = SubFactory(UserConfirmationBlockFactory)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TaskContentStreamBlock
|
||||||
|
|
||||||
|
|
||||||
|
class UserTextInputBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
|
class Meta:
|
||||||
|
model = UserTextInputBlock
|
||||||
|
|
||||||
|
|
||||||
|
class TaskBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
|
title = "Teilauftrag"
|
||||||
|
file_submission_required = False
|
||||||
|
content = TaskContentStreamBlockFactory()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TaskBlock
|
||||||
|
|
||||||
|
|
||||||
|
class PerformanceObjectiveBlockFactory(wagtail_factories.StructBlockFactory):
|
||||||
|
text = "Die Teilnehmer können die wichtigsten Eckwerte eines Versicherungsverhältnisses erfassen."
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = PerformanceObjectiveBlock
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentFactory(wagtail_factories.PageFactory):
|
||||||
|
title = "Auftrag"
|
||||||
|
starting_position = replace_whitespace(
|
||||||
|
"""
|
||||||
|
Jemand aus deiner Familie oder aus deinem Freundeskreis möchte sein
|
||||||
|
Versicherungspolice überprüfen lassen. Diese Person kommt nun mit ihrer Police auf dich zu
|
||||||
|
und bittet dich als Versicherungsprofi, diese kritisch zu überprüfen und ihr gg. Anpassungsvorschläge
|
||||||
|
zu unterbreiten. In diesem Kompetenznachweis kannst du nun dein Wissen und Können im Bereich
|
||||||
|
der Motorfahrzeugversicherung unter Beweis stellen.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Assignment
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentListPageFactory(wagtail_factories.PageFactory):
|
||||||
|
title = "Aufträge"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = AssignmentListPage
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -50,3 +51,7 @@ def first_true(iterable, default=False, pred=None):
|
||||||
# first_true([a,b,c], x) --> a or b or c or x
|
# first_true([a,b,c], x) --> a or b or c or x
|
||||||
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
|
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
|
||||||
return next(filter(pred, iterable), default)
|
return next(filter(pred, iterable), default)
|
||||||
|
|
||||||
|
|
||||||
|
def replace_whitespace(text, replacement=" "):
|
||||||
|
return re.sub(r"\s+", replacement, text).strip()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import djclick as click
|
import djclick as click
|
||||||
from wagtail.models import Page
|
from wagtail.models import Page
|
||||||
|
|
||||||
|
from vbv_lernwelt.assignment.creators.create_assignments import create_uk_assignments
|
||||||
from vbv_lernwelt.competence.create_uk_competence_profile import (
|
from vbv_lernwelt.competence.create_uk_competence_profile import (
|
||||||
create_uk_competence_profile,
|
create_uk_competence_profile,
|
||||||
create_uk_fr_competence_profile,
|
create_uk_fr_competence_profile,
|
||||||
|
|
@ -137,6 +138,7 @@ def create_course_uk_de():
|
||||||
create_versicherungsvermittlerin_with_categories(
|
create_versicherungsvermittlerin_with_categories(
|
||||||
course_id=COURSE_UK, title="Überbetriebliche Kurse"
|
course_id=COURSE_UK, title="Überbetriebliche Kurse"
|
||||||
)
|
)
|
||||||
|
create_uk_assignments(course_id=COURSE_UK)
|
||||||
create_uk_learning_path(course_id=COURSE_UK)
|
create_uk_learning_path(course_id=COURSE_UK)
|
||||||
create_uk_competence_profile(course_id=COURSE_UK)
|
create_uk_competence_profile(course_id=COURSE_UK)
|
||||||
create_default_media_library(course_id=COURSE_UK)
|
create_default_media_library(course_id=COURSE_UK)
|
||||||
|
|
@ -156,6 +158,14 @@ def create_course_uk_de():
|
||||||
"trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
|
"trainer": "Roland Grossenbacher, roland.grossenbacher@helvetia.ch",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
assignment_details_list=[
|
||||||
|
{
|
||||||
|
"learningContentId": LearningContent.objects.get(
|
||||||
|
slug="überbetriebliche-kurse-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"
|
||||||
|
).id,
|
||||||
|
"deadlineDateTimeUtc": "2023-05-30T19:00:00Z",
|
||||||
|
}
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# figma demo users and data
|
# figma demo users and data
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ from slugify import slugify
|
||||||
from wagtail.models import Locale, Page, Site
|
from wagtail.models import Locale, Page, Site
|
||||||
from wagtail_localize.models import LocaleSynchronization
|
from wagtail_localize.models import LocaleSynchronization
|
||||||
|
|
||||||
|
from vbv_lernwelt.assignment.models import Assignment
|
||||||
from vbv_lernwelt.core.admin import User
|
from vbv_lernwelt.core.admin import User
|
||||||
from vbv_lernwelt.course.consts import COURSE_UK, COURSE_UK_FR
|
from vbv_lernwelt.course.consts import COURSE_UK, COURSE_UK_FR
|
||||||
from vbv_lernwelt.course.models import CoursePage
|
from vbv_lernwelt.course.models import CoursePage
|
||||||
from vbv_lernwelt.learnpath.tests.learning_path_factories import (
|
from vbv_lernwelt.learnpath.tests.learning_path_factories import (
|
||||||
|
AssignmentBlockFactory,
|
||||||
AttendanceDayBlockFactory,
|
AttendanceDayBlockFactory,
|
||||||
CircleFactory,
|
CircleFactory,
|
||||||
FeedbackBlockFactory,
|
FeedbackBlockFactory,
|
||||||
|
|
@ -282,6 +284,20 @@ damit du erfolgreich mit deinem Lernpfad (durch-)starten kannst.
|
||||||
title="Reflexion",
|
title="Reflexion",
|
||||||
parent=circle,
|
parent=circle,
|
||||||
)
|
)
|
||||||
|
LearningContentFactory(
|
||||||
|
title="Überprüfen einer Motorfahrzeug-Versicherungspolice",
|
||||||
|
parent=circle,
|
||||||
|
contents=[
|
||||||
|
(
|
||||||
|
"assignment",
|
||||||
|
AssignmentBlockFactory(
|
||||||
|
assignment=Assignment.objects.get(
|
||||||
|
slug__startswith="überbetriebliche-kurse-assignment-überprüfen-einer-motorfahrzeugs"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
LearningContentFactory(
|
LearningContentFactory(
|
||||||
title="Feedback",
|
title="Feedback",
|
||||||
parent=circle,
|
parent=circle,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.13 on 2023-04-06 09:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("course", "0003_auto_20230404_0837"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="coursesession",
|
||||||
|
name="assignment_details_list",
|
||||||
|
field=models.JSONField(blank=True, default=list),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -121,6 +121,7 @@ class CoursePage(CourseBasePage):
|
||||||
"learnpath.LearningPath",
|
"learnpath.LearningPath",
|
||||||
"competence.CompetenceProfilePage",
|
"competence.CompetenceProfilePage",
|
||||||
"media_library.MediaLibraryPage",
|
"media_library.MediaLibraryPage",
|
||||||
|
"assignment.AssignmentListPage",
|
||||||
]
|
]
|
||||||
course = models.OneToOneField("course.Course", on_delete=models.PROTECT)
|
course = models.OneToOneField("course.Course", on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
|
@ -185,6 +186,7 @@ class CourseSession(models.Model):
|
||||||
end_date = models.DateField(null=True, blank=True)
|
end_date = models.DateField(null=True, blank=True)
|
||||||
|
|
||||||
attendance_days = models.JSONField(default=list, blank=True)
|
attendance_days = models.JSONField(default=list, blank=True)
|
||||||
|
assignment_details_list = models.JSONField(default=list, blank=True)
|
||||||
|
|
||||||
additional_json_data = models.JSONField(default=dict, blank=True)
|
additional_json_data = models.JSONField(default=dict, blank=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
||||||
"end_date",
|
"end_date",
|
||||||
"additional_json_data",
|
"additional_json_data",
|
||||||
"attendance_days",
|
"attendance_days",
|
||||||
|
"assignment_details_list",
|
||||||
"learning_path_url",
|
"learning_path_url",
|
||||||
"competence_url",
|
"competence_url",
|
||||||
"media_library_url",
|
"media_library_url",
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,12 @@ logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
def course_page_api_view(request, slug):
|
def course_page_api_view(request, slug_or_id):
|
||||||
try:
|
try:
|
||||||
page = Page.objects.get(slug=slug, locale__language_code="de-CH")
|
if slug_or_id.isdigit():
|
||||||
|
page = Page.objects.get(id=slug_or_id)
|
||||||
|
else:
|
||||||
|
page = Page.objects.get(slug=slug_or_id, 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):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.2.13 on 2023-04-03 16:05
|
# Generated by Django 3.2.13 on 2023-04-04 08:28
|
||||||
|
|
||||||
import wagtail.blocks
|
import wagtail.blocks
|
||||||
import wagtail.fields
|
import wagtail.fields
|
||||||
|
|
@ -104,8 +104,13 @@ class Migration(migrations.Migration):
|
||||||
wagtail.blocks.StructBlock(
|
wagtail.blocks.StructBlock(
|
||||||
[
|
[
|
||||||
("description", wagtail.blocks.TextBlock()),
|
("description", wagtail.blocks.TextBlock()),
|
||||||
("url", wagtail.blocks.TextBlock()),
|
(
|
||||||
("text", wagtail.blocks.RichTextBlock(required=False)),
|
"assignment",
|
||||||
|
wagtail.blocks.PageChooserBlock(
|
||||||
|
help_text="Choose the corresponding assignment.",
|
||||||
|
required=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
from wagtail import blocks
|
from wagtail import blocks
|
||||||
|
from wagtail.blocks import PageChooserBlock
|
||||||
|
|
||||||
|
|
||||||
class AssignmentBlock(blocks.StructBlock):
|
class AssignmentBlock(blocks.StructBlock):
|
||||||
description = blocks.TextBlock()
|
description = blocks.TextBlock()
|
||||||
url = blocks.TextBlock()
|
assignment = PageChooserBlock(
|
||||||
text = blocks.RichTextBlock(required=False)
|
required=True, help_text="Choose the corresponding assignment."
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
icon = "media"
|
icon = "media"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue