Document handling via REST
This commit is contained in:
parent
a1f2c8cd12
commit
49a3fa99e1
|
|
@ -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
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) =>
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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: () =>
|
||||||
|
|
|
||||||
|
|
@ -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}/`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
|
||||||
if (this.selectedCircle.id != "all") {
|
|
||||||
return criteria.circle.translation_key === this.selectedCircle.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return competence.children;
|
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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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/',
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue