feat: quiz validations and marks
This commit is contained in:
@@ -32,11 +32,11 @@
|
|||||||
"column_break_lknb",
|
"column_break_lknb",
|
||||||
"explanation_4",
|
"explanation_4",
|
||||||
"section_break_hkfe",
|
"section_break_hkfe",
|
||||||
"possible_answer_1",
|
"possibility_1",
|
||||||
"possible_answer_3",
|
"possibility_3",
|
||||||
"column_break_wpjr",
|
"column_break_wpjr",
|
||||||
"possible_answer_2",
|
"possibility_2",
|
||||||
"possible_answer_4"
|
"possibility_4"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -167,34 +167,34 @@
|
|||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "possible_answer_1",
|
"fieldname": "column_break_wpjr",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "possibility_1",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Possible Answer 1",
|
"label": "Possible Answer 1",
|
||||||
"mandatory_depends_on": "eval: doc.type == 'User Input'"
|
"mandatory_depends_on": "eval: doc.type == 'User Input'"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "possible_answer_3",
|
"fieldname": "possibility_3",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Possible Answer 3"
|
"label": "Possible Answer 3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_wpjr",
|
"fieldname": "possibility_2",
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "possible_answer_2",
|
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Possible Answer 2"
|
"label": "Possible Answer 2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "possible_answer_4",
|
"fieldname": "possibility_4",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Possible Answer 4"
|
"label": "Possible Answer 4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-10-10 16:03:38.776125",
|
"modified": "2023-10-16 11:39:39.757008",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Question",
|
"name": "LMS Question",
|
||||||
|
|||||||
@@ -12,6 +12,10 @@
|
|||||||
"column_break_gaac",
|
"column_break_gaac",
|
||||||
"max_attempts",
|
"max_attempts",
|
||||||
"show_submission_history",
|
"show_submission_history",
|
||||||
|
"section_break_hsiv",
|
||||||
|
"passing_percentage",
|
||||||
|
"column_break_rocd",
|
||||||
|
"total_marks",
|
||||||
"section_break_sbjx",
|
"section_break_sbjx",
|
||||||
"questions",
|
"questions",
|
||||||
"section_break_3",
|
"section_break_3",
|
||||||
@@ -90,11 +94,30 @@
|
|||||||
"fieldname": "show_submission_history",
|
"fieldname": "show_submission_history",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Show Submission History"
|
"label": "Show Submission History"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_hsiv",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "passing_percentage",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Passing Percentage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_rocd",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_marks",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Total Marks",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-07-04 15:26:24.457745",
|
"modified": "2023-10-16 17:21:33.932981",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Quiz",
|
"name": "LMS Quiz",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import json
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cstr
|
from frappe.utils import cstr, comma_and
|
||||||
from lms.lms.doctype.lms_question.lms_question import validate_correct_answers
|
from lms.lms.doctype.lms_question.lms_question import validate_correct_answers
|
||||||
from lms.lms.utils import (
|
from lms.lms.utils import (
|
||||||
generate_slug,
|
generate_slug,
|
||||||
@@ -15,6 +15,17 @@ from lms.lms.utils import (
|
|||||||
|
|
||||||
|
|
||||||
class LMSQuiz(Document):
|
class LMSQuiz(Document):
|
||||||
|
def validate(self):
|
||||||
|
self.validate_duplicate_questions()
|
||||||
|
|
||||||
|
def validate_duplicate_questions(self):
|
||||||
|
questions = [row.question for row in self.questions]
|
||||||
|
rows = [i + 1 for i, x in enumerate(questions) if questions.count(x) > 1]
|
||||||
|
if len(rows):
|
||||||
|
frappe.throw(
|
||||||
|
_("Rows {0} have the duplicate questions.").format(frappe.bold(comma_and(rows)))
|
||||||
|
)
|
||||||
|
|
||||||
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")
|
||||||
@@ -44,11 +55,13 @@ def quiz_summary(quiz, results):
|
|||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
correct = result["is_correct"][0]
|
correct = result["is_correct"][0]
|
||||||
result["question"] = frappe.db.get_value(
|
question_name = frappe.db.get_value(
|
||||||
"LMS Quiz Question",
|
"LMS Quiz Question",
|
||||||
{"parent": quiz, "idx": result["question_index"] + 1},
|
{"parent": quiz, "idx": result["question_index"] + 1},
|
||||||
["question"],
|
["question"],
|
||||||
)
|
)
|
||||||
|
result["question_name"] = question_name
|
||||||
|
result["question"] = frappe.db.get_value("LMS Question", question_name, "question")
|
||||||
|
|
||||||
for point in result["is_correct"]:
|
for point in result["is_correct"]:
|
||||||
correct = correct and point
|
correct = correct and point
|
||||||
@@ -184,9 +197,7 @@ def check_choice_answers(question, answers):
|
|||||||
fields.append(f"option_{cstr(num)}")
|
fields.append(f"option_{cstr(num)}")
|
||||||
fields.append(f"is_correct_{cstr(num)}")
|
fields.append(f"is_correct_{cstr(num)}")
|
||||||
|
|
||||||
question_details = frappe.db.get_value(
|
question_details = frappe.db.get_value("LMS Question", question, fields, as_dict=1)
|
||||||
"LMS Quiz Question", question, fields, as_dict=1
|
|
||||||
)
|
|
||||||
|
|
||||||
for num in range(1, 5):
|
for num in range(1, 5):
|
||||||
if question_details[f"option_{num}"] in answers:
|
if question_details[f"option_{num}"] in answers:
|
||||||
|
|||||||
@@ -5,22 +5,34 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"question"
|
"question",
|
||||||
|
"marks"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldname": "question",
|
"fieldname": "question",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
|
"in_preview": 1,
|
||||||
"label": "Question",
|
"label": "Question",
|
||||||
"options": "LMS Question",
|
"options": "LMS Question",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "marks",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"in_preview": 1,
|
||||||
|
"label": "Marks",
|
||||||
|
"non_negative": 1,
|
||||||
|
"reqd": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-10-10 15:42:51.791902",
|
"modified": "2023-10-16 19:51:03.893143",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Quiz Question",
|
"name": "LMS Quiz Question",
|
||||||
|
|||||||
@@ -6,8 +6,11 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"question",
|
"question",
|
||||||
"answer",
|
"section_break_fztv",
|
||||||
"is_correct"
|
"question_name",
|
||||||
|
"is_correct",
|
||||||
|
"column_break_flus",
|
||||||
|
"answer"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -31,12 +34,26 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Is Correct",
|
"label": "Is Correct",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_fztv",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "question_name",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Question Name",
|
||||||
|
"options": "LMS Question"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_flus",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-11-24 11:15:45.931119",
|
"modified": "2023-10-16 15:25:03.380843",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Quiz Result",
|
"name": "LMS Quiz Result",
|
||||||
|
|||||||
@@ -73,4 +73,5 @@ lms.patches.v1_0.change_naming_for_batch_course #14-09-2023
|
|||||||
execute:frappe.permissions.reset_perms("LMS Enrollment")
|
execute:frappe.permissions.reset_perms("LMS Enrollment")
|
||||||
lms.patches.v1_0.create_student_role
|
lms.patches.v1_0.create_student_role
|
||||||
lms.patches.v1_0.mark_confirmation_for_batch_students
|
lms.patches.v1_0.mark_confirmation_for_batch_students
|
||||||
lms.patches.v1_0.create_quiz_questions
|
lms.patches.v1_0.create_quiz_questions
|
||||||
|
lms.patches.v1_0.add_default_marks #16-10-2023
|
||||||
16
lms/patches/v1_0/add_default_marks.py
Normal file
16
lms/patches/v1_0/add_default_marks.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
questions = frappe.get_all("LMS Quiz Question", pluck="name")
|
||||||
|
|
||||||
|
for question in questions:
|
||||||
|
frappe.db.set_value("LMS Quiz Question", question, "marks", 1)
|
||||||
|
|
||||||
|
quizzes = frappe.get_all("LMS Quiz", pluck="name")
|
||||||
|
|
||||||
|
for quiz in quizzes:
|
||||||
|
questions_count = frappe.db.count("LMS Quiz Question", {"parent": quiz})
|
||||||
|
frappe.db.set_value(
|
||||||
|
"LMS Quiz", quiz, {"total_marks": questions_count, "passing_percentage": 100}
|
||||||
|
)
|
||||||
@@ -3,31 +3,21 @@ import frappe
|
|||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
frappe.reload_doc("lms", "doctype", "lms_question")
|
frappe.reload_doc("lms", "doctype", "lms_question")
|
||||||
frappe.reload_doc("lms", "doctype", "lms_quiz_question")
|
|
||||||
|
fields = ["name", "question", "type", "multiple"]
|
||||||
|
for num in range(1, 5):
|
||||||
|
fields.append(f"option_{num}")
|
||||||
|
fields.append(f"is_correct_{num}")
|
||||||
|
fields.append(f"explanation_{num}")
|
||||||
|
fields.append(f"possibility_{num}")
|
||||||
|
|
||||||
questions = frappe.get_all(
|
questions = frappe.get_all(
|
||||||
"LMS Quiz Question",
|
"LMS Quiz Question",
|
||||||
fields=[
|
fields=fields,
|
||||||
"name",
|
|
||||||
"question",
|
|
||||||
"type",
|
|
||||||
"multiple",
|
|
||||||
"option_1",
|
|
||||||
"is_correct_1",
|
|
||||||
"explanation_1",
|
|
||||||
"option_2",
|
|
||||||
"is_correct_2",
|
|
||||||
"explanation_2",
|
|
||||||
"option_3",
|
|
||||||
"is_correct_3",
|
|
||||||
"explanation_3",
|
|
||||||
"option_4",
|
|
||||||
"is_correct_4",
|
|
||||||
"explanation_4",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for question in questions:
|
for question in questions:
|
||||||
|
print(question.name)
|
||||||
doc = frappe.new_doc("LMS Question")
|
doc = frappe.new_doc("LMS Question")
|
||||||
doc.update(
|
doc.update(
|
||||||
{
|
{
|
||||||
@@ -44,9 +34,10 @@ def execute():
|
|||||||
f"option_{num}": question[f"option_{num}"],
|
f"option_{num}": question[f"option_{num}"],
|
||||||
f"is_correct_{num}": question[f"is_correct_{num}"],
|
f"is_correct_{num}": question[f"is_correct_{num}"],
|
||||||
f"explanation_{num}": question[f"explanation_{num}"],
|
f"explanation_{num}": question[f"explanation_{num}"],
|
||||||
|
f"possibility_{num}": question[f"possibility_{num}"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
doc.save()
|
doc.save()
|
||||||
|
print(doc.name)
|
||||||
frappe.db.set_value("LMS Quiz Question", question.name, "question", doc.name)
|
frappe.db.set_value("LMS Quiz Question", question.name, "question", doc.name)
|
||||||
|
|||||||
@@ -109,7 +109,28 @@ def quiz_renderer(quiz_name):
|
|||||||
)
|
)
|
||||||
+"</div>"
|
+"</div>"
|
||||||
|
|
||||||
quiz = frappe.get_doc("LMS Quiz", quiz_name)
|
quiz = frappe.db.get_value(
|
||||||
|
"LMS Quiz",
|
||||||
|
quiz_name,
|
||||||
|
["name", "title", "max_attempts", "show_answers", "show_submission_history"],
|
||||||
|
as_dict=True,
|
||||||
|
)
|
||||||
|
quiz.questions = []
|
||||||
|
fields = ["name", "question", "type", "multiple"]
|
||||||
|
for num in range(1, 5):
|
||||||
|
fields.append(f"option_{num}")
|
||||||
|
fields.append(f"is_correct_{num}")
|
||||||
|
fields.append(f"explanation_{num}")
|
||||||
|
fields.append(f"possibility_{num}")
|
||||||
|
|
||||||
|
questions = frappe.get_all(
|
||||||
|
"LMS Quiz Question", {"parent": quiz.name}, pluck="question", order_by="idx"
|
||||||
|
)
|
||||||
|
|
||||||
|
for question in questions:
|
||||||
|
details = frappe.db.get_value("LMS Question", question, fields, as_dict=1)
|
||||||
|
quiz.questions.append(details)
|
||||||
|
|
||||||
no_of_attempts = frappe.db.count(
|
no_of_attempts = frappe.db.count(
|
||||||
"LMS Quiz Submission", {"owner": frappe.session.user, "quiz": quiz_name}
|
"LMS Quiz Submission", {"owner": frappe.session.user, "quiz": quiz_name}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -51,7 +51,8 @@
|
|||||||
data-multi="{{ question.multiple }}" data-qt-index="{{ loop.index }}">
|
data-multi="{{ question.multiple }}" data-qt-index="{{ loop.index }}">
|
||||||
<div>
|
<div>
|
||||||
<div class="question-number">
|
<div class="question-number">
|
||||||
{{ _("Question ") }}{{ loop.index }}: {{ instruction }}</div>
|
{{ _("Question ") }}{{ loop.index }}: {{ instruction }}
|
||||||
|
</div>
|
||||||
<div class="question-text">
|
<div class="question-text">
|
||||||
{{ question.question }}
|
{{ question.question }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user