From da72513f6ab627fe151a42f6cdf983c67fe0e46c Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 20 Jun 2023 20:12:10 +0530 Subject: [PATCH 1/6] feat: quiz in classes --- lms/hooks.py | 4 + lms/overrides/user.py | 3 - lms/plugins.py | 10 +- lms/public/css/style.css | 2 +- lms/public/js/common_functions.js | 2 +- lms/templates/{ => quiz}/quiz.html | 3 - lms/templates/quiz/quiz.js | 262 +++++++++++++++++ .../assignment_submission.py | 4 + lms/www/batch/learn.html | 4 +- lms/www/batch/learn.js | 265 ------------------ lms/www/classes/class.html | 75 ++--- lms/www/classes/class.py | 10 +- lms/www/quiz_submission/quiz_submission.html | 58 ++++ lms/www/quiz_submission/quiz_submission.py | 31 ++ lms/www/utils.py | 84 ++++-- 15 files changed, 472 insertions(+), 345 deletions(-) rename lms/templates/{ => quiz}/quiz.html (96%) create mode 100644 lms/templates/quiz/quiz.js create mode 100644 lms/www/quiz_submission/quiz_submission.html create mode 100644 lms/www/quiz_submission/quiz_submission.py diff --git a/lms/hooks.py b/lms/hooks.py index 3a20df76..b0e04048 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -184,6 +184,10 @@ website_route_rules = [ "from_route": "/assignment-submission//", "to_route": "assignment_submission/assignment_submission", }, + { + "from_route": "/quiz-submission//", + "to_route": "quiz_submission/quiz_submission", + }, ] website_redirects = [ diff --git a/lms/overrides/user.py b/lms/overrides/user.py index b3d9c947..ea0a6a87 100644 --- a/lms/overrides/user.py +++ b/lms/overrides/user.py @@ -1,7 +1,4 @@ import hashlib -import random -import re - import frappe import requests from frappe import _ diff --git a/lms/plugins.py b/lms/plugins.py index cecef2f1..7542756d 100644 --- a/lms/plugins.py +++ b/lms/plugins.py @@ -16,6 +16,7 @@ be loaded in a webpage. import frappe from urllib.parse import quote +from frappe import _ class PageExtension: @@ -102,8 +103,13 @@ def set_mandatory_fields_for_profile(): def quiz_renderer(quiz_name): - quiz = frappe.get_doc("LMS Quiz", quiz_name) + if frappe.session.user == "Guest": + return "
" + _( + "Quiz is not available to Guest users. Please login to continue." + ) + +"
" + quiz = frappe.get_doc("LMS Quiz", quiz_name) context = {"quiz": quiz} no_of_attempts = frappe.db.count( @@ -116,7 +122,7 @@ def quiz_renderer(quiz_name): ) context.update({"attempts_exceeded": True, "last_attempt_score": last_attempt_score}) - return frappe.render_template("templates/quiz.html", context) + return frappe.render_template("templates/quiz/quiz.html", context) def exercise_renderer(argument): diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 241aab80..a7930781 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1950,7 +1950,7 @@ select { } .modal-title { - font-size: var(--text-base) !important; + font-size: var(--text-lg) !important; } .class-form-title { diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index 9308c654..cd28f6af 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -70,7 +70,7 @@ const file_size = (value) => { const join_course = (e) => { e.preventDefault(); - let course = $("#outline-heading").attr("data-course"); + let course = $(e.currentTarget).attr("data-course"); if (frappe.session.user == "Guest") { window.location.href = `/login?redirect-to=/courses/${course}`; return; diff --git a/lms/templates/quiz.html b/lms/templates/quiz/quiz.html similarity index 96% rename from lms/templates/quiz.html rename to lms/templates/quiz/quiz.html index 884c836e..0e9fd8ba 100644 --- a/lms/templates/quiz.html +++ b/lms/templates/quiz/quiz.html @@ -118,9 +118,6 @@
{{ _("Submit") }}
- - {{ _("Please join the course to submit the Quiz.") }} -
{{ _("Try Again") }}
diff --git a/lms/templates/quiz/quiz.js b/lms/templates/quiz/quiz.js new file mode 100644 index 00000000..de63c050 --- /dev/null +++ b/lms/templates/quiz/quiz.js @@ -0,0 +1,262 @@ +frappe.ready(() => { + this.quiz_submitted = false; + this.answer = []; + this.is_correct = []; + const self = this; + + $(".btn-start-quiz").click((e) => { + $("#start-banner").addClass("hide"); + $("#quiz-form").removeClass("hide"); + mark_active_question(); + }); + + $(".option").click((e) => { + if (!$("#check").hasClass("hide")) enable_check(e); + }); + + $(".possibility").keyup((e) => { + enable_check(e); + }); + + $("#summary").click((e) => { + add_to_local_storage(); + quiz_summary(e); + }); + + $("#check").click((e) => { + check_answer(e); + }); + + $("#next").click((e) => { + add_to_local_storage(); + mark_active_question(e); + }); + + $("#try-again").click((e) => { + try_quiz_again(e); + }); + + if ($("#quiz-title").data("max-attempts")) { + window.addEventListener("beforeunload", (e) => { + e.returnValue = ""; + if ($(".active-question").length && !self.quiz_submitted) { + quiz_summary(); + } + }); + } +}); + +const mark_active_question = (e = undefined) => { + $(".timer").addClass("hide"); + calculate_and_display_time(100); + $(".timer").removeClass("hide"); + + let current_index = $(".active-question").attr("data-qt-index") || 0; + let next_index = parseInt(current_index) + 1; + + $(".question").addClass("hide").removeClass("active-question"); + $(`.question[data-qt-index='${next_index}']`) + .removeClass("hide") + .addClass("active-question"); + $(".current-question").text(`${next_index}`); + $("#check").removeClass("hide").attr("disabled", true); + $("#next").addClass("hide"); + $(".explanation").addClass("hide"); + initialize_timer(); +}; + +const calculate_and_display_time = (percent_time) => { + $(".timer .progress-bar").attr("aria-valuenow", percent_time); + $(".timer .progress-bar").attr("aria-valuemax", percent_time); + $(".timer .progress-bar").css("width", `${percent_time}%`); + let progress_color = percent_time < 20 ? "red" : "var(--primary-color)"; + $(".timer .progress-bar").css("background-color", progress_color); +}; + +const initialize_timer = () => { + this.time_left = $(".timer").data("time"); + calculate_and_display_time(100, this.time_left); + $(".timer").removeClass("hide"); + const total_time = $(".timer").data("time"); + this.start_time = new Date().getTime(); + const self = this; + let old_diff; + + this.timer = setInterval(function () { + var diff = (new Date().getTime() - self.start_time) / 1000; + var variation = old_diff ? diff - old_diff : diff; + old_diff = diff; + self.time_left -= variation; + let percent_time = (self.time_left / total_time) * 100; + calculate_and_display_time(percent_time); + if (self.time_left <= 0) { + clearInterval(self.timer); + $(".timer").addClass("hide"); + check_answer(); + } + }, 100); +}; + +const enable_check = (e) => { + if ($(".option:checked").length || $(".possibility").val().trim()) { + $("#check").removeAttr("disabled"); + $(".custom-checkbox").removeClass("active-option"); + $(".option:checked") + .closest(".custom-checkbox") + .addClass("active-option"); + } +}; + +const quiz_summary = (e = undefined) => { + e && e.preventDefault(); + let quiz_name = $("#quiz-title").data("name"); + let total_questions = $(".question").length; + let self = this; + + frappe.call({ + method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary", + args: { + quiz: quiz_name, + results: localStorage.getItem(quiz_name), + }, + callback: (data) => { + $(".question").addClass("hide"); + $("#summary").addClass("hide"); + $(".quiz-footer").prepend( + `
+
${__("Score")}: ${ + data.message + }/${total_questions}
+
` + ); + $("#try-again").removeClass("hide"); + self.quiz_submitted = true; + }, + }); +}; + +const try_quiz_again = (e) => { + window.location.reload(); +}; + +const check_answer = (e = undefined) => { + e && e.preventDefault(); + + let answer = $(".active-question textarea"); + if (answer.length && !answer.val().trim()) { + frappe.throw(__("Please enter your answer")); + } + + clearInterval(self.timer); + $(".timer").addClass("hide"); + + let total_questions = $(".question").length; + let current_index = $(".active-question").attr("data-qt-index"); + + $(".explanation").removeClass("hide"); + $("#check").addClass("hide"); + + if (current_index == total_questions) { + $("#summary").removeClass("hide"); + } else { + $("#next").removeClass("hide"); + } + parse_options(); +}; + +const parse_options = () => { + let type = $(".active-question").data("type"); + + if (type == "Choices") { + $(".active-question input").each((i, element) => { + is_answer_correct(type, element); + }); + } else { + is_answer_correct(type, $(".active-question textarea")); + } +}; + +const is_answer_correct = (type, element) => { + let answer = decodeURIComponent($(element).val()); + + frappe.call({ + async: false, + method: "lms.lms.doctype.lms_quiz.lms_quiz.check_answer", + args: { + question: $(".active-question").data("name"), + type: type, + answer: answer, + }, + callback: (data) => { + type == "Choices" + ? parse_choices(element, data.message) + : parse_possible_answers(element, data.message); + }, + }); +}; + +const parse_choices = (element, correct) => { + if ($(element).prop("checked")) { + self.answer.push(decodeURIComponent($(element).val())); + correct && self.is_correct.push(1); + correct ? add_icon(element, "check") : add_icon(element, "wrong"); + } else { + correct && self.is_correct.push(0); + correct + ? add_icon(element, "minus-circle-green") + : add_icon(element, "minus-circle"); + } +}; + +const parse_possible_answers = (element, correct) => { + self.answer.push(decodeURIComponent($(element).val())); + if (correct) { + self.is_correct.push(1); + show_indicator("success", element); + } else { + self.is_correct.push(0); + show_indicator("failure", element); + } +}; + +const show_indicator = (class_name, element) => { + let label = class_name == "success" ? "Correct" : "Incorrect"; + let icon = + class_name == "success" ? "#icon-solid-success" : "#icon-solid-error"; + $(`
+ + + + ${__(label)} +
`).insertAfter(element); +}; + +const add_icon = (element, icon) => { + $(element).closest(".custom-checkbox").removeClass("active-option"); + $(element).closest(".option").addClass("hide"); + let label = $(element).siblings(".option-text").text(); + $(element).siblings(".option-text").html(` +
+ + ${label} +
+ `); +}; + +const add_to_local_storage = () => { + let current_index = $(".active-question").attr("data-qt-index"); + let quiz_name = $("#quiz-title").data("name"); + let quiz_stored = JSON.parse(localStorage.getItem(quiz_name)); + + let quiz_obj = { + question_index: current_index, + answer: self.answer.join(), + is_correct: self.is_correct, + }; + + quiz_stored ? quiz_stored.push(quiz_obj) : (quiz_stored = [quiz_obj]); + localStorage.setItem(quiz_name, JSON.stringify(quiz_stored)); + + self.answer = []; + self.is_correct = []; +}; diff --git a/lms/www/assignment_submission/assignment_submission.py b/lms/www/assignment_submission/assignment_submission.py index 3f903099..6fc9cf23 100644 --- a/lms/www/assignment_submission/assignment_submission.py +++ b/lms/www/assignment_submission/assignment_submission.py @@ -5,6 +5,10 @@ from lms.lms.utils import has_course_moderator_role def get_context(context): context.no_cache = 1 + + if frappe.session.user == "Guest": + raise frappe.PermissionError(_("You don't have permission to access this page.")) + context.is_moderator = has_course_moderator_role() submission = frappe.form_dict["submission"] assignment = frappe.form_dict["assignment"] diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index d23dd671..23003702 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -87,8 +87,7 @@ {% endif %} -
{% if lesson.title %}{{ lesson.title }}{% endif %}
@@ -246,6 +245,7 @@ {{ super() }} {% for ext in page_extensions %} {{ ext.render_footer() }} diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 92dd3c9c..8eb95256 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -1,8 +1,5 @@ frappe.ready(() => { this.marked_as_complete = false; - this.quiz_submitted = false; - this.answer = []; - this.is_correct = []; let self = this; frappe.telemetry.capture("on_lesson_page", "lms"); @@ -12,14 +9,6 @@ frappe.ready(() => { save_current_lesson(); - $(".option").click((e) => { - if (!$("#check").hasClass("hide")) enable_check(e); - }); - - $(".possibility").keyup((e) => { - enable_check(e); - }); - $(window).scroll(() => { let self = this; if ( @@ -32,24 +21,6 @@ frappe.ready(() => { } }); - $("#summary").click((e) => { - add_to_local_storage(); - quiz_summary(e); - }); - - $("#check").click((e) => { - check_answer(e); - }); - - $("#next").click((e) => { - add_to_local_storage(); - mark_active_question(e); - }); - - $("#try-again").click((e) => { - try_quiz_again(e); - }); - $("#certification").click((e) => { create_certificate(e); }); @@ -62,12 +33,6 @@ frappe.ready(() => { clear_work(e); }); - $(".btn-start-quiz").click((e) => { - $("#start-banner").addClass("hide"); - $("#quiz-form").removeClass("hide"); - mark_active_question(); - }); - $(".btn-back").click((e) => { window.location.href = window.location.href.split("?")[0]; }); @@ -76,15 +41,6 @@ frappe.ready(() => { frappe.utils.copy_to_clipboard($(e.currentTarget).data("link")); $(".attachments").collapse("hide"); }); - - if ($("#quiz-title").data("max-attempts")) { - window.addEventListener("beforeunload", (e) => { - e.returnValue = ""; - if ($(".active-question").length && !self.quiz_submitted) { - quiz_summary(); - } - }); - } }); const save_current_lesson = () => { @@ -96,35 +52,6 @@ const save_current_lesson = () => { } }; -const enable_check = (e) => { - if ($(".option:checked").length || $(".possibility").val().trim()) { - $("#check").removeAttr("disabled"); - $(".custom-checkbox").removeClass("active-option"); - $(".option:checked") - .closest(".custom-checkbox") - .addClass("active-option"); - } -}; - -const mark_active_question = (e = undefined) => { - $(".timer").addClass("hide"); - calculate_and_display_time(100); - $(".timer").removeClass("hide"); - - let current_index = $(".active-question").attr("data-qt-index") || 0; - let next_index = parseInt(current_index) + 1; - - $(".question").addClass("hide").removeClass("active-question"); - $(`.question[data-qt-index='${next_index}']`) - .removeClass("hide") - .addClass("active-question"); - $(".current-question").text(`${next_index}`); - $("#check").removeClass("hide").attr("disabled", true); - $("#next").addClass("hide"); - $(".explanation").addClass("hide"); - initialize_timer(); -}; - const mark_progress = () => { let status = "Complete"; frappe.call({ @@ -155,166 +82,6 @@ const show_certificate_if_course_completed = (data) => { } }; -const quiz_summary = (e = undefined) => { - e && e.preventDefault(); - let quiz_name = $("#quiz-title").data("name"); - let total_questions = $(".question").length; - let self = this; - - frappe.call({ - method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary", - args: { - quiz: quiz_name, - results: localStorage.getItem(quiz_name), - }, - callback: (data) => { - $(".question").addClass("hide"); - $("#summary").addClass("hide"); - $("#quiz-form") - .parent() - .prepend( - `
-
${__("Score")}: ${ - data.message - }/${total_questions}
-
` - ); - $("#try-again").removeClass("hide"); - self.quiz_submitted = true; - }, - }); -}; - -const try_quiz_again = (e) => { - window.location.reload(); -}; - -const check_answer = (e = undefined) => { - e && e.preventDefault(); - - let answer = $(".active-question textarea"); - if (answer.length && !answer.val().trim()) { - frappe.throw(__("Please enter your answer")); - } - - clearInterval(self.timer); - $(".timer").addClass("hide"); - - let total_questions = $(".question").length; - let current_index = $(".active-question").attr("data-qt-index"); - - $(".explanation").removeClass("hide"); - $("#check").addClass("hide"); - - if (current_index == total_questions) { - if ($(".eligible-for-submission").length) { - $("#summary").removeClass("hide"); - } else { - $("#submission-message").removeClass("hide"); - } - } else { - $("#next").removeClass("hide"); - } - parse_options(); -}; - -const parse_options = () => { - let type = $(".active-question").data("type"); - - if (type == "Choices") { - $(".active-question input").each((i, element) => { - is_answer_correct(type, element); - }); - } else { - is_answer_correct(type, $(".active-question textarea")); - } -}; - -const is_answer_correct = (type, element) => { - let answer = decodeURIComponent($(element).val()); - - frappe.call({ - async: false, - method: "lms.lms.doctype.lms_quiz.lms_quiz.check_answer", - args: { - question: $(".active-question").data("name"), - type: type, - answer: answer, - }, - callback: (data) => { - type == "Choices" - ? parse_choices(element, data.message) - : parse_possible_answers(element, data.message); - }, - }); -}; - -const parse_choices = (element, correct) => { - if ($(element).prop("checked")) { - self.answer.push(decodeURIComponent($(element).val())); - correct && self.is_correct.push(1); - correct ? add_icon(element, "check") : add_icon(element, "wrong"); - } else { - correct && self.is_correct.push(0); - correct - ? add_icon(element, "minus-circle-green") - : add_icon(element, "minus-circle"); - } -}; - -const parse_possible_answers = (element, correct) => { - self.answer.push(decodeURIComponent($(element).val())); - if (correct) { - self.is_correct.push(1); - show_indicator("success", element); - } else { - self.is_correct.push(0); - show_indicator("failure", element); - } -}; - -const show_indicator = (class_name, element) => { - let label = class_name == "success" ? "Correct" : "Incorrect"; - let icon = - class_name == "success" ? "#icon-solid-success" : "#icon-solid-error"; - $(`
- - - - ${__(label)} -
`).insertAfter(element); -}; - -const add_icon = (element, icon) => { - $(element).closest(".custom-checkbox").removeClass("active-option"); - $(element).closest(".option").addClass("hide"); - let label = $(element).siblings(".option-text").text(); - $(element).siblings(".option-text").html(` -
- - ${label} -
- `); -}; - -const add_to_local_storage = () => { - let current_index = $(".active-question").attr("data-qt-index"); - let quiz_name = $("#quiz-title").data("name"); - let quiz_stored = JSON.parse(localStorage.getItem(quiz_name)); - - let quiz_obj = { - question_index: current_index, - answer: self.answer.join(), - is_correct: self.is_correct, - }; - - quiz_stored ? quiz_stored.push(quiz_obj) : (quiz_stored = [quiz_obj]); - localStorage.setItem(quiz_name, JSON.stringify(quiz_stored)); - - self.answer = []; - self.is_correct = []; -}; - const create_certificate = (e) => { e.preventDefault(); course = $(".title").attr("data-course"); @@ -483,35 +250,3 @@ const fetch_assignments = () => { }, }); }; - -const initialize_timer = () => { - this.time_left = $(".timer").data("time"); - calculate_and_display_time(100, this.time_left); - $(".timer").removeClass("hide"); - const total_time = $(".timer").data("time"); - this.start_time = new Date().getTime(); - const self = this; - let old_diff; - - this.timer = setInterval(function () { - var diff = (new Date().getTime() - self.start_time) / 1000; - var variation = old_diff ? diff - old_diff : diff; - old_diff = diff; - self.time_left -= variation; - let percent_time = (self.time_left / total_time) * 100; - calculate_and_display_time(percent_time); - if (self.time_left <= 0) { - clearInterval(self.timer); - $(".timer").addClass("hide"); - check_answer(); - } - }, 100); -}; - -const calculate_and_display_time = (percent_time) => { - $(".timer .progress-bar").attr("aria-valuenow", percent_time); - $(".timer .progress-bar").attr("aria-valuemax", percent_time); - $(".timer .progress-bar").css("width", `${percent_time}%`); - let progress_color = percent_time < 20 ? "red" : "var(--primary-color)"; - $(".timer .progress-bar").css("background-color", progress_color); -}; diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index 50cd4a0a..6f9e1d0e 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -260,49 +260,58 @@ {{ _("Create New") }}

- {{ _("To create a new assignment for this class, click on the create assignment button. Once you have created the new assignment you can come back to the class and add the assignment from here.") }} + {{ _("To create a new assignment or quiz for this class, click on the buttons below. Once you have created the new assignment or quiz you can come back and add it from here.") }}

-
- {% if all_assignments | length %} -
-
- {{ _("Assignments") }} -
-

- {{ _("Select the assignments you wish to include for the assessment of this class. Your selections will be automatically saved upon clicking. If you decide to remove an item from the list, simply uncheck it.") }} -

- {% for assignment in all_assignments %} -
- +
+ {{ _("Select Assessments") }} +
+

+ {{ _("Select the assessments you wish to include for this class. Your selections will be automatically saved upon clicking. If you decide to remove an item from the list, simply uncheck it.") }} +

+
+ {% if all_assignments | length %} +
+
+ {{ _("Assignments") }}
- {% endfor %} -
- {% endif %} - + {% for quiz in all_quizzes %} +
+ +
+ {% endfor %} +
+ {% endif %} +
+
diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py index 49b21e57..2bb3d385 100644 --- a/lms/www/classes/class.py +++ b/lms/www/classes/class.py @@ -76,9 +76,8 @@ def get_context(context): def get_all_quizzes(class_name): - all_quizzes = frappe.get_all( - "LMS Quiz", {"owner": frappe.session.user}, ["name", "title"] - ) + filters = {} if has_course_moderator_role() else {"owner": frappe.session.user} + all_quizzes = frappe.get_all("LMS Quiz", filters, ["name", "title"]) for quiz in all_quizzes: quiz.checked = frappe.db.exists( { @@ -92,9 +91,8 @@ def get_all_quizzes(class_name): def get_all_assignments(class_name): - all_assignments = frappe.get_all( - "LMS Assignment", {"owner": frappe.session.user}, ["name", "title"] - ) + filters = {} if has_course_moderator_role() else {"owner": frappe.session.user} + all_assignments = frappe.get_all("LMS Assignment", filters, ["name", "title"]) for assignment in all_assignments: assignment.checked = frappe.db.exists( { diff --git a/lms/www/quiz_submission/quiz_submission.html b/lms/www/quiz_submission/quiz_submission.html new file mode 100644 index 00000000..87f86caa --- /dev/null +++ b/lms/www/quiz_submission/quiz_submission.html @@ -0,0 +1,58 @@ +{% extends "lms/templates/lms_base.html" %} +{% block title %} + {{ quiz.title }} +{% endblock %} + +{% block page_content %} +
+ {{ Header() }} +
+ {{ SubmissionForm(quiz) }} +
+
+{% endblock %} + +{% macro Header() %} +
+
+
+
+
+
+ {{ quiz.title }} +
+ {% if submission.score %} +
+ {{ submission.score }} +
+ {% endif %} +
+ +
+ + +
+ +
+
+
+
+{% endmacro %} + +{% macro SubmissionForm(quiz) %} + {% include("lms/templates/quiz/quiz.html") %} +{% endmacro %} + +{% block script %} + {{ super() }} + +{% endblock %} \ No newline at end of file diff --git a/lms/www/quiz_submission/quiz_submission.py b/lms/www/quiz_submission/quiz_submission.py new file mode 100644 index 00000000..d50acf03 --- /dev/null +++ b/lms/www/quiz_submission/quiz_submission.py @@ -0,0 +1,31 @@ +import frappe +from lms.lms.utils import has_course_moderator_role +from frappe import _ + + +def get_context(context): + context.no_cache = 1 + + if frappe.session.user == "Guest": + raise frappe.PermissionError(_("You don't have permission to access this page.")) + + context.is_moderator = has_course_moderator_role() + submission = frappe.form_dict["submission"] + quiz_name = frappe.form_dict["quiz"] + + context.quiz = frappe.get_doc("LMS Quiz", quiz_name) + + if submission == "new-submission": + context.submission = frappe._dict() + else: + context.submission = frappe.db.get_value( + "LMS Quiz Submission", + submission, + ["name", "score", "member", "member_name"], + as_dict=True, + ) + if not context.is_moderator and frappe.session.user != context.submission.member: + raise frappe.PermissionError(_("You don't have permission to access this page.")) + + if not context.assignment or not context.submission: + raise frappe.PermissionError(_("Invalid Submission URL")) diff --git a/lms/www/utils.py b/lms/www/utils.py index 65d867d8..4855700e 100644 --- a/lms/www/utils.py +++ b/lms/www/utils.py @@ -71,35 +71,61 @@ def get_assessments(class_name, member=None): for assessment in assessments: if assessment.assessment_type == "LMS Assignment": - assessment.title = frappe.db.get_value( - "LMS Assignment", assessment.assessment_name, "title" - ) - - existing_submission = frappe.db.exists( - { - "doctype": "LMS Assignment Submission", - "member": member, - "assignment": assessment.assessment_name, - } - ) - - if existing_submission: - assessment.submission = frappe.db.get_value( - "LMS Assignment Submission", - existing_submission, - ["name", "status", "comments"], - as_dict=True, - ) - - assessment.edit_url = f"/assignments/{assessment.assessment_name}" - submission_name = existing_submission if existing_submission else "new-submission" - assessment.url = ( - f"/assignment-submission/{assessment.assessment_name}/{submission_name}" - ) + assessment = get_assignment_details(assessment, member) elif assessment.assessment_type == "LMS Quiz": - assessment.title = frappe.db.get_value( - "LMS Quiz", assessment.assessment_name, "title" - ) - assessment.url = f"/quizzes/{assessment.assessment_name}" + assessment = get_quiz_details(assessment, member) + return assessments + + +def get_assignment_details(assessment, member): + assessment.title = frappe.db.get_value( + "LMS Assignment", assessment.assessment_name, "title" + ) + + existing_submission = frappe.db.exists( + { + "doctype": "LMS Assignment Submission", + "member": member, + "assignment": assessment.assessment_name, + } + ) + + if existing_submission: + assessment.submission = frappe.db.get_value( + "LMS Assignment Submission", + existing_submission, + ["name", "status", "comments"], + as_dict=True, + ) + + assessment.edit_url = f"/assignments/{assessment.assessment_name}" + submission_name = existing_submission if existing_submission else "new-submission" + assessment.url = ( + f"/assignment-submission/{assessment.assessment_name}/{submission_name}" + ) + + +def get_quiz_details(assessment, member): + assessment.title = frappe.db.get_value("LMS Quiz", assessment.assessment_name, "title") + + existing_submission = frappe.db.exists( + { + "doctype": "LMS Quiz Submission", + "member": member, + "quiz": assessment.assessment_name, + } + ) + + if existing_submission: + assessment.submission = frappe.db.get_value( + "LMS Quiz Submission", + existing_submission, + ["name", "score"], + as_dict=True, + ) + + assessment.edit_url = f"/quizzes/{assessment.assessment_name}" + submission_name = existing_submission if existing_submission else "new-submission" + assessment.url = f"/quiz-submission/{assessment.assessment_name}/{submission_name}" From 7d18e1d928cb94bbada4e07811291af3036737d0 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 21 Jun 2023 20:11:30 +0530 Subject: [PATCH 2/6] fix: quiz max attempts --- lms/lms/doctype/lms_quiz/lms_quiz.json | 5 +- lms/lms/doctype/lms_quiz/lms_quiz.py | 28 +++-- lms/plugins.py | 26 ++-- lms/templates/quiz/quiz.html | 109 ++++++++++------- lms/templates/quiz/quiz.js | 36 +++--- .../assignment_submission.html | 2 + lms/www/batch/learn.js | 1 - lms/www/batch/quiz.html | 22 +++- lms/www/batch/quiz.js | 30 +---- lms/www/batch/quiz.py | 4 +- lms/www/classes/progress.html | 114 +++++++++++------- lms/www/quiz_submission/quiz_submission.html | 7 +- lms/www/quiz_submission/quiz_submission.py | 19 ++- lms/www/utils.py | 21 ++-- 14 files changed, 262 insertions(+), 162 deletions(-) diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.json b/lms/lms/doctype/lms_quiz/lms_quiz.json index a3221040..7f3a8d48 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.json +++ b/lms/lms/doctype/lms_quiz/lms_quiz.json @@ -39,7 +39,7 @@ "read_only": 1 }, { - "default": "0", + "default": "1", "fieldname": "max_attempts", "fieldtype": "Int", "label": "Max Attempts" @@ -48,6 +48,7 @@ "default": "0", "fieldname": "time", "fieldtype": "Int", + "hidden": 1, "label": "Time Per Question (in Seconds)" }, { @@ -69,7 +70,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-11-15 15:36:39.585488", + "modified": "2023-06-21 09:13:01.322701", "modified_by": "Administrator", "module": "LMS", "name": "LMS Quiz", diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.py b/lms/lms/doctype/lms_quiz/lms_quiz.py index 66ea1a3e..e8e80382 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/lms_quiz.py @@ -2,12 +2,11 @@ # For license information, please see license.txt import json - import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import cstr -from lms.lms.utils import generate_slug, has_course_moderator_role +from lms.lms.utils import generate_slug, has_course_moderator_role, can_create_courses class LMSQuiz(Document): @@ -126,7 +125,7 @@ def quiz_summary(quiz, results): score += correct del result["question_index"] - frappe.get_doc( + submission = frappe.get_doc( { "doctype": "LMS Quiz Submission", "quiz": quiz, @@ -134,19 +133,32 @@ def quiz_summary(quiz, results): "score": score, "member": frappe.session.user, } - ).save(ignore_permissions=True) + ) + submission.save(ignore_permissions=True) - return score + return { + "score": score, + "submission": submission.name, + } @frappe.whitelist() -def save_quiz(quiz_title, quiz): +def save_quiz(quiz_title, max_attempts=1, quiz=None): + if not can_create_courses(): + return + + values = { + "title": quiz_title, + "max_attempts": max_attempts, + } + if quiz: - frappe.db.set_value("LMS Quiz", quiz, "title", quiz_title) + print(max_attempts) + frappe.db.set_value("LMS Quiz", quiz, values) return quiz else: doc = frappe.new_doc("LMS Quiz") - doc.update({"title": quiz_title}) + doc.update(values) doc.save(ignore_permissions=True) return doc.name diff --git a/lms/plugins.py b/lms/plugins.py index 7542756d..28badff8 100644 --- a/lms/plugins.py +++ b/lms/plugins.py @@ -110,19 +110,29 @@ def quiz_renderer(quiz_name): +"" quiz = frappe.get_doc("LMS Quiz", quiz_name) - context = {"quiz": quiz} - no_of_attempts = frappe.db.count( "LMS Quiz Submission", {"owner": frappe.session.user, "quiz": quiz_name} ) - if quiz.max_attempts and no_of_attempts >= quiz.max_attempts: - last_attempt_score = frappe.db.get_value( - "LMS Quiz Submission", {"owner": frappe.session.user, "quiz": quiz_name}, ["score"] - ) + all_submissions = frappe.get_all( + "LMS Quiz Submission", + { + "quiz": quiz.name, + "member": frappe.session.user, + }, + ["name", "score", "creation"], + order_by="creation desc", + ) - context.update({"attempts_exceeded": True, "last_attempt_score": last_attempt_score}) - return frappe.render_template("templates/quiz/quiz.html", context) + return frappe.render_template( + "templates/quiz/quiz.html", + { + "quiz": quiz, + "no_of_attempts": no_of_attempts, + "all_submissions": all_submissions, + "no_of_attempts": no_of_attempts, + }, + ) def exercise_renderer(argument): diff --git a/lms/templates/quiz/quiz.html b/lms/templates/quiz/quiz.html index 0e9fd8ba..cf218135 100644 --- a/lms/templates/quiz/quiz.html +++ b/lms/templates/quiz/quiz.html @@ -1,16 +1,26 @@ -{% if attempts_exceeded %} -
-

- {{ quiz.title }} -

-
- {{ _("You have already exceeded the maximum number of attempts allowed for this quiz.") }} - {{ _("Your latest score is {0}.").format(last_attempt_score) }} -
-
+{% if not hide_quiz %} +
+
    + +
  • + {{ _("This quiz consists of {0} questions.").format(quiz.questions | length) }} +
  • + + {% if quiz.max_attempts %} + {% set suffix = "times" if quiz.max_attempts > 1 else "time" %} +
  • + {{ _("You can attempt this quiz only {0} {1}").format(quiz.max_attempts, suffix) }} +
  • + {% endif %} + + {% if quiz.time %} +
  • + {{ _("The quiz has a time limit. For each question you will be given {0} seconds.").format(quiz.time) }} +
  • + {% endif %} +
+ -{% else %} -
@@ -18,30 +28,17 @@ {{ quiz.title }}
-
- {{ _("This quiz consists of {0} questions.").format(quiz.questions | length) }} + {% if not quiz.max_attempts or no_of_attempts < quiz.max_attempts %} + + {% else %} +
+ {{ _("You have already exceeded the maximum number of attempts allowed for this quiz.") }} +
+ {% endif %}
- {% if quiz.max_attempts %} - {% set suffix = "times" if quiz.max_attempts > 1 else "time" %} -
- {{ _("This quiz can only be taken {0} {1}. If you attempt the quiz but leave the page before submitting, - the quiz will be automatically submitted.").format(quiz.max_attempts, suffix) }} -
- {% endif %} - - {% if quiz.time %} -
- {{ _("The quiz has a time limit. For each question you will be given {0} seconds.").format(quiz.time) }} -
- {% endif %} - - -
- -
@@ -108,20 +105,50 @@
{% endif %} - - -
+ +
-
+ +
+ {% endif %} + +{% if all_submissions | length %} +
+
+ {{ _("All Submissions") }} +
+
+
+
+
+
{{ _("No.") }}
+
{{ _("Date") }}
+
{{ _("Score") }}
+
+
+
+
+ {% for submission in all_submissions %} +
+
+
{{ loop.index }}
+
{{ frappe.utils.format_datetime(submission.creation, "medium") }}
+
{{ submission.score }}
+
+
+ {% endfor %} +
+
+ +
+{% endif %} \ No newline at end of file diff --git a/lms/templates/quiz/quiz.js b/lms/templates/quiz/quiz.js index de63c050..05fd5889 100644 --- a/lms/templates/quiz/quiz.js +++ b/lms/templates/quiz/quiz.js @@ -3,6 +3,7 @@ frappe.ready(() => { this.answer = []; this.is_correct = []; const self = this; + localStorage.removeItem($("#quiz-title").data("name")); $(".btn-start-quiz").click((e) => { $("#start-banner").addClass("hide"); @@ -19,15 +20,18 @@ frappe.ready(() => { }); $("#summary").click((e) => { + e.preventDefault(); add_to_local_storage(); quiz_summary(e); }); $("#check").click((e) => { + e.preventDefault(); check_answer(e); }); $("#next").click((e) => { + e.preventDefault(); add_to_local_storage(); mark_active_question(e); }); @@ -35,15 +39,6 @@ frappe.ready(() => { $("#try-again").click((e) => { try_quiz_again(e); }); - - if ($("#quiz-title").data("max-attempts")) { - window.addEventListener("beforeunload", (e) => { - e.returnValue = ""; - if ($(".active-question").length && !self.quiz_submitted) { - quiz_summary(); - } - }); - } }); const mark_active_question = (e = undefined) => { @@ -122,13 +117,15 @@ const quiz_summary = (e = undefined) => { callback: (data) => { $(".question").addClass("hide"); $("#summary").addClass("hide"); - $(".quiz-footer").prepend( - `
-
${__("Score")}: ${ - data.message - }/${total_questions}
-
` + $(".quiz-footer span").addClass("hide"); + $("#quiz-form").prepend( + `
+ ${__("Your score is ")} ${data.message.score} ${__( + " out of " + )} ${total_questions} +
` ); + $("#try-again").data("submission", data.message.submission); $("#try-again").removeClass("hide"); self.quiz_submitted = true; }, @@ -136,7 +133,14 @@ const quiz_summary = (e = undefined) => { }; const try_quiz_again = (e) => { - window.location.reload(); + if (window.location.href.includes("new-submission")) { + window.location.href = window.location.pathname.replace( + "new-submission", + $ + ); + } else { + window.location.reload(); + } }; const check_answer = (e = undefined) => { diff --git a/lms/www/assignment_submission/assignment_submission.html b/lms/www/assignment_submission/assignment_submission.html index 6afb2192..551c829f 100644 --- a/lms/www/assignment_submission/assignment_submission.html +++ b/lms/www/assignment_submission/assignment_submission.html @@ -32,6 +32,8 @@ {{ _("All Classes") }} + + {{ _("Assignment Submission") }} diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 8eb95256..3b1554f3 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -3,7 +3,6 @@ frappe.ready(() => { let self = this; frappe.telemetry.capture("on_lesson_page", "lms"); - localStorage.removeItem($("#quiz-title").data("name")); fetch_assignments(); diff --git a/lms/www/batch/quiz.html b/lms/www/batch/quiz.html index 16a2e4c2..25078a62 100644 --- a/lms/www/batch/quiz.html +++ b/lms/www/batch/quiz.html @@ -58,13 +58,16 @@ - {% if quiz.name %}
- + {% endif %} +
- {% endif %} @@ -86,6 +89,19 @@ + +
+
+ {{ _("Max Attempts") }} +
+
+ {{ _("Enter the maximum number of times a user can attempt this quiz") }} +
+
+ {% set max_attempts = quiz.max_attempts if quiz.name else 1 %} + +
+
{% endmacro %} diff --git a/lms/www/batch/quiz.js b/lms/www/batch/quiz.js index 9f592b74..29ba3519 100644 --- a/lms/www/batch/quiz.js +++ b/lms/www/batch/quiz.js @@ -1,8 +1,9 @@ frappe.ready(() => { - $("#quiz-title").focusout((e) => { - if ($("#quiz-title").val() != $("#quiz-title").data("title")) { - save_quiz({ quiz_title: $("#quiz-title").val() }); - } + $(".btn-save-quiz").click((e) => { + save_quiz({ + quiz_title: $("#quiz-title").val(), + max_attempts: $("#max-attempts").val(), + }); }); $(".question-row").click((e) => { @@ -14,26 +15,6 @@ frappe.ready(() => { }); }); -const show_quiz_modal = () => { - let quiz_dialog = new frappe.ui.Dialog({ - title: __("Create Quiz"), - fields: [ - { - fieldtype: "Data", - label: __("Quiz Title"), - fieldname: "quiz_title", - reqd: 1, - }, - ], - primary_action: (values) => { - quiz_dialog.hide(); - save_quiz(values); - }, - }); - - quiz_dialog.show(); -}; - const show_question_modal = (values = {}) => { let fields = get_question_fields(values); @@ -142,6 +123,7 @@ const save_quiz = (values) => { method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz", args: { quiz_title: values.quiz_title, + max_attempts: values.max_attempts, quiz: $("#quiz-form").data("name") || "", }, callback: (data) => { diff --git a/lms/www/batch/quiz.py b/lms/www/batch/quiz.py index 2d83c588..e46292bc 100644 --- a/lms/www/batch/quiz.py +++ b/lms/www/batch/quiz.py @@ -20,7 +20,9 @@ def get_context(context): else: fields_arr = ["name", "question", "type"] - context.quiz = frappe.db.get_value("LMS Quiz", quizname, ["title", "name"], as_dict=1) + context.quiz = frappe.db.get_value( + "LMS Quiz", quizname, ["title", "name", "max_attempts"], as_dict=1 + ) context.quiz.questions = frappe.get_all( "LMS Quiz Question", {"parent": quizname}, fields_arr, order_by="idx" ) diff --git a/lms/www/classes/progress.html b/lms/www/classes/progress.html index 4f7be796..87479189 100644 --- a/lms/www/classes/progress.html +++ b/lms/www/classes/progress.html @@ -1,6 +1,6 @@ {% extends "lms/templates/lms_base.html" %} {% block title %} - {{ student.first_name }} 's {{ _("Progress") }} + {{ student.first_name }}'s {{ _("Progress") }} {% endblock %} @@ -15,61 +15,93 @@ {% macro Header() %}
-
-
-
-
- {{ _("{0}'s Progress").format(student.full_name) }} -
-
- - {{ _("All Classes") }} - - +
+
+
+
+ {{ _("{0}").format(student.full_name) }} +
+
+ + {{ _("All Classes") }} + + - {{ class_info.name }} - - - {{ _("{0}'s Progress").format(student.full_name) }} -
-
+ {{ class_info.name }} + + + {{ _("Student Progress").format(student.full_name) }} +
+
{% if is_moderator %} - {% endif %} -
-
+
+
{% endmacro %} {% macro Progress(class_info, student) %} {% if assessments | length %} -
- {% for assessment in assessments %} -
- - {{ assessment.title }} - - - {% if assessment.submission %} - {% set status = assessment.submission.status %} - {% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %} -
-
- {{ assessment.submission.status }} +
+
+
+
+
+ {{ _("Assessment") }} +
+
+ {{ _("Type") }} +
+
+ {{ _("Status/Score") }}
- {% else %} -
- {{ _("Not Attempted") }} +
+ +
+ {% for assessment in assessments %} + {% set has_access = is_moderator and assessment.submission or frappe.session.user == student.name %} +
+
+ + {{ assessment.title }} + +
+ {{ (assessment.assessment_type).split("LMS ")[1] }}
- {% endif %} + +
+ {% if assessment.submission %} + {% if assessment.assessment_type == "LMS Assignment" %} + {% set status = assessment.submission.status %} + {% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %} +
+ {{ status }} +
+ {% else %} +
+ {{ assessment.submission.score }} +
+ {% endif %} + {% else %} +
+ {{ _("Not Attempted") }} +
+ {% endif %} +
+ +
{% endfor %}
diff --git a/lms/www/quiz_submission/quiz_submission.html b/lms/www/quiz_submission/quiz_submission.html index 87f86caa..cba6b20d 100644 --- a/lms/www/quiz_submission/quiz_submission.html +++ b/lms/www/quiz_submission/quiz_submission.html @@ -21,16 +21,13 @@
{{ quiz.title }}
- {% if submission.score %} -
- {{ submission.score }} -
- {% endif %}
{{ _("All Classes") }} + + {{ _("Quiz Submission") }}
diff --git a/lms/www/quiz_submission/quiz_submission.py b/lms/www/quiz_submission/quiz_submission.py index d50acf03..4519f89b 100644 --- a/lms/www/quiz_submission/quiz_submission.py +++ b/lms/www/quiz_submission/quiz_submission.py @@ -24,8 +24,25 @@ def get_context(context): ["name", "score", "member", "member_name"], as_dict=True, ) + if not context.is_moderator and frappe.session.user != context.submission.member: raise frappe.PermissionError(_("You don't have permission to access this page.")) - if not context.assignment or not context.submission: + if not context.quiz or not context.submission: raise frappe.PermissionError(_("Invalid Submission URL")) + + context.all_submissions = frappe.get_all( + "LMS Quiz Submission", + { + "quiz": context.quiz.name, + "member": context.submission.member, + }, + ["name", "score", "creation"], + order_by="creation desc", + ) + + context.no_of_attempts = len(context.all_submissions) or 0 + context.hide_quiz = ( + context.is_moderator and context.submission.member != frappe.session.user + ) + print(context.no_of_attempts) diff --git a/lms/www/utils.py b/lms/www/utils.py index 4855700e..a99046bc 100644 --- a/lms/www/utils.py +++ b/lms/www/utils.py @@ -110,22 +110,21 @@ def get_assignment_details(assessment, member): def get_quiz_details(assessment, member): assessment.title = frappe.db.get_value("LMS Quiz", assessment.assessment_name, "title") - existing_submission = frappe.db.exists( + existing_submission = frappe.get_all( + "LMS Quiz Submission", { - "doctype": "LMS Quiz Submission", "member": member, "quiz": assessment.assessment_name, - } + }, + ["name", "score"], + order_by="creation desc", ) - if existing_submission: - assessment.submission = frappe.db.get_value( - "LMS Quiz Submission", - existing_submission, - ["name", "score"], - as_dict=True, - ) + if len(existing_submission): + assessment.submission = existing_submission[0] assessment.edit_url = f"/quizzes/{assessment.assessment_name}" - submission_name = existing_submission if existing_submission else "new-submission" + submission_name = ( + existing_submission[0].name if len(existing_submission) else "new-submission" + ) assessment.url = f"/quiz-submission/{assessment.assessment_name}/{submission_name}" From bb0abe27cdbadb44b7307420b63ddd8f8af7ce98 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 22 Jun 2023 10:52:57 +0530 Subject: [PATCH 3/6] fix: redirect after quiz submission --- lms/templates/quiz/quiz.html | 2 +- lms/templates/quiz/quiz.js | 11 ++++++----- lms/www/classes/class.html | 4 ++-- lms/www/quiz_submission/quiz_submission.py | 3 ++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lms/templates/quiz/quiz.html b/lms/templates/quiz/quiz.html index cf218135..4ae2b242 100644 --- a/lms/templates/quiz/quiz.html +++ b/lms/templates/quiz/quiz.html @@ -114,7 +114,7 @@ -
diff --git a/lms/templates/quiz/quiz.js b/lms/templates/quiz/quiz.js index 05fd5889..e5aa0b00 100644 --- a/lms/templates/quiz/quiz.js +++ b/lms/templates/quiz/quiz.js @@ -125,7 +125,7 @@ const quiz_summary = (e = undefined) => { )} ${total_questions} ` ); - $("#try-again").data("submission", data.message.submission); + $("#try-again").attr("data-submission", data.message.submission); $("#try-again").removeClass("hide"); self.quiz_submitted = true; }, @@ -133,11 +133,12 @@ const quiz_summary = (e = undefined) => { }; const try_quiz_again = (e) => { + e.preventDefault(); if (window.location.href.includes("new-submission")) { - window.location.href = window.location.pathname.replace( - "new-submission", - $ - ); + const target = $(e.currentTarget); + window.location.href = `/quiz-submission/${target.data( + "quiz" + )}/${target.data("submission")}`; } else { window.location.reload(); } diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index 6f9e1d0e..ec398d4e 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -263,10 +263,10 @@ {{ _("To create a new assignment or quiz for this class, click on the buttons below. Once you have created the new assignment or quiz you can come back and add it from here.") }}

diff --git a/lms/www/quiz_submission/quiz_submission.py b/lms/www/quiz_submission/quiz_submission.py index 4519f89b..f7d3f35b 100644 --- a/lms/www/quiz_submission/quiz_submission.py +++ b/lms/www/quiz_submission/quiz_submission.py @@ -17,6 +17,8 @@ def get_context(context): if submission == "new-submission": context.submission = frappe._dict() + context.no_of_attempts = 0 + context.hide_quiz = False else: context.submission = frappe.db.get_value( "LMS Quiz Submission", @@ -45,4 +47,3 @@ def get_context(context): context.hide_quiz = ( context.is_moderator and context.submission.member != frappe.session.user ) - print(context.no_of_attempts) From c9a5c0801eac99bbf1d44a26afe6bbe2815d6ee2 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 22 Jun 2023 10:53:11 +0530 Subject: [PATCH 4/6] fix: redirect after quiz submission --- lms/templates/quiz/quiz.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lms/templates/quiz/quiz.js b/lms/templates/quiz/quiz.js index e5aa0b00..9f1466f7 100644 --- a/lms/templates/quiz/quiz.js +++ b/lms/templates/quiz/quiz.js @@ -136,9 +136,9 @@ const try_quiz_again = (e) => { e.preventDefault(); if (window.location.href.includes("new-submission")) { const target = $(e.currentTarget); - window.location.href = `/quiz-submission/${target.data( - "quiz" - )}/${target.data("submission")}`; + window.location.href = `/quiz-submission/ + ${target.data("quiz")}/ + ${target.data("submission")}`; } else { window.location.reload(); } From d8e11f69cc04e57b41429eb9b04b153ebdafd99a Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 22 Jun 2023 11:14:15 +0530 Subject: [PATCH 5/6] fix: quiz creation url --- lms/templates/quiz/quiz.js | 5 ++--- lms/www/classes/class.html | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lms/templates/quiz/quiz.js b/lms/templates/quiz/quiz.js index 9f1466f7..37fd563e 100644 --- a/lms/templates/quiz/quiz.js +++ b/lms/templates/quiz/quiz.js @@ -120,9 +120,8 @@ const quiz_summary = (e = undefined) => { $(".quiz-footer span").addClass("hide"); $("#quiz-form").prepend( `
- ${__("Your score is ")} ${data.message.score} ${__( - " out of " - )} ${total_questions} + ${__("Your score is")} ${data.message.score} + ${__("out of")} ${total_questions}
` ); $("#try-again").attr("data-submission", data.message.submission); diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index ec398d4e..01f895ac 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -266,7 +266,7 @@ {{ _("Create Assignment") }} - + {{ _("Create Quiz") }} From 22199da7d4a2b5261fbdd08b7bfdcbf9161c5daf Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 22 Jun 2023 11:25:32 +0530 Subject: [PATCH 6/6] fix: linters --- lms/lms/doctype/lms_quiz/lms_quiz.py | 1 - lms/plugins.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.py b/lms/lms/doctype/lms_quiz/lms_quiz.py index e8e80382..cfe1bb45 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/lms_quiz.py @@ -153,7 +153,6 @@ def save_quiz(quiz_title, max_attempts=1, quiz=None): } if quiz: - print(max_attempts) frappe.db.set_value("LMS Quiz", quiz, values) return quiz else: diff --git a/lms/plugins.py b/lms/plugins.py index 28badff8..1a66d87a 100644 --- a/lms/plugins.py +++ b/lms/plugins.py @@ -130,7 +130,7 @@ def quiz_renderer(quiz_name): "quiz": quiz, "no_of_attempts": no_of_attempts, "all_submissions": all_submissions, - "no_of_attempts": no_of_attempts, + "hide_quiz": False, }, )