From 048cee654e2ba403f80a57b52fd3ae472d53de84 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 31 Dec 2024 13:15:25 +0530 Subject: [PATCH] fix: mark lesson progress when quiz and assignment are submitted --- frontend/src/components/Assignment.vue | 16 +++++ frontend/src/components/Quiz.vue | 14 +++++ lms/lms/api.py | 12 ++++ .../doctype/course_lesson/course_lesson.py | 62 +++++++++++++------ 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/Assignment.vue b/frontend/src/components/Assignment.vue index 7d0d1efa..0ac60405 100644 --- a/frontend/src/components/Assignment.vue +++ b/frontend/src/components/Assignment.vue @@ -133,6 +133,7 @@ import { Badge, Button, + call, createResource, createDocumentResource, FileUploader, @@ -247,6 +248,7 @@ const addNewSubmission = () => { }, }) } else { + markLessonProgress() router.go() } }, @@ -261,6 +263,20 @@ const saveSubmission = (file) => { submissionFile.value = file } +const markLessonProgress = () => { + if (router.currentRoute.value.name == 'Lesson') { + let courseName = router.currentRoute.value.params.courseName + let chapterNumber = router.currentRoute.value.params.chapterNumber + let lessonNumber = router.currentRoute.value.params.lessonNumber + + call('lms.lms.api.mark_lesson_progress', { + course: courseName, + chapter_number: chapterNumber, + lesson_number: lessonNumber, + }) + } +} + const getType = () => { const type = assignment.data?.type if (type == 'Image') { diff --git a/frontend/src/components/Quiz.vue b/frontend/src/components/Quiz.vue index b4b3c42f..7df188b7 100644 --- a/frontend/src/components/Quiz.vue +++ b/frontend/src/components/Quiz.vue @@ -271,6 +271,7 @@ import { Badge, Button, + call, createResource, ListView, TextEditor, @@ -280,6 +281,7 @@ import { ref, watch, reactive, inject, computed } from 'vue' import { createToast } from '@/utils/' import { CheckCircle, XCircle, MinusCircle } from 'lucide-vue-next' import { timeAgo } from '@/utils' +import { useRouter } from 'vue-router' import ProgressBar from '@/components/ProgressBar.vue' const user = inject('$user') @@ -291,6 +293,7 @@ let questions = reactive([]) const possibleAnswer = ref(null) const timer = ref(0) let timerInterval = null +const router = useRouter() const props = defineProps({ quizName: { @@ -560,6 +563,7 @@ const createSubmission = () => { {}, { onSuccess(data) { + markLessonProgress() if (quiz.data && quiz.data.max_attempts) attempts.reload() if (quiz.data.duration) clearInterval(timerInterval) }, @@ -583,6 +587,16 @@ const getInstructions = (question) => { else return __('Type your answer') } +const markLessonProgress = () => { + if (router.currentRoute.value.name == 'Lesson') { + call('lms.lms.api.mark_lesson_progress', { + course: router.currentRoute.value.params.courseName, + chapter_number: router.currentRoute.value.params.chapterNumber, + lesson_number: router.currentRoute.value.params.lessonNumber, + }) + } +} + const getSubmissionColumns = () => { return [ { diff --git a/lms/lms/api.py b/lms/lms/api.py index e6430277..91fb5bad 100644 --- a/lms/lms/api.py +++ b/lms/lms/api.py @@ -17,6 +17,7 @@ from frappe.utils import time_diff, now_datetime, get_datetime, flt from typing import Optional from lms.lms.utils import get_average_rating, get_lesson_count from xml.dom.minidom import parseString +from lms.lms.doctype.course_lesson.course_lesson import save_progress @frappe.whitelist() @@ -1030,3 +1031,14 @@ def delete_scorm_package(scorm_package_path): scorm_package_path = frappe.get_site_path("public", scorm_package_path[1:]) if os.path.exists(scorm_package_path): shutil.rmtree(scorm_package_path) + + +@frappe.whitelist() +def mark_lesson_progress(course, chapter_number, lesson_number): + chapter_name = frappe.get_value( + "Chapter Reference", {"parent": course, "idx": chapter_number}, "chapter" + ) + lesson_name = frappe.get_value( + "Lesson Reference", {"parent": chapter_name, "idx": lesson_number}, "lesson" + ) + save_progress(lesson_name, course) diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index 2955305b..40d47e4f 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -89,27 +89,25 @@ def save_progress(lesson, course): "LMS Enrollment", {"course": course, "member": frappe.session.user} ) if not membership: - return - - frappe.db.set_value("LMS Enrollment", membership, "current_lesson", lesson) - - if frappe.db.exists( - "LMS Course Progress", {"lesson": lesson, "member": frappe.session.user} - ): - return - - quiz_completed = get_quiz_progress(lesson) - if not quiz_completed: return 0 - frappe.get_doc( - { - "doctype": "LMS Course Progress", - "lesson": lesson, - "status": "Complete", - "member": frappe.session.user, - } - ).save(ignore_permissions=True) + frappe.db.set_value("LMS Enrollment", membership, "current_lesson", lesson) + already_completed = frappe.db.exists( + "LMS Course Progress", {"lesson": lesson, "member": frappe.session.user} + ) + + quiz_completed = get_quiz_progress(lesson) + assignment_completed = get_assignment_progress(lesson) + + if not already_completed and quiz_completed and assignment_completed: + frappe.get_doc( + { + "doctype": "LMS Course Progress", + "lesson": lesson, + "status": "Complete", + "member": frappe.session.user, + } + ).save(ignore_permissions=True) progress = get_course_progress(course) capture_progress_for_analytics(progress, course) @@ -159,6 +157,32 @@ def get_quiz_progress(lesson): return True +def get_assignment_progress(lesson): + lesson_details = frappe.db.get_value( + "Course Lesson", lesson, ["body", "content"], as_dict=1 + ) + assignments = [] + + if lesson_details.content: + content = json.loads(lesson_details.content) + + for block in content.get("blocks"): + if block.get("type") == "assignment": + assignments.append(block.get("data").get("assignment")) + + elif lesson_details.body: + macros = find_macros(lesson_details.body) + assignments = [value for name, value in macros if name == "Assignment"] + + for assignment in assignments: + if not frappe.db.exists( + "LMS Assignment Submission", + {"assignment": assignment, "member": frappe.session.user}, + ): + return False + return True + + @frappe.whitelist() def get_lesson_info(chapter): return frappe.db.get_value("Course Chapter", chapter, "course")