feat: add questions from LMS Portal
This commit is contained in:
@@ -17,7 +17,7 @@ from lms.lms.utils import (
|
|||||||
class LMSQuiz(Document):
|
class LMSQuiz(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_duplicate_questions()
|
self.validate_duplicate_questions()
|
||||||
self.set_total_marks()
|
self.total_marks = set_total_marks(self.name, self.questions)
|
||||||
|
|
||||||
def validate_duplicate_questions(self):
|
def validate_duplicate_questions(self):
|
||||||
questions = [row.question for row in self.questions]
|
questions = [row.question for row in self.questions]
|
||||||
@@ -27,13 +27,6 @@ class LMSQuiz(Document):
|
|||||||
_("Rows {0} have the duplicate questions.").format(frappe.bold(comma_and(rows)))
|
_("Rows {0} have the duplicate questions.").format(frappe.bold(comma_and(rows)))
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_total_marks(self):
|
|
||||||
marks = 0
|
|
||||||
for question in self.questions:
|
|
||||||
marks += question.marks
|
|
||||||
|
|
||||||
self.total_marks = marks
|
|
||||||
|
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
if not self.name:
|
if not self.name:
|
||||||
self.name = generate_slug(self.title, "LMS Quiz")
|
self.name = generate_slug(self.title, "LMS Quiz")
|
||||||
@@ -56,6 +49,13 @@ class LMSQuiz(Document):
|
|||||||
return result[0]
|
return result[0]
|
||||||
|
|
||||||
|
|
||||||
|
def set_total_marks(quiz, questions):
|
||||||
|
marks = 0
|
||||||
|
for question in questions:
|
||||||
|
marks += question.get("marks")
|
||||||
|
return marks
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def quiz_summary(quiz, results):
|
def quiz_summary(quiz, results):
|
||||||
score = 0
|
score = 0
|
||||||
@@ -116,6 +116,7 @@ def quiz_summary(quiz, results):
|
|||||||
def save_quiz(
|
def save_quiz(
|
||||||
quiz_title,
|
quiz_title,
|
||||||
passing_percentage,
|
passing_percentage,
|
||||||
|
questions,
|
||||||
max_attempts=0,
|
max_attempts=0,
|
||||||
quiz=None,
|
quiz=None,
|
||||||
show_answers=1,
|
show_answers=1,
|
||||||
@@ -134,18 +135,64 @@ def save_quiz(
|
|||||||
|
|
||||||
if quiz:
|
if quiz:
|
||||||
frappe.db.set_value("LMS Quiz", quiz, values)
|
frappe.db.set_value("LMS Quiz", quiz, values)
|
||||||
|
update_questions(quiz, questions)
|
||||||
return quiz
|
return quiz
|
||||||
else:
|
else:
|
||||||
doc = frappe.new_doc("LMS Quiz")
|
doc = frappe.new_doc("LMS Quiz")
|
||||||
doc.update(values)
|
doc.update(values)
|
||||||
doc.save()
|
doc.save()
|
||||||
|
update_questions(doc.name, questions)
|
||||||
return doc.name
|
return doc.name
|
||||||
|
|
||||||
|
|
||||||
|
def update_questions(quiz, questions):
|
||||||
|
questions = json.loads(questions)
|
||||||
|
|
||||||
|
delete_questions(quiz, questions)
|
||||||
|
add_questions(quiz, questions)
|
||||||
|
frappe.db.set_value("LMS Quiz", quiz, "total_marks", set_total_marks(quiz, questions))
|
||||||
|
|
||||||
|
|
||||||
|
def delete_questions(quiz, questions):
|
||||||
|
existing_questions = frappe.get_all(
|
||||||
|
"LMS Quiz Question",
|
||||||
|
{
|
||||||
|
"parent": quiz,
|
||||||
|
},
|
||||||
|
pluck="name",
|
||||||
|
)
|
||||||
|
|
||||||
|
current_questions = [question.get("question_name") for question in questions]
|
||||||
|
|
||||||
|
for question in existing_questions:
|
||||||
|
if question not in current_questions:
|
||||||
|
frappe.db.delete("LMS Quiz Question", question)
|
||||||
|
|
||||||
|
|
||||||
|
def add_questions(quiz, questions):
|
||||||
|
for index, question in enumerate(questions):
|
||||||
|
question = frappe._dict(question)
|
||||||
|
if question.question_name:
|
||||||
|
doc = frappe.get_doc("LMS Quiz Question", question.question_name)
|
||||||
|
else:
|
||||||
|
doc = frappe.new_doc("LMS Quiz Question")
|
||||||
|
doc.update(
|
||||||
|
{
|
||||||
|
"parent": quiz,
|
||||||
|
"parenttype": "LMS Quiz",
|
||||||
|
"parentfield": "questions",
|
||||||
|
"idx": index + 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
doc.update({"question": question.question, "marks": question.marks})
|
||||||
|
|
||||||
|
doc.save()
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def save_question(quiz, values, index):
|
def save_question(quiz, values, index):
|
||||||
values = frappe._dict(json.loads(values))
|
values = frappe._dict(json.loads(values))
|
||||||
validate_correct_answers(values)
|
|
||||||
|
|
||||||
if values.get("name"):
|
if values.get("name"):
|
||||||
doc = frappe.get_doc("LMS Question", values.get("name"))
|
doc = frappe.get_doc("LMS Question", values.get("name"))
|
||||||
@@ -182,8 +229,7 @@ def save_question(quiz, values, index):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
doc.save()
|
doc.save()
|
||||||
|
|
||||||
return doc.name
|
return doc.name
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,9 @@
|
|||||||
{% macro QuizForm(quiz) %}
|
{% macro QuizForm(quiz) %}
|
||||||
<div id="quiz-form" {% if quiz.name %} data-name="{{ quiz.name }}" data-index="{{ quiz.questions | length }}" {% endif %}>
|
<div id="quiz-form" {% if quiz.name %} data-name="{{ quiz.name }}" data-index="{{ quiz.questions | length }}" {% endif %}>
|
||||||
{{ QuizDetails(quiz) }}
|
{{ QuizDetails(quiz) }}
|
||||||
{% if quiz.questions %}
|
<div class="field-group">
|
||||||
<div class="field-group">
|
<div class="questions-table"></div>
|
||||||
<div class="questions-table"></div>
|
</div>
|
||||||
<!-- <button class="btn btn-secondary btn-sm btn-add-question mt-4">
|
|
||||||
{{ _("New Question") }}
|
|
||||||
</button> -->
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if quiz.name and not quiz.questions | length %}
|
|
||||||
{{ EmptyState() }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
@@ -153,7 +144,7 @@
|
|||||||
{{ super() }}
|
{{ super() }}
|
||||||
{% if has_course_instructor_role() or has_course_moderator_role() %}
|
{% if has_course_instructor_role() or has_course_moderator_role() %}
|
||||||
<script>
|
<script>
|
||||||
const quiz_questions = {{ quiz.questions }}
|
const quiz_questions = {{ quiz.questions or [] }}
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -13,10 +13,6 @@ frappe.ready(() => {
|
|||||||
edit_question(e);
|
edit_question(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* $(".btn-add-question").click((e) => {
|
|
||||||
show_question_modal();
|
|
||||||
}); */
|
|
||||||
|
|
||||||
$(document).on("click", ".questions-table .link-btn", (e) => {
|
$(document).on("click", ".questions-table .link-btn", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
fetch_question_data(e);
|
fetch_question_data(e);
|
||||||
@@ -131,6 +127,8 @@ const edit_question = (e) => {
|
|||||||
|
|
||||||
const save_quiz = (values) => {
|
const save_quiz = (values) => {
|
||||||
validate_mandatory();
|
validate_mandatory();
|
||||||
|
validate_questions();
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz",
|
method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz",
|
||||||
args: {
|
args: {
|
||||||
@@ -138,6 +136,7 @@ const save_quiz = (values) => {
|
|||||||
max_attempts: $("#max-attempts").val(),
|
max_attempts: $("#max-attempts").val(),
|
||||||
passing_percentage: $("#passing-percentage").val(),
|
passing_percentage: $("#passing-percentage").val(),
|
||||||
quiz: $("#quiz-form").data("name") || "",
|
quiz: $("#quiz-form").data("name") || "",
|
||||||
|
questions: this.table.get_value("questions"),
|
||||||
show_answers: $("#show-answers").is(":checked") ? 1 : 0,
|
show_answers: $("#show-answers").is(":checked") ? 1 : 0,
|
||||||
show_submission_history: $("#show-submission-history").is(
|
show_submission_history: $("#show-submission-history").is(
|
||||||
":checked"
|
":checked"
|
||||||
@@ -171,6 +170,24 @@ const validate_mandatory = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validate_questions = () => {
|
||||||
|
let questions = this.table.get_value("questions");
|
||||||
|
|
||||||
|
if (!questions.length) {
|
||||||
|
frappe.throw(__("Please add a question."));
|
||||||
|
}
|
||||||
|
|
||||||
|
questions.forEach((question, index) => {
|
||||||
|
if (!question.question) {
|
||||||
|
frappe.throw(__("Please add question in row ") + (index + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!question.marks) {
|
||||||
|
frappe.throw(__("Please add marks in row ") + (index + 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const scroll_to_element = (element) => {
|
const scroll_to_element = (element) => {
|
||||||
if ($(element).length) {
|
if ($(element).length) {
|
||||||
$([document.documentElement, document.body]).animate(
|
$([document.documentElement, document.body]).animate(
|
||||||
@@ -224,16 +241,24 @@ const create_questions_table = () => {
|
|||||||
{
|
{
|
||||||
fieldname: "question",
|
fieldname: "question",
|
||||||
fieldtype: "Link",
|
fieldtype: "Link",
|
||||||
label: "Question",
|
label: __("Question"),
|
||||||
options: "LMS Question",
|
options: "LMS Question",
|
||||||
in_list_view: 1,
|
in_list_view: 1,
|
||||||
only_select: 1,
|
only_select: 1,
|
||||||
|
reqd: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: "marks",
|
fieldname: "marks",
|
||||||
fieldtype: "Int",
|
fieldtype: "Int",
|
||||||
label: "Marks",
|
label: __("Marks"),
|
||||||
in_list_view: 1,
|
in_list_view: 1,
|
||||||
|
reqd: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "question_name",
|
||||||
|
fieldname: "Link",
|
||||||
|
options: "LMS Quiz Question",
|
||||||
|
label: __("Question Name"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user