Merged in feature/completion-check-permissions (pull request #19)
Feature/completion check permissions Approved-by: Christian Cueni
This commit is contained in:
commit
dcf42934b1
|
|
@ -84,7 +84,7 @@ function showFileInformation() {
|
|||
{{ $t("circlePage.documents.fileLabel") }}
|
||||
</label>
|
||||
<div class="mb-4 btn-secondary mt-4 text-xl relative cursor-pointer">
|
||||
<input @change="fileChange" id="upload" type="file" class="absolute opacity-0" />
|
||||
<input id="upload" type="file" class="absolute opacity-0" @change="fileChange" />
|
||||
{{ $t("circlePage.documents.modalAction") }}
|
||||
</div>
|
||||
<div v-if="showFileInformation()" class="mb-4">
|
||||
|
|
@ -100,7 +100,7 @@ function showFileInformation() {
|
|||
<label class="block text-bold mb-4" for="name">
|
||||
{{ $t("circlePage.documents.modalFileName") }}
|
||||
</label>
|
||||
<input v-model="formData.name" id="name" type="text" class="w-1/2 mb-2" />
|
||||
<input id="name" v-model="formData.name" type="text" class="w-1/2 mb-2" />
|
||||
<p>{{ $t("circlePage.documents.modalNameInformation") }}</p>
|
||||
<div v-if="formErrors.name">
|
||||
<p class="text-red-700">{{ $t("circlePage.documents.chooseName") }}</p>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ import type { LearningPath } from "@/services/learningPath";
|
|||
import { useCockpitStore } from "@/stores/cockpit";
|
||||
import { useCompetenceStore } from "@/stores/competence";
|
||||
import { useLearningPathStore } from "@/stores/learningPath";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import log from "loglevel";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
courseSlug: string;
|
||||
|
|
@ -15,6 +17,7 @@ const props = defineProps<{
|
|||
|
||||
log.debug("CockpitIndexPage created", props.courseSlug);
|
||||
|
||||
const userStore = useUserStore();
|
||||
const cockpitStore = useCockpitStore();
|
||||
const competenceStore = useCompetenceStore();
|
||||
const learningPathStore = useLearningPathStore();
|
||||
|
|
@ -25,6 +28,33 @@ function userCountStatus(userId: number) {
|
|||
);
|
||||
}
|
||||
|
||||
const circles = computed(() => {
|
||||
const learningPathCircles = learningPathStore
|
||||
.learningPathForUser(props.courseSlug, userStore.id)
|
||||
?.circles.map((c) => {
|
||||
return {
|
||||
id: c.id,
|
||||
title: c.title,
|
||||
slug: c.slug,
|
||||
translation_key: c.translation_key,
|
||||
};
|
||||
});
|
||||
|
||||
if (cockpitStore.cockpitSessionUser?.circles?.length) {
|
||||
return cockpitStore.cockpitSessionUser.circles;
|
||||
} else if (learningPathCircles) {
|
||||
return learningPathCircles;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const selectedCirclesTitles = computed(() => {
|
||||
return circles.value
|
||||
.filter((c) => cockpitStore.selectedCircles.includes(c.translation_key))
|
||||
.map((c) => c.title);
|
||||
});
|
||||
|
||||
const data = {
|
||||
transferProgress: {
|
||||
fail: 0,
|
||||
|
|
@ -47,7 +77,7 @@ function setActiveClasses(translationKey: string) {
|
|||
<h1 class="heading-3">{{ $t("general.circles") }}:</h1>
|
||||
<ul class="flex flex-row leading-7 text-base font-bold ml-4">
|
||||
<li
|
||||
v-for="circle in cockpitStore.circles"
|
||||
v-for="circle in circles"
|
||||
:key="circle.translation_key"
|
||||
class="mr-4 last:mr-0"
|
||||
>
|
||||
|
|
@ -132,10 +162,7 @@ function setActiveClasses(translationKey: string) {
|
|||
></LearningPathDiagram>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
v-for="title in cockpitStore.selectedCirclesTitles"
|
||||
:key="title"
|
||||
>
|
||||
<span v-for="title in selectedCirclesTitles" :key="title">
|
||||
{{ title }}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useCockpitStore } from "@/stores/cockpit";
|
||||
import { useCompetenceStore } from "@/stores/competence";
|
||||
import { useLearningPathStore } from "@/stores/learningPath";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import * as log from "loglevel";
|
||||
import { onMounted } from "vue";
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ onMounted(async () => {
|
|||
|
||||
learningPathStore.loadLearningPath(props.courseSlug + "-lp", csu.user_id);
|
||||
});
|
||||
learningPathStore.loadLearningPath(props.courseSlug + "-lp", useUserStore().id);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,6 +276,20 @@ async function uploadDocument(data: DocumentUploadData) {
|
|||
})
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
v-for="expert in courseSessionsStore.circleExperts"
|
||||
:key="expert.user_id"
|
||||
>
|
||||
<div class="flex flex-row items-center mt-2 mb-2">
|
||||
<img
|
||||
class="h-[45px] rounded-full mr-2"
|
||||
:src="expert.avatar_url"
|
||||
/>
|
||||
<p class="lg:leading-[45px]">
|
||||
{{ expert.first_name }} {{ expert.last_name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-secondary mt-4 text-xl">
|
||||
{{ $t("circlePage.contactExpertButton") }}
|
||||
</button>
|
||||
|
|
@ -302,10 +316,10 @@ async function uploadDocument(data: DocumentUploadData) {
|
|||
<template #title>{{ $t("circlePage.documents.action") }}</template>
|
||||
<template #body>
|
||||
<DocumentUploadForm
|
||||
@form-submit="uploadDocument"
|
||||
:learning-sequences="dropdownLearningSequences"
|
||||
:show-upload-error-message="showUploadErrorMessage"
|
||||
:is-uploading="isUploading"
|
||||
@form-submit="uploadDocument"
|
||||
/>
|
||||
</template>
|
||||
</ItModal>
|
||||
|
|
|
|||
|
|
@ -1,59 +1,59 @@
|
|||
{
|
||||
"id": 362,
|
||||
"id": 568,
|
||||
"title": "Test Lernpfad",
|
||||
"slug": "test-lehrgang-lp",
|
||||
"type": "learnpath.LearningPath",
|
||||
"translation_key": "8a230aa1-075e-4ac1-a8d6-87642c4f33ba",
|
||||
"frontend_url": "/learn/test-lehrgang-lp",
|
||||
"translation_key": "25ddc136-af7d-4a74-8731-896281bfe20b",
|
||||
"frontend_url": "/course/test-lehrgang/learn",
|
||||
"children": [
|
||||
{
|
||||
"id": 363,
|
||||
"id": 569,
|
||||
"title": "Basis",
|
||||
"slug": "test-lehrgang-lp-topic-basis",
|
||||
"type": "learnpath.Topic",
|
||||
"translation_key": "d6e14156-2fb9-4f1b-83ce-6879e364f9a2",
|
||||
"translation_key": "8cb75aee-0349-41e2-9d2b-2938c2b04891",
|
||||
"frontend_url": "",
|
||||
"is_visible": false
|
||||
},
|
||||
{
|
||||
"id": 364,
|
||||
"id": 570,
|
||||
"title": "Basis",
|
||||
"slug": "test-lehrgang-lp-circle-basis",
|
||||
"type": "learnpath.Circle",
|
||||
"translation_key": "8034e867-4b05-4509-a9bc-99f9f3619e88",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis",
|
||||
"translation_key": "aaa04c2b-03bf-470e-b414-bd8203db529d",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis",
|
||||
"children": [
|
||||
{
|
||||
"id": 365,
|
||||
"id": 571,
|
||||
"title": "Starten",
|
||||
"slug": "test-lehrgang-lp-circle-basis-ls-starten",
|
||||
"type": "learnpath.LearningSequence",
|
||||
"translation_key": "868bc4cb-c5b5-423e-a890-433184cd06e0",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis#ls-starten",
|
||||
"translation_key": "ce16116f-f4ed-4fc0-a95a-cc75ba88958d",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis#ls-starten",
|
||||
"icon": "it-icon-ls-start"
|
||||
},
|
||||
{
|
||||
"id": 366,
|
||||
"id": 572,
|
||||
"title": "Einf\u00fchrung",
|
||||
"slug": "test-lehrgang-lp-circle-basis-lu-einf\u00fchrung",
|
||||
"type": "learnpath.LearningUnit",
|
||||
"translation_key": "6b0a4794-9861-4ea4-b422-99261a4347a6",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis#lu-einf\u00fchrung",
|
||||
"evaluate_url": "/learn/test-lehrgang-lp/basis/evaluate/einf\u00fchrung",
|
||||
"translation_key": "33863daf-a503-425d-a1a2-9a711f8256a5",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis#lu-einf\u00fchrung",
|
||||
"evaluate_url": "/course/test-lehrgang/learn/basis/evaluate/einf\u00fchrung",
|
||||
"course_category": {
|
||||
"id": 14,
|
||||
"id": 27,
|
||||
"title": "Allgemein",
|
||||
"general": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": 367,
|
||||
"id": 573,
|
||||
"title": "Einf\u00fchrung",
|
||||
"slug": "test-lehrgang-lp-circle-basis-lc-einf\u00fchrung",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "d1d1b923-f597-4de7-ac44-d02c2f0a1a59",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis/einf\u00fchrung",
|
||||
"translation_key": "ae19458c-9b08-4b9c-9e7c-62c3cce4a6cc",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis/einf\u00fchrung",
|
||||
"minutes": 15,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -62,41 +62,41 @@
|
|||
"description": "Beispiel Dokument",
|
||||
"url": null
|
||||
},
|
||||
"id": "9f22d0b7-643a-4e97-816a-a41141befc95"
|
||||
"id": "601ac5e1-b268-442e-b15b-26ead06bdf77"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 368,
|
||||
"id": 574,
|
||||
"title": "Beenden",
|
||||
"slug": "test-lehrgang-lp-circle-basis-ls-beenden",
|
||||
"type": "learnpath.LearningSequence",
|
||||
"translation_key": "338208db-7c85-470e-872f-850e34747873",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis#ls-beenden",
|
||||
"translation_key": "3c167825-a358-4c62-a632-9482e9fbfe5f",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis#ls-beenden",
|
||||
"icon": "it-icon-ls-end"
|
||||
},
|
||||
{
|
||||
"id": 369,
|
||||
"id": 575,
|
||||
"title": "Beenden",
|
||||
"slug": "test-lehrgang-lp-circle-basis-lu-beenden",
|
||||
"type": "learnpath.LearningUnit",
|
||||
"translation_key": "c14b63d6-3144-41fa-8a3c-2eada6ddd5ea",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis#lu-beenden",
|
||||
"evaluate_url": "/learn/test-lehrgang-lp/basis/evaluate/beenden",
|
||||
"translation_key": "9a70a164-0468-4681-a6ed-a1b636db1ae6",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis#lu-beenden",
|
||||
"evaluate_url": "/course/test-lehrgang/learn/basis/evaluate/beenden",
|
||||
"course_category": {
|
||||
"id": 14,
|
||||
"id": 27,
|
||||
"title": "Allgemein",
|
||||
"general": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": 370,
|
||||
"id": 576,
|
||||
"title": "Jetzt kann es losgehen!",
|
||||
"slug": "test-lehrgang-lp-circle-basis-lc-jetzt-kann-es-losgehen",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "6920bcac-597b-462a-9458-32aa5dc8d3f7",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/basis/jetzt-kann-es-losgehen",
|
||||
"translation_key": "f251beda-a4b8-4a49-89a6-8c52d335b140",
|
||||
"frontend_url": "/course/test-lehrgang/learn/basis/jetzt-kann-es-losgehen",
|
||||
"minutes": 30,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
"description": "Beispiel Dokument",
|
||||
"url": null
|
||||
},
|
||||
"id": "1422a7c3-0a9a-4321-88a0-d82d0ed26ba2"
|
||||
"id": "1075443f-e2e5-46eb-87c4-804f0227a858"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -116,17 +116,17 @@
|
|||
{
|
||||
"type": "goal",
|
||||
"value": "... hier ein Beispieltext f\u00fcr ein Ziel 1",
|
||||
"id": "38afbda4-7b7e-4f5c-88e8-c595c43e1659"
|
||||
"id": "6c227ac1-42a7-4ca3-bde2-8531bf655481"
|
||||
},
|
||||
{
|
||||
"type": "goal",
|
||||
"value": "... hier ein Beispieltext f\u00fcr ein Ziel 2",
|
||||
"id": "4d00ac58-0499-4316-9af2-356c37dedc35"
|
||||
"id": "7c466321-abe3-4705-bbb1-f286a8e5c800"
|
||||
},
|
||||
{
|
||||
"type": "goal",
|
||||
"value": "... hier ein Beispieltext f\u00fcr ein Ziel 3",
|
||||
"id": "945eb104-8cc1-45cd-a07a-a4d3ec4f39a3"
|
||||
"id": "1e491838-62a9-4185-b321-f64ca7c99f36"
|
||||
}
|
||||
],
|
||||
"job_situation_description": "Du triffst in diesem Circle auf die folgenden berufstypischen Handlungsfelder:",
|
||||
|
|
@ -134,101 +134,88 @@
|
|||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 1",
|
||||
"id": "02fb807a-0d07-4353-81ec-8b8b383954d7"
|
||||
"id": "0d4a66de-523c-4659-9b4b-bb81cef28961"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 2",
|
||||
"id": "371952f6-5871-4bf1-b423-d3dab7371001"
|
||||
"id": "dc4d8157-1db4-4e64-bc0c-00a35159c32d"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 3",
|
||||
"id": "116bfa7b-65e8-44a1-8c82-e8b05fd86a01"
|
||||
"id": "a270baca-1077-4535-9a9f-5562af9854d8"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 4",
|
||||
"id": "08baf7dd-8801-4af9-8af8-714989775ddb"
|
||||
"id": "aa4b21f6-0bd3-40f3-8589-c43e4524f565"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 5",
|
||||
"id": "93ade4b8-c4fb-4941-98c5-e58336fca4bb"
|
||||
"id": "8618d1e7-c628-42ef-aac3-201b2b65393f"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 6",
|
||||
"id": "1fac4ee4-6d86-4e9e-9fa4-a99c6659bc8b"
|
||||
"id": "be7a2a59-2aef-4dd8-ad8d-17c4a46b064f"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Job Situation 7",
|
||||
"id": "06d1e273-dec8-4a0b-ae2c-2baeb7a19ec7"
|
||||
}
|
||||
],
|
||||
"experts": [
|
||||
{
|
||||
"type": "person",
|
||||
"value": {
|
||||
"first_name": "Patrizia",
|
||||
"last_name": "Mustermann",
|
||||
"email": "patrizia.mustermann@example.com",
|
||||
"photo": null,
|
||||
"biography": ""
|
||||
},
|
||||
"id": "83490f33-da54-4548-baac-af75ea36651e"
|
||||
"id": "a4b74338-abd7-4de8-82ab-d77664f6cbbf"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 371,
|
||||
"id": 577,
|
||||
"title": "Beraten der Kunden",
|
||||
"slug": "test-lehrgang-lp-topic-beraten-der-kunden",
|
||||
"type": "learnpath.Topic",
|
||||
"translation_key": "728a2578-a22c-41df-9079-43a5318c5030",
|
||||
"translation_key": "2ea6ea41-b839-4462-aea4-1796b0f9849d",
|
||||
"frontend_url": "",
|
||||
"is_visible": true
|
||||
},
|
||||
{
|
||||
"id": 372,
|
||||
"id": 578,
|
||||
"title": "Analyse",
|
||||
"slug": "test-lehrgang-lp-circle-analyse",
|
||||
"type": "learnpath.Circle",
|
||||
"translation_key": "e429adf5-dd5d-4699-b471-40c782fb507e",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse",
|
||||
"translation_key": "dbc95ecd-0fdf-4b0a-ba91-7eec88a420f3",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse",
|
||||
"children": [
|
||||
{
|
||||
"id": 373,
|
||||
"id": 579,
|
||||
"title": "Starten",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-ls-starten",
|
||||
"type": "learnpath.LearningSequence",
|
||||
"translation_key": "40e977e0-3668-418d-b838-d3774a5cbe7d",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#ls-starten",
|
||||
"translation_key": "9b10c6ec-e313-49fa-b09d-9639429254f9",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#ls-starten",
|
||||
"icon": "it-icon-ls-start"
|
||||
},
|
||||
{
|
||||
"id": 374,
|
||||
"id": 580,
|
||||
"title": "Einf\u00fchrung",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lu-einf\u00fchrung",
|
||||
"type": "learnpath.LearningUnit",
|
||||
"translation_key": "badfd186-26c1-433e-90ad-8cac52eb599f",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#lu-einf\u00fchrung",
|
||||
"evaluate_url": "/learn/test-lehrgang-lp/analyse/evaluate/einf\u00fchrung",
|
||||
"translation_key": "f51ab860-bc23-4f59-bb88-0e8506ef42e5",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#lu-einf\u00fchrung",
|
||||
"evaluate_url": "/course/test-lehrgang/learn/analyse/evaluate/einf\u00fchrung",
|
||||
"course_category": {
|
||||
"id": 14,
|
||||
"id": 27,
|
||||
"title": "Allgemein",
|
||||
"general": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": 375,
|
||||
"id": 581,
|
||||
"title": "Einleitung Circle \"Analyse\"",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-einleitung-circle-analyse",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "5e8d6478-6287-4658-94c5-ecbd5d624962",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/einleitung-circle-analyse",
|
||||
"translation_key": "70363615-2a53-478d-82f7-0aa02744f559",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/einleitung-circle-analyse",
|
||||
"minutes": 15,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -237,60 +224,60 @@
|
|||
"description": "Beispiel Dokument",
|
||||
"url": null
|
||||
},
|
||||
"id": "8b7f183e-1879-4391-953f-52d9a621f435"
|
||||
"id": "174d883b-1bd0-4bee-872d-d08c2544dc3a"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 376,
|
||||
"id": 582,
|
||||
"title": "Beobachten",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-ls-beobachten",
|
||||
"type": "learnpath.LearningSequence",
|
||||
"translation_key": "35df96df-2e8d-4f16-aee1-8d72990f63a0",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#ls-beobachten",
|
||||
"translation_key": "0a540c5a-25c8-42ab-8661-6c08c78d91c2",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#ls-beobachten",
|
||||
"icon": "it-icon-ls-watch"
|
||||
},
|
||||
{
|
||||
"id": 377,
|
||||
"id": 583,
|
||||
"title": "Fahrzeug",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lu-fahrzeug",
|
||||
"type": "learnpath.LearningUnit",
|
||||
"translation_key": "405d42e4-ee10-4453-8e5f-82e49bb4d597",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#lu-fahrzeug",
|
||||
"evaluate_url": "/learn/test-lehrgang-lp/analyse/evaluate/fahrzeug",
|
||||
"translation_key": "f072e5b2-c033-4d7d-9dae-28e6b856087c",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#lu-fahrzeug",
|
||||
"evaluate_url": "/course/test-lehrgang/learn/analyse/evaluate/fahrzeug",
|
||||
"course_category": {
|
||||
"id": 15,
|
||||
"id": 28,
|
||||
"title": "Fahrzeug",
|
||||
"general": false
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": 391,
|
||||
"id": 597,
|
||||
"title": "Innerhalb des Handlungsfelds \u00abFahrzeug\u00bb bin ich f\u00e4hig, die Ziele und Pl\u00e4ne des Kunden zu ergr\u00fcnden (SOLL).",
|
||||
"slug": "test-lehrgang-competence-crit-y13-fahrzeug",
|
||||
"type": "competence.PerformanceCriteria",
|
||||
"translation_key": "3b714984-afdb-4456-9c01-a59064724929",
|
||||
"translation_key": "7d76cdd3-57a0-4f82-bc33-fcc8a78b15e0",
|
||||
"frontend_url": "",
|
||||
"competence_id": "Y1.3"
|
||||
},
|
||||
{
|
||||
"id": 392,
|
||||
"id": 598,
|
||||
"title": "Innerhalb des Handlungsfelds \u00abFahrzeug\u00bb bin ich f\u00e4hig, die IST-Situation des Kunden mit der geeigneten Gespr\u00e4chs-/Fragetechnik zu erfassen.",
|
||||
"slug": "test-lehrgang-competence-crit-y21-fahrzeug",
|
||||
"type": "competence.PerformanceCriteria",
|
||||
"translation_key": "c2850a27-60c5-471b-9fec-ba0baf152e91",
|
||||
"translation_key": "5b3e1105-a12b-4d99-984c-28f01daeef54",
|
||||
"frontend_url": "",
|
||||
"competence_id": "Y2.1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 378,
|
||||
"id": 584,
|
||||
"title": "Rafael Fasel wechselt sein Auto",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-rafael-fasel-wechselt-sein-auto",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "b7779d45-adf4-41fc-a4a5-e95c732b2224",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/rafael-fasel-wechselt-sein-auto",
|
||||
"translation_key": "ff254250-d010-4f57-9e57-987c343029a6",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/rafael-fasel-wechselt-sein-auto",
|
||||
"minutes": 30,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -299,17 +286,17 @@
|
|||
"description": "In diesem Online-Training lernst du, wie du den Kundenbedarf ermittelst.",
|
||||
"url": ""
|
||||
},
|
||||
"id": "c79d34cb-0e7e-403d-a672-03d94cf6bdc7"
|
||||
"id": "454fb0d8-c37d-4c8e-b15c-c50a32be9fd7"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 379,
|
||||
"id": 585,
|
||||
"title": "Fachcheck Fahrzeug",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-fachcheck-fahrzeug",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "e395e05c-81bf-4bc6-98e8-3833bebb551c",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/fachcheck-fahrzeug",
|
||||
"translation_key": "b0a95253-3a63-4d77-9ddc-961b711175a5",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/fachcheck-fahrzeug",
|
||||
"minutes": 30,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -318,42 +305,42 @@
|
|||
"description": "Beispiel Test",
|
||||
"url": null
|
||||
},
|
||||
"id": "ac4c67bc-7de9-4e5c-a35e-e13f5766d6cc"
|
||||
"id": "4b3e40c5-f5f9-4726-bc4c-0d914a029f83"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 380,
|
||||
"id": 586,
|
||||
"title": "Reisen",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lu-reisen",
|
||||
"type": "learnpath.LearningUnit",
|
||||
"translation_key": "d0c956cc-3c86-4e08-9990-ed4e85d03219",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#lu-reisen",
|
||||
"evaluate_url": "/learn/test-lehrgang-lp/analyse/evaluate/reisen",
|
||||
"translation_key": "22bcb754-d5c5-413b-b63e-76e6406afef9",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#lu-reisen",
|
||||
"evaluate_url": "/course/test-lehrgang/learn/analyse/evaluate/reisen",
|
||||
"course_category": {
|
||||
"id": 16,
|
||||
"id": 29,
|
||||
"title": "Reisen",
|
||||
"general": false
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": 393,
|
||||
"id": 599,
|
||||
"title": "Innerhalb des Handlungsfelds \u00abReisen\u00bb bin ich f\u00e4hig, die Ziele und Pl\u00e4ne des Kunden zu ergr\u00fcnden (SOLL).",
|
||||
"slug": "test-lehrgang-competence-crit-y13-reisen",
|
||||
"type": "competence.PerformanceCriteria",
|
||||
"translation_key": "1df45a12-41f2-4ff5-8580-d5a7caf5dd56",
|
||||
"translation_key": "6a3ce4ac-0d38-4a02-81fa-0979290142e1",
|
||||
"frontend_url": "",
|
||||
"competence_id": "Y1.3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 381,
|
||||
"id": 587,
|
||||
"title": "Reiseversicherung",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-reiseversicherung",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "bad7439a-8b0c-4877-8d6c-78f292be83d4",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/reiseversicherung",
|
||||
"translation_key": "cb1c9c93-7f3b-42d6-9078-2d36655fdfd7",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/reiseversicherung",
|
||||
"minutes": 240,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -362,60 +349,60 @@
|
|||
"description": "Beispiel \u00dcbung",
|
||||
"url": null
|
||||
},
|
||||
"id": "7e1ee533-7f75-495b-a2bc-8bbd2b1311c9"
|
||||
"id": "b59bccb2-bcb2-48cc-8204-8df94723975b"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 382,
|
||||
"id": 588,
|
||||
"title": "Emma und Ayla campen durch Amerika",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-emma-und-ayla-campen-durch-amerika",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "27f9d8f3-209c-4d55-94d9-2e70fbfe163b",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/emma-und-ayla-campen-durch-amerika",
|
||||
"translation_key": "fdf19afe-fe69-496d-a1d4-ecf18ed36b01",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/emma-und-ayla-campen-durch-amerika",
|
||||
"minutes": 120,
|
||||
"contents": [
|
||||
{
|
||||
"type": "exercise",
|
||||
"type": "learningmodule",
|
||||
"value": {
|
||||
"description": "Beispiel \u00dcbung",
|
||||
"description": "Beispiel Lernmodul",
|
||||
"url": "/static/media/web_based_trainings/story-06-a-01-emma-und-ayla-campen-durch-amerika-einstieg/scormcontent/index.html"
|
||||
},
|
||||
"id": "b08e1851-8583-4428-b1bc-402c7095130b"
|
||||
"id": "c3a14f9f-3491-4695-9544-a3b2a2c3a82a"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 383,
|
||||
"id": 589,
|
||||
"title": "Beenden",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-ls-beenden",
|
||||
"type": "learnpath.LearningSequence",
|
||||
"translation_key": "68be244d-0e00-4700-834c-57b4db366fc1",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#ls-beenden",
|
||||
"translation_key": "28ffad90-9333-452f-af18-108d4aff5ee4",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#ls-beenden",
|
||||
"icon": "it-icon-ls-end"
|
||||
},
|
||||
{
|
||||
"id": 384,
|
||||
"id": 590,
|
||||
"title": "Beenden",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lu-beenden",
|
||||
"type": "learnpath.LearningUnit",
|
||||
"translation_key": "d594db87-ad78-491b-bf1b-410adfa3a0ba",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse#lu-beenden",
|
||||
"evaluate_url": "/learn/test-lehrgang-lp/analyse/evaluate/beenden",
|
||||
"translation_key": "05a1cb34-e8d8-44e2-9635-5e33a852bfa2",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse#lu-beenden",
|
||||
"evaluate_url": "/course/test-lehrgang/learn/analyse/evaluate/beenden",
|
||||
"course_category": {
|
||||
"id": 14,
|
||||
"id": 27,
|
||||
"title": "Allgemein",
|
||||
"general": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": 385,
|
||||
"id": 591,
|
||||
"title": "KompetenzNavi anschauen",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-kompetenznavi-anschauen",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "8ee57ba5-e09e-4058-937a-b733ea72b969",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/kompetenznavi-anschauen",
|
||||
"translation_key": "b90e7ddc-fcde-47aa-91e1-abd67ed96e66",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/kompetenznavi-anschauen",
|
||||
"minutes": 30,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -424,17 +411,17 @@
|
|||
"description": "Beispiel Dokument",
|
||||
"url": null
|
||||
},
|
||||
"id": "3ef87e69-5e5c-415a-934c-ed47ad9fdd93"
|
||||
"id": "a7faefea-4cd1-471a-aed1-c780d8236301"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 386,
|
||||
"id": 592,
|
||||
"title": "Circle \"Analyse\" abschliessen",
|
||||
"slug": "test-lehrgang-lp-circle-analyse-lc-circle-analyse-abschliessen",
|
||||
"type": "learnpath.LearningContent",
|
||||
"translation_key": "90d9ab63-cc0f-492f-aad1-f7d448ee5b2c",
|
||||
"frontend_url": "/learn/test-lehrgang-lp/analyse/circle-analyse-abschliessen",
|
||||
"translation_key": "5c17be62-2da6-413c-82a4-7754c00ef18a",
|
||||
"frontend_url": "/course/test-lehrgang/learn/analyse/circle-analyse-abschliessen",
|
||||
"minutes": 30,
|
||||
"contents": [
|
||||
{
|
||||
|
|
@ -443,7 +430,7 @@
|
|||
"description": "Beispiel Dokument",
|
||||
"url": null
|
||||
},
|
||||
"id": "21415232-862b-488c-9987-4f4ee369a854"
|
||||
"id": "c39488aa-2ce4-4bd7-9a39-f9ace70353bd"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -454,12 +441,12 @@
|
|||
{
|
||||
"type": "goal",
|
||||
"value": "... die heutige Versicherungssituation von Privat- oder Gesch\u00e4ftskunden einzusch\u00e4tzen.",
|
||||
"id": "d1f001fa-f7b8-41a3-90c7-632260ff7054"
|
||||
"id": "c6d1b496-14e7-4570-ba05-c6f408f6ecfb"
|
||||
},
|
||||
{
|
||||
"type": "goal",
|
||||
"value": "... deinem Kunden seine optimale L\u00f6sung aufzuzeigen",
|
||||
"id": "8f73bb0f-e898-4961-ab28-dd34caca2c0b"
|
||||
"id": "92e3ec0d-e90e-4d8e-a81a-43f0e56c504f"
|
||||
}
|
||||
],
|
||||
"job_situation_description": "Du triffst in diesem Circle auf die folgenden berufstypischen Handlungsfelder:",
|
||||
|
|
@ -467,25 +454,12 @@
|
|||
{
|
||||
"type": "job_situation",
|
||||
"value": "Autoversicherung",
|
||||
"id": "df46930b-2911-4161-a677-75b4b156dff3"
|
||||
"id": "1a047ce6-8922-4bc7-b185-5b7d6d89c0f9"
|
||||
},
|
||||
{
|
||||
"type": "job_situation",
|
||||
"value": "Autokauf",
|
||||
"id": "17a6d252-e942-44cc-920f-015e38e727be"
|
||||
}
|
||||
],
|
||||
"experts": [
|
||||
{
|
||||
"type": "person",
|
||||
"value": {
|
||||
"first_name": "Patrizia",
|
||||
"last_name": "Huggel",
|
||||
"email": "patrizia.huggel@eiger-versicherungen.ch",
|
||||
"photo": null,
|
||||
"biography": ""
|
||||
},
|
||||
"id": "b0633305-5e74-43eb-93b8-ebbcfb1b17d1"
|
||||
"id": "c1b5a26b-570a-4147-9338-753d87e67cf3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -493,6 +467,7 @@
|
|||
"course": {
|
||||
"id": -1,
|
||||
"title": "Test Lehrgang",
|
||||
"category_name": "Handlungsfeld"
|
||||
"category_name": "Handlungsfeld",
|
||||
"slug": "test-lehrgang"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import requests
|
|||
|
||||
def main():
|
||||
client = requests.session()
|
||||
client.get("http://localhost:8001/")
|
||||
client.get("http://localhost:8000/")
|
||||
|
||||
client.post(
|
||||
"http://localhost:8001/api/core/login/",
|
||||
"http://localhost:8000/api/core/login/",
|
||||
json={
|
||||
"username": "admin",
|
||||
"password": "test",
|
||||
|
|
@ -16,7 +16,7 @@ def main():
|
|||
)
|
||||
|
||||
response = client.get(
|
||||
"http://localhost:8001/api/course/page/test-lehrgang-lp/",
|
||||
"http://localhost:8000/api/course/page/test-lehrgang-lp/",
|
||||
)
|
||||
print(response.status_code)
|
||||
print(response.json())
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ function directUpload(fileData: FileData, file: File) {
|
|||
Accept: "application/json",
|
||||
} as HeadersInit;
|
||||
|
||||
let options = {
|
||||
const options = {
|
||||
method: "POST",
|
||||
headers: headers,
|
||||
body: formData,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { itGetCached } from "@/fetchHelpers";
|
|||
import type { CourseSessionUser, ExpertSessionUser } from "@/types";
|
||||
import log from "loglevel";
|
||||
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export type CockpitStoreState = {
|
||||
|
|
@ -19,25 +20,21 @@ export const useCockpitStore = defineStore({
|
|||
selectedCircles: [],
|
||||
} as CockpitStoreState;
|
||||
},
|
||||
getters: {
|
||||
circles: (state) => state.cockpitSessionUser?.circles,
|
||||
selectedCirclesTitles: (state) =>
|
||||
state.cockpitSessionUser?.circles
|
||||
.filter((circle) => state.selectedCircles.indexOf(circle.translation_key) > -1)
|
||||
.map((circle) => circle.title),
|
||||
},
|
||||
actions: {
|
||||
async loadCourseSessionUsers(courseSlug: string, reload = false) {
|
||||
log.debug("loadCockpitData called");
|
||||
const { users, cockpit_user: cockpitUser } = await itGetCached(
|
||||
`/api/course/sessions/${courseSlug}/users/`,
|
||||
{
|
||||
reload: reload,
|
||||
}
|
||||
);
|
||||
const users = (await itGetCached(`/api/course/sessions/${courseSlug}/users/`, {
|
||||
reload: reload,
|
||||
})) as CourseSessionUser[];
|
||||
|
||||
this.courseSessionUsers = users;
|
||||
this.cockpitSessionUser = cockpitUser;
|
||||
this.courseSessionUsers = users.filter((user) => user.role === "MEMBER");
|
||||
|
||||
const userStore = useUserStore();
|
||||
const currentUser = users.find((user) => user.user_id === userStore.id);
|
||||
|
||||
if (currentUser && currentUser.role === "EXPERT") {
|
||||
this.cockpitSessionUser = currentUser as ExpertSessionUser;
|
||||
}
|
||||
|
||||
if (this.cockpitSessionUser && this.cockpitSessionUser.circles?.length > 0) {
|
||||
this.selectedCircles = [this.cockpitSessionUser.circles[0].translation_key];
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
import { itGetCached, itPost } from "@/fetchHelpers";
|
||||
import { deleteCircleDocument } from "@/services/files";
|
||||
import type { CircleDocument, CircleExpert, CourseSession } from "@/types";
|
||||
import type {
|
||||
CircleDocument,
|
||||
CourseSession,
|
||||
CourseSessionUser,
|
||||
ExpertSessionUser,
|
||||
} from "@/types";
|
||||
import _ from "lodash";
|
||||
import log from "loglevel";
|
||||
|
||||
import { defineStore } from "pinia";
|
||||
import { computed, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
|
@ -29,6 +33,27 @@ function loadCourseSessionsData(reload = false) {
|
|||
reload: reload,
|
||||
});
|
||||
|
||||
// TODO: refactor after implementing of Klassenkonzept
|
||||
const uniqueCourses = _.uniqBy(courseSessions.value, "course.id");
|
||||
await Promise.all(
|
||||
uniqueCourses.map(async (courseSession) => {
|
||||
const users = (await itGetCached(
|
||||
`/api/course/sessions/${courseSession.course.slug}/users/`,
|
||||
{
|
||||
reload: reload,
|
||||
}
|
||||
)) as CourseSessionUser[];
|
||||
courseSessions.value = courseSessions.value
|
||||
.filter((cs) => {
|
||||
return cs.course.slug === courseSession.course.slug;
|
||||
})
|
||||
.map((cs) => {
|
||||
cs.users = users;
|
||||
return cs;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const userStore = useUserStore();
|
||||
if (!courseSessions.value && userStore.loggedIn) {
|
||||
throw `No courseSessionData found for user`;
|
||||
|
|
@ -41,16 +66,6 @@ function loadCourseSessionsData(reload = false) {
|
|||
return { courseSessions };
|
||||
}
|
||||
|
||||
function userExpertCircles(
|
||||
userId: number,
|
||||
courseSessionForRoute: CourseSession | undefined
|
||||
): CircleExpert[] {
|
||||
if (!courseSessionForRoute) {
|
||||
return [];
|
||||
}
|
||||
return courseSessionForRoute.experts.filter((expert) => expert.user_id === userId);
|
||||
}
|
||||
|
||||
export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||
// using setup function seems cleaner, see https://pinia.vuejs.org/core-concepts/#setup-stores
|
||||
|
||||
|
|
@ -59,10 +74,13 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
// store should do own setup, we don't want to have each component initialize it
|
||||
// that's why we call the load function in here
|
||||
const { courseSessions } = loadCourseSessionsData();
|
||||
|
||||
// these will become getters
|
||||
const coursesFromCourseSessions = computed(() =>
|
||||
// TODO: refactor after implementing of Klassenkonzept
|
||||
_.uniqBy(courseSessions.value, "course.id")
|
||||
);
|
||||
|
||||
const courseSessionForRoute = computed(() => {
|
||||
const route = useRoute();
|
||||
const routePath = decodeURI(route.path);
|
||||
|
|
@ -71,28 +89,40 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
return routePath.startsWith(cs.course_url);
|
||||
});
|
||||
});
|
||||
|
||||
const hasCockpit = computed(() => {
|
||||
if (courseSessionForRoute.value) {
|
||||
const userStore = useUserStore();
|
||||
return (
|
||||
courseSessionForRoute.value.experts.filter(
|
||||
(expert) => expert.user_id === userStore.id
|
||||
).length > 0
|
||||
userStore.course_session_experts.includes(courseSessionForRoute.value.id) ||
|
||||
userStore.is_superuser
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const circleExperts = computed(() => {
|
||||
const circleStore = useCircleStore();
|
||||
const circleTranslationKey = circleStore.circle?.translation_key;
|
||||
|
||||
if (courseSessionForRoute.value && circleTranslationKey) {
|
||||
return courseSessionForRoute.value.users.filter((u) => {
|
||||
if (u.role === "EXPERT") {
|
||||
return (u as ExpertSessionUser).circles
|
||||
.map((c) => c.translation_key)
|
||||
.includes(circleTranslationKey);
|
||||
}
|
||||
return false;
|
||||
}) as ExpertSessionUser[];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const canUploadCircleDocuments = computed(() => {
|
||||
const userStore = useUserStore();
|
||||
const circleStore = useCircleStore();
|
||||
const expertCircles = userExpertCircles(userStore.id, courseSessionForRoute.value);
|
||||
|
||||
return (
|
||||
expertCircles.filter(
|
||||
(c) => c.circle_translation_key === circleStore.circle?.translation_key
|
||||
).length > 0
|
||||
circleExperts.value.filter((expert) => expert.user_id === userStore.id).length > 0
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -106,7 +136,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
return ls;
|
||||
}
|
||||
|
||||
for (let document of courseSessionForRoute.value.documents) {
|
||||
for (const document of courseSessionForRoute.value.documents) {
|
||||
if (document.learning_sequence === ls.id) {
|
||||
ls.documents.push(document);
|
||||
}
|
||||
|
|
@ -146,6 +176,7 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
|||
hasCockpit,
|
||||
canUploadCircleDocuments,
|
||||
circleDocuments,
|
||||
circleExperts,
|
||||
addDocument,
|
||||
startUpload,
|
||||
removeDocument,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ export type UserState = {
|
|||
email: string;
|
||||
username: string;
|
||||
avatar_url: string;
|
||||
is_superuser: boolean;
|
||||
course_session_experts: number[];
|
||||
loggedIn: boolean;
|
||||
};
|
||||
|
||||
|
|
@ -24,6 +26,8 @@ const initialUserState: UserState = {
|
|||
last_name: "",
|
||||
username: "",
|
||||
avatar_url: "",
|
||||
is_superuser: false,
|
||||
course_session_experts: [],
|
||||
loggedIn: false,
|
||||
};
|
||||
|
||||
|
|
@ -76,9 +80,6 @@ export const useUserStore = defineStore({
|
|||
this.$state = data;
|
||||
this.loggedIn = true;
|
||||
appStore.userLoaded = true;
|
||||
// todo: why?
|
||||
// const courseSessionsStore = useCourseSessionsStore();
|
||||
// await courseSessionsStore.loadCourseSessionsData();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -341,8 +341,8 @@ export interface CourseSession {
|
|||
course_url: string;
|
||||
media_library_url: string;
|
||||
additional_json_data: unknown;
|
||||
experts: CircleExpert[];
|
||||
documents: CircleDocument[];
|
||||
users: CourseSessionUser[];
|
||||
}
|
||||
|
||||
export type Role = "MEMBER" | "EXPERT" | "TUTOR";
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -32,7 +32,6 @@ from vbv_lernwelt.course.views import (
|
|||
request_course_completion,
|
||||
request_course_completion_for_user,
|
||||
)
|
||||
|
||||
from vbv_lernwelt.feedback.views import get_name
|
||||
from wagtail import urls as wagtail_urls
|
||||
from wagtail.admin import urls as wagtailadmin_urls
|
||||
|
|
@ -78,7 +77,7 @@ urlpatterns = [
|
|||
name="mark_course_completion"),
|
||||
path(r"api/course/completion/<course_id>/", request_course_completion,
|
||||
name="request_course_completion"),
|
||||
path(r"api/course/completion/<course_id>/<user_id>/",
|
||||
path(r"api/course/completion/<course_id>/<int:user_id>/",
|
||||
request_course_completion_for_user,
|
||||
name="request_course_completion_for_user"),
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
course_session_experts = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
|
|
@ -13,4 +16,13 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
"email",
|
||||
"username",
|
||||
"avatar_url",
|
||||
"is_superuser",
|
||||
"course_session_experts",
|
||||
]
|
||||
|
||||
def get_course_session_experts(self, obj):
|
||||
qs = CourseSessionUser.objects.filter(
|
||||
role=CourseSessionUser.Role.EXPERT, user=obj
|
||||
)
|
||||
|
||||
return [csu.course_session.id for csu in qs]
|
||||
|
|
|
|||
|
|
@ -132,16 +132,6 @@ def create_test_learning_path(user=None, skip_locales=True):
|
|||
),
|
||||
("goal", "... deinem Kunden seine optimale Lösung aufzuzeigen"),
|
||||
],
|
||||
experts=[
|
||||
(
|
||||
"person",
|
||||
{
|
||||
"last_name": "Huggel",
|
||||
"first_name": "Patrizia",
|
||||
"email": "patrizia.huggel@eiger-versicherungen.ch",
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
LearningSequenceFactory(title="Starten", parent=circle, icon="it-icon-ls-start")
|
||||
|
|
|
|||
|
|
@ -236,6 +236,9 @@ class CourseSessionUser(models.Model):
|
|||
"email": self.user.email,
|
||||
"avatar_url": self.user.avatar_url,
|
||||
"role": self.role,
|
||||
"circles": self.expert.all().values(
|
||||
"id", "title", "slug", "translation_key"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,29 @@ from vbv_lernwelt.learnpath.models import LearningSequence
|
|||
|
||||
|
||||
def has_course_access_by_page_request(request, obj):
|
||||
return has_course_access(request.user, obj.specific.get_course())
|
||||
return has_course_access(request.user, obj.specific.get_course().id)
|
||||
|
||||
|
||||
def has_course_access(user, course):
|
||||
def has_course_access(user, course_id):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
if CourseSessionUser.objects.filter(
|
||||
course_session__course_id=course.id, user=user
|
||||
course_session__course_id=course_id, user=user
|
||||
).exists():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_course_expert(user, course_id: int):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
if CourseSessionUser.objects.filter(
|
||||
course_session__course_id=course_id,
|
||||
user=user,
|
||||
role=CourseSessionUser.Role.EXPERT,
|
||||
).exists():
|
||||
return True
|
||||
|
||||
|
|
@ -27,25 +41,23 @@ def course_sessions_for_user_qs(user):
|
|||
return course_sessions
|
||||
|
||||
|
||||
def is_circle_expert(user, learning_sequence, course) -> bool:
|
||||
def is_circle_expert(user, course_session_id: int, learning_sequence_id: int) -> bool:
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
try:
|
||||
learning_sequence = LearningSequence.objects.get(id=learning_sequence)
|
||||
learning_sequence = LearningSequence.objects.get(id=learning_sequence_id)
|
||||
except LearningSequence.DoesNotExist:
|
||||
return False
|
||||
|
||||
circle_id = learning_sequence.get_parent().circle.id
|
||||
|
||||
try:
|
||||
CourseSessionUser.objects.get(
|
||||
course_session__id=course,
|
||||
user_id=user.id,
|
||||
role=CourseSessionUser.Role.EXPERT,
|
||||
expert__id=circle_id,
|
||||
)
|
||||
except CourseSessionUser.DoesNotExist:
|
||||
return False
|
||||
if CourseSessionUser.objects.filter(
|
||||
course_session_id=course_session_id,
|
||||
user=user,
|
||||
role=CourseSessionUser.Role.EXPERT,
|
||||
expert__id=circle_id,
|
||||
).exists():
|
||||
return True
|
||||
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -6,9 +6,7 @@ from vbv_lernwelt.course.models import (
|
|||
CourseCategory,
|
||||
CourseCompletion,
|
||||
CourseSession,
|
||||
CourseSessionUser,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import Circle
|
||||
|
||||
|
||||
class CourseSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -50,7 +48,6 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
learning_path_url = serializers.SerializerMethodField()
|
||||
competence_url = serializers.SerializerMethodField()
|
||||
media_library_url = serializers.SerializerMethodField()
|
||||
experts = serializers.SerializerMethodField()
|
||||
documents = serializers.SerializerMethodField()
|
||||
|
||||
def get_course(self, obj):
|
||||
|
|
@ -68,26 +65,6 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
def get_competence_url(self, obj):
|
||||
return obj.course.get_competence_url()
|
||||
|
||||
def get_experts(self, obj):
|
||||
expert_relations = CourseSessionUser.objects.filter(
|
||||
expert__in=Circle.objects.descendant_of(obj.course.coursepage)
|
||||
).distinct()
|
||||
expert_result = []
|
||||
for er in expert_relations:
|
||||
for circle in er.expert.all():
|
||||
expert_result.append(
|
||||
{
|
||||
"user_id": er.user.id,
|
||||
"user_email": er.user.email,
|
||||
"user_first_name": er.user.first_name,
|
||||
"user_last_name": er.user.last_name,
|
||||
"circle_id": circle.id,
|
||||
"circle_slug": circle.slug,
|
||||
"circle_translation_key": circle.translation_key,
|
||||
}
|
||||
)
|
||||
return expert_result
|
||||
|
||||
def get_documents(self, obj):
|
||||
documents = CircleDocument.objects.filter(
|
||||
course_session=obj, file__upload_finished_at__isnull=False
|
||||
|
|
@ -109,7 +86,6 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
|||
"competence_url",
|
||||
"media_library_url",
|
||||
"course_url",
|
||||
"experts",
|
||||
"documents",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ from vbv_lernwelt.course.models import (
|
|||
)
|
||||
from vbv_lernwelt.course.permissions import (
|
||||
course_sessions_for_user_qs,
|
||||
has_course_access,
|
||||
has_course_access_by_page_request,
|
||||
is_circle_expert,
|
||||
is_course_expert,
|
||||
)
|
||||
from vbv_lernwelt.course.serializers import (
|
||||
CourseCompletionSerializer,
|
||||
|
|
@ -67,13 +69,16 @@ def _request_course_completion(course_id, user_id):
|
|||
|
||||
@api_view(["GET"])
|
||||
def request_course_completion(request, course_id):
|
||||
return _request_course_completion(course_id, request.user.id)
|
||||
if has_course_access(request.user, course_id):
|
||||
return _request_course_completion(course_id, request.user.id)
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
def request_course_completion_for_user(request, course_id, user_id):
|
||||
# TODO: check permissions to access this users data
|
||||
return _request_course_completion(course_id, user_id)
|
||||
if request.user.id == user_id or is_course_expert(request.user, course_id):
|
||||
return _request_course_completion(course_id, user_id)
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
@api_view(["POST"])
|
||||
|
|
@ -139,24 +144,9 @@ def get_course_session_users(request, course_slug):
|
|||
course__slug=course_slug
|
||||
)
|
||||
qs = CourseSessionUser.objects.filter(course_session__in=course_sessions)
|
||||
cockpit_user_csu = qs.filter(user_id=request.user.id)
|
||||
|
||||
if len(cockpit_user_csu) == 0:
|
||||
return Response({"error": "User not found"}, status=404)
|
||||
|
||||
user_data = [csu.to_dict() for csu in qs.exclude(user_id=request.user.id)]
|
||||
|
||||
data = {
|
||||
"cockpit_user": cockpit_user_csu[0].to_dict()
|
||||
| {
|
||||
"circles": cockpit_user_csu[0]
|
||||
.expert.all()
|
||||
.values("id", "title", "slug", "translation_key")
|
||||
},
|
||||
"users": user_data,
|
||||
}
|
||||
|
||||
return Response(status=200, data=data)
|
||||
user_data = [csu.to_dict() for csu in qs]
|
||||
return Response(status=200, data=user_data)
|
||||
except PermissionDenied as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
|
|
@ -171,8 +161,8 @@ def document_upload_start(request):
|
|||
|
||||
if not is_circle_expert(
|
||||
request.user,
|
||||
serializer.validated_data["learning_sequence"],
|
||||
serializer.validated_data["course_session"],
|
||||
serializer.validated_data["learning_sequence"],
|
||||
):
|
||||
raise PermissionDenied()
|
||||
|
||||
|
|
@ -227,7 +217,7 @@ def document_direct_upload(request, file_id):
|
|||
def document_delete(request, document_id):
|
||||
document = get_object_or_404(CircleDocument, id=document_id)
|
||||
if not is_circle_expert(
|
||||
request.user, document.learning_sequence_id, document.course_session_id
|
||||
request.user, document.course_session.id, document.learning_sequence.id
|
||||
):
|
||||
raise PermissionDenied()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# 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",
|
||||
),
|
||||
]
|
||||
|
|
@ -4,7 +4,6 @@ from wagtail import blocks
|
|||
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
|
||||
from wagtail.blocks import StreamBlock
|
||||
from wagtail.fields import StreamField
|
||||
from wagtail.images.blocks import ImageChooserBlock
|
||||
from wagtail.models import Page
|
||||
|
||||
from vbv_lernwelt.core.model_utils import find_available_slug
|
||||
|
|
@ -73,17 +72,6 @@ class Topic(CourseBasePage):
|
|||
return f"{self.title}"
|
||||
|
||||
|
||||
class PersonBlock(blocks.StructBlock):
|
||||
first_name = blocks.CharBlock()
|
||||
last_name = blocks.CharBlock()
|
||||
email = blocks.EmailBlock()
|
||||
photo = ImageChooserBlock(required=False)
|
||||
biography = blocks.RichTextBlock(required=False)
|
||||
|
||||
class Meta:
|
||||
icon = "user"
|
||||
|
||||
|
||||
class Circle(CourseBasePage):
|
||||
parent_page_types = ["learnpath.LearningPath"]
|
||||
subpage_types = [
|
||||
|
|
@ -99,7 +87,6 @@ class Circle(CourseBasePage):
|
|||
"goals",
|
||||
"job_situation_description",
|
||||
"job_situations",
|
||||
"experts",
|
||||
]
|
||||
|
||||
description = models.TextField(default="", blank=True)
|
||||
|
|
@ -119,18 +106,11 @@ class Circle(CourseBasePage):
|
|||
],
|
||||
use_json_field=True,
|
||||
)
|
||||
experts = StreamField(
|
||||
[
|
||||
("person", PersonBlock()),
|
||||
],
|
||||
use_json_field=True,
|
||||
)
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
FieldPanel("description"),
|
||||
FieldPanel("goals"),
|
||||
FieldPanel("job_situations"),
|
||||
FieldPanel("experts"),
|
||||
]
|
||||
|
||||
def get_frontend_url(self):
|
||||
|
|
|
|||
|
|
@ -135,16 +135,6 @@ pretium quis, sem. Nulla consequat massa quis enim. Donec.
|
|||
goals = [
|
||||
("goal", f"... hier ein Beispieltext für ein Ziel {x + 1}") for x in range(3)
|
||||
]
|
||||
experts = [
|
||||
(
|
||||
"person",
|
||||
{
|
||||
"last_name": "Mustermann",
|
||||
"first_name": "Patrizia",
|
||||
"email": "patrizia.mustermann@example.com",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
model = Circle
|
||||
|
|
|
|||
Loading…
Reference in New Issue