Skip to content

Commit e6599a8

Browse files
authored
Merge pull request #2383 from raizasafeel/fix/security
fix(quiz): exam submissions and scope check_answer
2 parents 12fa7ac + 538edbb commit e6599a8

2 files changed

Lines changed: 21 additions & 6 deletions

File tree

frontend/src/components/Quiz.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ const handlePageHide = () => {
512512
if (activeQuestion.value > 0 && !quizSubmission.data) {
513513
const params = new URLSearchParams({
514514
quiz: quiz.data.name,
515-
results: localStorage.getItem(quiz.data.title),
515+
results: localStorage.getItem(quiz.data.title) || '[]',
516516
})
517517
518518
navigator.sendBeacon(
@@ -648,7 +648,7 @@ const quizSubmission = createResource({
648648
makeParams(values) {
649649
return {
650650
quiz: quiz.data.name,
651-
results: localStorage.getItem(quiz.data.title),
651+
results: localStorage.getItem(quiz.data.title) || '[]',
652652
}
653653
},
654654
})
@@ -767,6 +767,7 @@ const checkAnswer = () => {
767767
createResource({
768768
url: 'lms.lms.doctype.lms_quiz.lms_quiz.check_answer',
769769
params: {
770+
quiz: quiz.data.name,
770771
question: currentQuestion.value,
771772
question_type: questionDetails.data.type,
772773
answers: JSON.stringify(answers),
@@ -832,7 +833,9 @@ const resetQuestion = () => {
832833
833834
const submitQuiz = () => {
834835
if (!quiz.data.show_answers) {
835-
if (questionDetails.data.type == 'Open Ended') addToLocalStorage()
836+
if (questionDetails.data.type == 'Open Ended' || getAnswers().length) {
837+
addToLocalStorage()
838+
}
836839
setTimeout(() => {
837840
createSubmission()
838841
}, 500)

lms/lms/doctype/lms_quiz/lms_quiz.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ def set_total_marks(questions: list) -> int:
101101

102102

103103
@frappe.whitelist()
104-
def submit_quiz(quiz: str, results: str):
105-
results = results and json.loads(results)
104+
def submit_quiz(quiz: str, results: str | None = None):
105+
results = json.loads(results) if results else []
106106
percentage = 0
107107

108108
quiz_details = frappe.db.get_value(
@@ -275,7 +275,19 @@ def save_progress_after_quiz(quiz_details: dict, percentage: float):
275275

276276

277277
@frappe.whitelist()
278-
def check_answer(question: str, question_type: str, answers: str):
278+
def check_answer(quiz: str, question: str, question_type: str, answers: str):
279+
ADMIN_ROLES = ("System Manager", "Moderator", "Course Creator", "Batch Evaluator")
280+
is_admin = any(role in ADMIN_ROLES for role in frappe.get_roles())
281+
282+
if not frappe.db.exists("LMS Quiz Question", {"parent": quiz, "question": question}):
283+
frappe.throw(_("Question not found in this quiz."), frappe.PermissionError)
284+
285+
if not is_admin and not frappe.db.get_value("LMS Quiz", quiz, "show_answers"):
286+
frappe.throw(
287+
_("Live answer checking is not enabled for this quiz."),
288+
frappe.PermissionError,
289+
)
290+
279291
answers = answers and json.loads(answers)
280292
if question_type == "Choices":
281293
return check_choice_answers(question, answers)

0 commit comments

Comments
 (0)