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 %}
+
+ {{ _("Start") }}
+
+ {% 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 %}
-
-
- {{ _("Start the Quiz") }}
-
-
-
-
{% endif %}
-
{{ _("Check") }}
-
+
{{ _("Next Question") }}
-
-
+
+
{{ _("Submit") }}
-
-
+
+
{{ _("Try Again") }}
-
+
{% endif %}
+
+{% if all_submissions | length %}
+
+
+ {{ _("All Submissions") }}
+
+
+
+
+{% 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 %}
-
+ {% if quiz.name %}
+
{{ _("Add Question") }}
+ {% endif %}
+
+ {{ _("Save") }}
+
- {% 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() %}
{% 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 %}
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}"