Document handling via REST

This commit is contained in:
Daniel Egger 2023-10-10 13:11:13 +02:00
parent a1f2c8cd12
commit 49a3fa99e1
20 changed files with 137 additions and 181 deletions

View File

@ -20,7 +20,7 @@ const documents = {
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument, "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
"\n query courseQuery($courseId: ID!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument, "\n query courseQuery($courseId: ID!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument, "\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
"\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n documents {\n id\n name\n file_name\n url\n learning_sequence {\n id\n title\n circle {\n id\n slug\n title\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument, "\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument,
"\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar!\n $submitted: Boolean\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n submitted: $submitted\n ) {\n feedback_response {\n id\n data\n submitted\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument, "\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar!\n $submitted: Boolean\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n submitted: $submitted\n ) {\n feedback_response {\n id\n data\n submitted\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
}; };
@ -69,7 +69,7 @@ export function graphql(source: "\n query competenceCertificateQuery($courseSlu
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n documents {\n id\n name\n file_name\n url\n learning_sequence {\n id\n title\n circle {\n id\n slug\n title\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n documents {\n id\n name\n file_name\n url\n learning_sequence {\n id\n title\n circle {\n id\n slug\n title\n }\n }\n }\n }\n }\n"]; export function graphql(source: "\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */

File diff suppressed because one or more lines are too long

View File

@ -204,21 +204,6 @@ export const COURSE_SESSION_DETAIL_QUERY = graphql(`
} }
} }
} }
documents {
id
name
file_name
url
learning_sequence {
id
title
circle {
id
slug
title
}
}
}
} }
} }
`); `);

View File

@ -1,22 +0,0 @@
<script setup lang="ts">
import * as log from "loglevel";
import { onMounted } from "vue";
import { useCourseSessionDetailQuery } from "@/composables";
const props = defineProps<{
courseSlug: string;
}>();
onMounted(async () => {
log.debug("TestCourseSessionComposablePage mounted");
});
// const courseSession = useCurrentCourseSession();
const queryResult = useCourseSessionDetailQuery("-1");
</script>
<template>
<h1>Hello World</h1>
<pre>{{ queryResult.courseSessionDetail }}</pre>
</template>

View File

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCockpitStore } from "@/stores/cockpit";
import { useCompetenceStore } from "@/stores/competence"; import { useCompetenceStore } from "@/stores/competence";
import { useLearningPathStore } from "@/stores/learningPath"; import { useLearningPathStore } from "@/stores/learningPath";
import * as log from "loglevel"; import * as log from "loglevel";
@ -16,7 +15,6 @@ const props = defineProps<{
log.debug("CockpitUserProfilePage created", props.userId); log.debug("CockpitUserProfilePage created", props.userId);
const cockpitStore = useCockpitStore();
const competenceStore = useCompetenceStore(); const competenceStore = useCompetenceStore();
const learningPathStore = useLearningPathStore(); const learningPathStore = useLearningPathStore();

View File

@ -47,7 +47,7 @@ const submittables = computed(() => {
return []; return [];
} }
return learningPath.circles return learningPath.circles
.filter((circle) => props.selectedCircle == circle.id) .filter((circle) => props.selectedCircle.toString() == circle.id.toString())
.flatMap((circle) => { .flatMap((circle) => {
const learningContents = circle.flatLearningContents.filter( const learningContents = circle.flatLearningContents.filter(
(lc) => (lc) =>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables"; import { useCurrentCourseSession } from "@/composables";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue"; import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { useCockpitStore } from "@/stores/cockpit"; import { useCockpitStore } from "@/stores/cockpit";
import ItModal from "@/components/ui/ItModal.vue"; import ItModal from "@/components/ui/ItModal.vue";
@ -9,7 +9,11 @@ import { useTranslation } from "i18next-vue";
import type { CircleDocument, DocumentUploadData } from "@/types"; import type { CircleDocument, DocumentUploadData } from "@/types";
import dialog from "@/utils/confirm-dialog"; import dialog from "@/utils/confirm-dialog";
import log from "loglevel"; import log from "loglevel";
import { uploadCircleDocument } from "@/services/files"; import {
deleteCircleDocument,
fetchCourseSessionDocuments,
uploadCircleDocument,
} from "@/services/files";
import { useCourseSessionsStore } from "@/stores/courseSessions"; import { useCourseSessionsStore } from "@/stores/courseSessions";
import DocumentListItem from "@/components/circle/DocumentListItem.vue"; import DocumentListItem from "@/components/circle/DocumentListItem.vue";
import { useCircleStore } from "@/stores/circle"; import { useCircleStore } from "@/stores/circle";
@ -19,7 +23,6 @@ const courseSession = useCurrentCourseSession();
const circleStore = useCircleStore(); const circleStore = useCircleStore();
const courseSessionsStore = useCourseSessionsStore(); const courseSessionsStore = useCourseSessionsStore();
const courseSessionDetailResults = useCourseSessionDetailQuery();
const { t } = useTranslation(); const { t } = useTranslation();
@ -27,8 +30,25 @@ const showUploadModal = ref(false);
const showUploadErrorMessage = ref(false); const showUploadErrorMessage = ref(false);
const isUploading = ref(false); const isUploading = ref(false);
const circleDocumentsResultData = ref<CircleDocument[]>([]);
let courseSessionDocumentsUrl = "";
async function fetchDocuments() {
const result = await fetchCourseSessionDocuments(courseSession.value?.id);
if (result.length > 0) {
circleDocumentsResultData.value = result;
} else {
circleDocumentsResultData.value = [];
}
}
onMounted(async () => { onMounted(async () => {
log.debug("DocumentPage mounted"); log.debug("DocumentPage mounted");
if (courseSession.value?.id) {
courseSessionDocumentsUrl = `/api/core/document/list/${courseSession.value?.id}/`;
}
await fetchDocuments();
}); });
watch( watch(
@ -48,14 +68,12 @@ watch(
const dropdownLearningSequences = computed(() => const dropdownLearningSequences = computed(() =>
circleStore.circle?.learningSequences.map((sequence) => ({ circleStore.circle?.learningSequences.map((sequence) => ({
id: sequence.id, id: sequence.id,
name: `${sequence.title} ${sequence.id}`, name: `${sequence.title}`,
})) }))
); );
const circleDocuments = computed(() => { const circleDocuments = computed(() => {
const documents = return circleDocumentsResultData.value.filter(
courseSessionDetailResults.courseSessionDetail.value?.documents ?? [];
return documents.filter(
(d) => d.learning_sequence.circle.slug === cockpitStore.currentCircle?.slug (d) => d.learning_sequence.circle.slug === cockpitStore.currentCircle?.slug
); );
}); });
@ -67,7 +85,10 @@ const deleteDocument = async (doc: CircleDocument) => {
}; };
try { try {
await dialog.confirm(options); await dialog.confirm(options);
courseSessionsStore.removeDocument(doc.id); await deleteCircleDocument(doc.id, courseSessionDocumentsUrl);
circleDocumentsResultData.value = circleDocumentsResultData.value.filter(
(d) => d.id !== doc.id
);
} catch (e) { } catch (e) {
log.debug("rejected"); log.debug("rejected");
} }
@ -81,11 +102,13 @@ async function uploadDocument(data: DocumentUploadData) {
if (!courseSessionsStore.currentCourseSession) { if (!courseSessionsStore.currentCourseSession) {
throw new Error("No course session found"); throw new Error("No course session found");
} }
const newDocument = await uploadCircleDocument( await uploadCircleDocument(
data, data,
courseSessionsStore.currentCourseSession.id courseSessionsStore.currentCourseSession.id,
courseSessionDocumentsUrl
); );
courseSessionsStore.addDocument(newDocument); await fetchDocuments();
showUploadModal.value = false; showUploadModal.value = false;
isUploading.value = false; isUploading.value = false;
} catch (error) { } catch (error) {

View File

@ -21,18 +21,33 @@
<script setup lang="ts"> <script setup lang="ts">
import DocumentListItem from "@/components/circle/DocumentListItem.vue"; import DocumentListItem from "@/components/circle/DocumentListItem.vue";
import { useCourseSessionDetailQuery } from "@/composables"; import { useCurrentCourseSession } from "@/composables";
import { computed } from "vue"; import { computed, onMounted, ref } from "vue";
import { useCircleStore } from "@/stores/circle"; import { useCircleStore } from "@/stores/circle";
import type { CircleDocument } from "@/types";
import { fetchCourseSessionDocuments } from "@/services/files";
const courseSessionDetailResults = useCourseSessionDetailQuery(); const courseSession = useCurrentCourseSession();
const circleStore = useCircleStore(); const circleStore = useCircleStore();
const circleDocumentsResultData = ref<CircleDocument[]>([]);
async function fetchDocuments() {
const result = await fetchCourseSessionDocuments(courseSession.value?.id);
if (result.length > 0) {
circleDocumentsResultData.value = result;
} else {
circleDocumentsResultData.value = [];
}
}
const circleDocuments = computed(() => { const circleDocuments = computed(() => {
const documents = return circleDocumentsResultData.value.filter(
courseSessionDetailResults.courseSessionDetail.value?.documents ?? [];
return documents.filter(
(d) => d.learning_sequence.circle.slug === circleStore.circle?.slug (d) => d.learning_sequence.circle.slug === circleStore.circle?.slug
); );
}); });
onMounted(async () => {
await fetchDocuments();
});
</script> </script>

View File

@ -98,11 +98,6 @@ const router = createRouter({
}, },
], ],
}, },
{
path: "/course/:courseSlug/test-composable",
component: () => import("../pages/TestCourseSessionComposablePage.vue"),
props: true,
},
{ {
path: "/course/:courseSlug/learn", path: "/course/:courseSlug/learn",
component: () => component: () =>

View File

@ -1,6 +1,6 @@
import { itDelete, itFetch, itPost } from "@/fetchHelpers"; import { bustItGetCache, itDelete, itFetch, itGetCached, itPost } from "@/fetchHelpers";
import { getCookieValue } from "@/router/guards"; import { getCookieValue } from "@/router/guards";
import type { CircleDocument, DocumentUploadData } from "@/types"; import type { DocumentUploadData } from "@/types";
type FileData = { type FileData = {
fields: Record<string, string>; fields: Record<string, string>;
@ -73,8 +73,9 @@ function handleUpload(url: string, options: RequestInit) {
export async function uploadCircleDocument( export async function uploadCircleDocument(
data: DocumentUploadData, data: DocumentUploadData,
courseSessionId: number courseSessionId: number,
): Promise<CircleDocument> { bustCacheUrlKey = ""
) {
if (data.file === null) { if (data.file === null) {
throw new Error("No file selected"); throw new Error("No file selected");
} }
@ -82,22 +83,25 @@ export async function uploadCircleDocument(
const startData = await startFileUpload(data, courseSessionId); const startData = await startFileUpload(data, courseSessionId);
await uploadFile(startData, data.file); await uploadFile(startData, data.file);
const response = await itPost(`/api/core/file/finish/`, { const response = itPost(`/api/core/file/finish/`, {
file_id: startData.file_id, file_id: startData.file_id,
}); });
const newDocument: CircleDocument = { if (bustCacheUrlKey) {
id: startData.id, bustItGetCache(bustCacheUrlKey);
name: data.name, }
file_name: data.file.name,
url: response.url,
course_session: courseSessionId,
learning_sequence: data.learningSequence.id,
};
return Promise.resolve(newDocument); return response;
} }
export async function deleteCircleDocument(documentId: string) { export async function deleteCircleDocument(documentId: string, bustCacheUrlKey = "") {
return itDelete(`/api/core/document/${documentId}/`); const result = itDelete(`/api/core/document/${documentId}/`);
if (bustCacheUrlKey) {
bustItGetCache(bustCacheUrlKey);
}
return result;
}
export async function fetchCourseSessionDocuments(courseSessionId: number) {
return itGetCached(`/api/core/document/list/${courseSessionId}/`);
} }

View File

@ -8,7 +8,6 @@ import type {
CompetenceProfilePage, CompetenceProfilePage,
PerformanceCriteria, PerformanceCriteria,
} from "@/types"; } from "@/types";
import i18next from "i18next";
import _ from "lodash"; import _ from "lodash";
import cloneDeep from "lodash/cloneDeep"; import cloneDeep from "lodash/cloneDeep";
import groupBy from "lodash/groupBy"; import groupBy from "lodash/groupBy";
@ -17,9 +16,6 @@ import { defineStore } from "pinia";
export type CompetenceStoreState = { export type CompetenceStoreState = {
competenceProfilePages: Map<string, CompetenceProfilePage>; competenceProfilePages: Map<string, CompetenceProfilePage>;
selectedCircle: { id: string; name: string };
availableCircles: { id: string; name: string }[];
circles: CircleLight[]; circles: CircleLight[];
}; };
@ -28,8 +24,6 @@ export const useCompetenceStore = defineStore({
state: () => { state: () => {
return { return {
competenceProfilePages: new Map<string, CompetenceProfilePage>(), competenceProfilePages: new Map<string, CompetenceProfilePage>(),
selectedCircle: { id: "all", name: `Circle: ${i18next.t("Alle")}` },
availableCircles: [],
circles: [], circles: [],
} as CompetenceStoreState; } as CompetenceStoreState;
}, },
@ -52,13 +46,7 @@ export const useCompetenceStore = defineStore({
}; };
}, },
criteriaByCompetence(competence: CompetencePage) { criteriaByCompetence(competence: CompetencePage) {
return competence.children.filter((criteria) => { return competence.children;
if (this.selectedCircle.id != "all") {
return criteria.circle.translation_key === this.selectedCircle.id;
}
return competence.children;
});
}, },
competenceProfilePage(userId: string | undefined = undefined) { competenceProfilePage(userId: string | undefined = undefined) {
if (!userId) { if (!userId) {
@ -88,14 +76,10 @@ export const useCompetenceStore = defineStore({
["asc"] ["asc"]
); );
if (this.selectedCircle.id !== "all") {
criteria = criteria.filter(
(c) => c.circle.translation_key === this.selectedCircle.id
);
}
if (circleId) { if (circleId) {
criteria = criteria.filter((c) => circleId === c.circle.id); criteria = criteria.filter(
(c) => circleId.toString() === c.circle.id.toString()
);
} }
return criteria; return criteria;
@ -116,12 +100,7 @@ export const useCompetenceStore = defineStore({
if (competenceProfilePage?.children.length) { if (competenceProfilePage?.children.length) {
return _.orderBy( return _.orderBy(
competenceProfilePage.children.filter((competence) => { competenceProfilePage.children.filter((competence) => {
let criteria = competence.children; const criteria = competence.children;
if (this.selectedCircle.id != "all") {
criteria = criteria.filter((criteria) => {
return criteria.circle.translation_key === this.selectedCircle.id;
});
}
return criteria.length > 0; return criteria.length > 0;
}), }),
["competence_id"], ["competence_id"],
@ -159,10 +138,6 @@ export const useCompetenceStore = defineStore({
this.competenceProfilePages.set(userId, cloneDeep(competenceProfilePage)); this.competenceProfilePages.set(userId, cloneDeep(competenceProfilePage));
this.circles = competenceProfilePage.circles; this.circles = competenceProfilePage.circles;
const circles = competenceProfilePage.circles.map((c: CircleLight) => {
return { id: c.translation_key, name: `Circle: ${c.title}` };
});
this.availableCircles = [{ id: "all", name: "Circle: Alle" }, ...circles];
await this.parseCompletionData(userId); await this.parseCompletionData(userId);

View File

@ -146,35 +146,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
return Boolean(isCourseExpert && (inLearningPath() || inCompetenceProfile())); return Boolean(isCourseExpert && (inLearningPath() || inCompetenceProfile()));
}); });
// const canUploadCircleDocuments = computed(() => {
// const userStore = useUserStore();
// return (
// circleExperts.value.filter((expert) => expert.user_id === userStore.id).length > 0
// );
// });
// const circleDocuments = computed(() => {
// const circleStore = useCircleStore();
//
// return (
// circleStore.circle?.learningSequences
// .map((ls) => ({ id: ls.id, title: ls.title, documents: [] }))
// .map((ls: { id: number; title: string; documents: CircleDocument[] }) => {
// if (currentCourseSession.value === undefined) {
// return ls;
// }
//
// for (const document of currentCourseSession.value.documents) {
// if (document.learning_sequence === ls.id) {
// ls.documents.push(document);
// }
// }
// return ls;
// })
// .filter((ls) => ls.documents.length > 0) || []
// );
// });
function hasCockpit(courseSession: CourseSession) { function hasCockpit(courseSession: CourseSession) {
const userStore = useUserStore(); const userStore = useUserStore();
return ( return (
@ -183,10 +154,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
); );
} }
// function addDocument(document: CircleDocument) {
// currentCourseSession.value?.documents.push(document);
// }
function allDueDates() { function allDueDates() {
const allDueDatesReturn: DueDate[] = []; const allDueDatesReturn: DueDate[] = [];
@ -211,26 +178,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
}); });
} }
// async function startUpload() {
// log.debug("loadCourseSessionsData called");
// allCourseSessions.value = await itPost(`/api/core/file/start`, {
// file_type: "image/png",
// file_name: "test.png",
// });
// }
//
// async function removeDocument(documentId: string) {
// await deleteCircleDocument(documentId);
//
// if (currentCourseSession.value === undefined) {
// return;
// }
//
// currentCourseSession.value.documents = currentCourseSession.value?.documents.filter(
// (d) => d.id !== documentId
// );
// }
return { return {
uniqueCourseSessionsByCourse, uniqueCourseSessionsByCourse,
allCurrentCourseSessions, allCurrentCourseSessions,
@ -240,9 +187,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
hasCockpit, hasCockpit,
hasCourseSessionPreview, hasCourseSessionPreview,
currentCourseSessionHasCockpit, currentCourseSessionHasCockpit,
// addDocument,
// startUpload,
// removeDocument,
allDueDates, allDueDates,
// use `useCurrentCourseSession` whenever possible // use `useCurrentCourseSession` whenever possible

View File

@ -569,7 +569,6 @@ export interface CourseSessionDetail {
assignments: CourseSessionAssignment[]; assignments: CourseSessionAssignment[];
attendance_courses: CourseSessionAttendanceCourse[]; attendance_courses: CourseSessionAttendanceCourse[];
edoniq_tests: CourseSessionEdoniqTest[]; edoniq_tests: CourseSessionEdoniqTest[];
documents: CircleDocument[];
users: CourseSessionUser[]; users: CourseSessionUser[];
} }

View File

@ -31,12 +31,12 @@ from vbv_lernwelt.course.views import (
document_direct_upload, document_direct_upload,
document_upload_finish, document_upload_finish,
document_upload_start, document_upload_start,
get_course_session_users,
get_course_sessions, get_course_sessions,
mark_course_completion_view, mark_course_completion_view,
request_course_completion, request_course_completion,
request_course_completion_for_user, request_course_completion_for_user,
) )
from vbv_lernwelt.course_session.views import get_course_session_documents
from vbv_lernwelt.edoniq_test.views import ( from vbv_lernwelt.edoniq_test.views import (
export_students, export_students,
export_students_and_trainers, export_students_and_trainers,
@ -90,6 +90,10 @@ urlpatterns = [
path('server/documents/', include(wagtaildocs_urls)), path('server/documents/', include(wagtaildocs_urls)),
path('server/pages/', include(wagtail_urls)), path('server/pages/', include(wagtail_urls)),
# core
re_path(r"server/core/icons/$", generate_web_component_icons,
name="generate_web_component_icons"),
# user management # user management
path("sso/", include("vbv_lernwelt.sso.urls")), path("sso/", include("vbv_lernwelt.sso.urls")),
re_path(r'api/core/me/$', me_user_view, name='me_user_view'), re_path(r'api/core/me/$', me_user_view, name='me_user_view'),
@ -104,10 +108,6 @@ urlpatterns = [
re_path(r"api/notify/email_notification_settings/$", email_notification_settings, re_path(r"api/notify/email_notification_settings/$", email_notification_settings,
name='email_notification_settings'), name='email_notification_settings'),
# core
re_path(r"server/core/icons/$", generate_web_component_icons,
name="generate_web_component_icons"),
# course # course
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/<signed_int:course_session_id>/users/", # path(r"api/course/sessions/<signed_int:course_session_id>/users/",
@ -139,6 +139,9 @@ urlpatterns = [
name='file_upload_finish'), name='file_upload_finish'),
path(r"api/core/document/local/<str:file_id>/", document_direct_upload, path(r"api/core/document/local/<str:file_id>/", document_direct_upload,
name='file_upload_local'), name='file_upload_local'),
path(r'api/core/document/list/<str:course_session_id>/',
get_course_session_documents,
name='get_course_session_documents'),
# feedback # feedback
path(r'api/core/feedback/<str:course_session_id>/summary/', path(r'api/core/feedback/<str:course_session_id>/summary/',

View File

@ -8,22 +8,22 @@ from graphql import GraphQLError
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
from vbv_lernwelt.course.models import ( from vbv_lernwelt.course.models import (
CircleDocument,
Course, Course,
CourseBasePage, CourseBasePage,
CoursePage, CoursePage,
CourseSession, CourseSession,
CourseSessionUser, CourseSessionUser,
CircleDocument,
) )
from vbv_lernwelt.course.permissions import has_course_access from vbv_lernwelt.course.permissions import has_course_access
from vbv_lernwelt.course_session.graphql.types import ( from vbv_lernwelt.course_session.graphql.types import (
CourseSessionAttendanceCourseObjectType,
CourseSessionAssignmentObjectType, CourseSessionAssignmentObjectType,
CourseSessionAttendanceCourseObjectType,
CourseSessionEdoniqTestObjectType, CourseSessionEdoniqTestObjectType,
) )
from vbv_lernwelt.course_session.models import ( from vbv_lernwelt.course_session.models import (
CourseSessionAttendanceCourse,
CourseSessionAssignment, CourseSessionAssignment,
CourseSessionAttendanceCourse,
CourseSessionEdoniqTest, CourseSessionEdoniqTest,
) )
from vbv_lernwelt.learnpath.graphql.types import LearningPathObjectType from vbv_lernwelt.learnpath.graphql.types import LearningPathObjectType

View File

@ -322,6 +322,9 @@ class CircleDocument(models.Model):
"learnpath.LearningSequence", on_delete=models.CASCADE "learnpath.LearningSequence", on_delete=models.CASCADE
) )
def get_circle(self):
return self.learning_sequence.get_circle()
@property @property
def url(self) -> str: def url(self) -> str:
return self.file.url return self.file.url

View File

@ -89,6 +89,8 @@ class CourseSessionSerializer(serializers.ModelSerializer):
class CircleDocumentSerializer(serializers.ModelSerializer): class CircleDocumentSerializer(serializers.ModelSerializer):
learning_sequence = serializers.SerializerMethodField()
class Meta: class Meta:
model = CircleDocument model = CircleDocument
fields = [ fields = [
@ -100,6 +102,20 @@ class CircleDocumentSerializer(serializers.ModelSerializer):
"learning_sequence", "learning_sequence",
] ]
def get_learning_sequence(self, obj):
ls = obj.learning_sequence
circle = ls.get_circle()
return {
"title": ls.title,
"id": ls.id,
"slug": ls.slug,
"circle": {
"title": circle.title,
"id": circle.id,
"slug": circle.slug,
},
}
class DocumentUploadStartInputSerializer(serializers.Serializer): class DocumentUploadStartInputSerializer(serializers.Serializer):
file_name = serializers.CharField() file_name = serializers.CharField()

View File

@ -3,8 +3,8 @@ from graphene_django import DjangoObjectType
from vbv_lernwelt.course.permissions import is_course_session_expert from vbv_lernwelt.course.permissions import is_course_session_expert
from vbv_lernwelt.course_session.models import ( from vbv_lernwelt.course_session.models import (
CourseSessionAttendanceCourse,
CourseSessionAssignment, CourseSessionAssignment,
CourseSessionAttendanceCourse,
CourseSessionEdoniqTest, CourseSessionEdoniqTest,
) )
from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus

View File

@ -1,3 +1,21 @@
from django.shortcuts import render from rest_framework.decorators import api_view
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
# Create your views here. from vbv_lernwelt.course.models import CircleDocument
from vbv_lernwelt.course.permissions import has_course_session_access
from vbv_lernwelt.course.serializers import CircleDocumentSerializer
@api_view(["GET"])
def get_course_session_documents(request, course_session_id):
if not has_course_session_access(request.user, course_session_id):
raise PermissionDenied()
circle_documents = CircleDocument.objects.filter(
course_session_id=course_session_id
)
return Response(
status=200, data=CircleDocumentSerializer(circle_documents, many=True).data
)

View File

@ -6,12 +6,12 @@ from vbv_lernwelt.learnpath.graphql.types import (
LearningContentAssignmentObjectType, LearningContentAssignmentObjectType,
LearningContentAttendanceCourseObjectType, LearningContentAttendanceCourseObjectType,
LearningContentDocumentListObjectType, LearningContentDocumentListObjectType,
LearningContentEdoniqTestObjectType,
LearningContentFeedbackObjectType, LearningContentFeedbackObjectType,
LearningContentLearningModuleObjectType, LearningContentLearningModuleObjectType,
LearningContentMediaLibraryObjectType, LearningContentMediaLibraryObjectType,
LearningContentPlaceholderObjectType, LearningContentPlaceholderObjectType,
LearningContentRichTextObjectType, LearningContentRichTextObjectType,
LearningContentEdoniqTestObjectType,
LearningContentVideoObjectType, LearningContentVideoObjectType,
LearningPathObjectType, LearningPathObjectType,
) )