diff --git a/frontend/src/components/Quiz.vue b/frontend/src/components/Quiz.vue index b925cb7f..165e666f 100644 --- a/frontend/src/components/Quiz.vue +++ b/frontend/src/components/Quiz.vue @@ -207,7 +207,7 @@
@@ -282,7 +290,7 @@ import { FormControl, } from 'frappe-ui' import { ref, watch, reactive, inject, computed } from 'vue' -import { createToast } from '@/utils/' +import { createToast, showToast } from '@/utils/' import { CheckCircle, XCircle, MinusCircle } from 'lucide-vue-next' import { timeAgo } from '@/utils' import { useRouter } from 'vue-router' @@ -536,7 +544,7 @@ const addToLocalStorage = () => { localStorage.setItem(quiz.data.title, JSON.stringify(quizData)) } -const nextQuetion = () => { +const nextQuestion = () => { if (!quiz.data.show_answers && questionDetails.data?.type != 'Open Ended') { checkAnswer() } else { @@ -574,6 +582,16 @@ const createSubmission = () => { if (quiz.data && quiz.data.max_attempts) attempts.reload() if (quiz.data.duration) clearInterval(timerInterval) }, + onError(err) { + const errorTitle = err?.message || '' + if (errorTitle.includes('MaximumAttemptsExceededError')) { + const errorMessage = err.messages?.[0] || err + showToast(__('Error'), __(errorMessage), 'x') + setTimeout(() => { + window.location.reload() + }, 3000) + } + }, } ) } diff --git a/frontend/src/pages/QuizForm.vue b/frontend/src/pages/QuizForm.vue index b8f66df6..c143d2aa 100644 --- a/frontend/src/pages/QuizForm.vue +++ b/frontend/src/pages/QuizForm.vue @@ -55,7 +55,7 @@ { const { userResource } = usersStore() - const { isLoggedIn } = sessionStore() + let { isLoggedIn } = sessionStore() const { allowGuestAccess } = useSettings() try { diff --git a/frontend/src/utils/quiz.js b/frontend/src/utils/quiz.js index e391bc30..4781ba70 100644 --- a/frontend/src/utils/quiz.js +++ b/frontend/src/utils/quiz.js @@ -4,6 +4,7 @@ import { createApp, h } from 'vue' import { usersStore } from '../stores/user' import translationPlugin from '../translation' import { CircleHelp } from 'lucide-vue-next' +import router from '@/router' export class Quiz { constructor({ data, api, readOnly }) { @@ -46,6 +47,7 @@ export class Quiz { quiz: quiz, }) app.use(translationPlugin) + app.use(router) const { userResource } = usersStore() app.provide('$user', userResource) app.mount(this.wrapper) diff --git a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py index 0618eb2b..b643ea54 100644 --- a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py +++ b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py @@ -10,12 +10,29 @@ from frappe.desk.doctype.notification_log.notification_log import make_notificat class LMSQuizSubmission(Document): def validate(self): + self.validate_if_max_attempts_exceeded() self.validate_marks() self.set_percentage() def on_update(self): self.notify_member() + def validate_if_max_attempts_exceeded(self): + max_attempts = frappe.db.get_value("LMS Quiz", self.quiz, ["max_attempts"]) + if max_attempts == 0: + return + + current_user_submission_count = frappe.db.count( + self.doctype, filters={"quiz": self.quiz, "member": frappe.session.user} + ) + if current_user_submission_count >= max_attempts: + frappe.throw( + _("You have exceeded the maximum number of attempts ({0}) for this quiz").format( + max_attempts + ), + MaximumAttemptsExceededError, + ) + def validate_marks(self): self.score = 0 for row in self.result: @@ -52,3 +69,7 @@ class LMSQuizSubmission(Document): ) make_notification_logs(notification, [self.member]) + + +class MaximumAttemptsExceededError(frappe.DuplicateEntryError): + pass diff --git a/lms/locale/ar.po b/lms/locale/ar.po index 2c4cc89c..8170ae3a 100644 --- a/lms/locale/ar.po +++ b/lms/locale/ar.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/bs.po b/lms/locale/bs.po index edbdc727..8e1b48f5 100644 --- a/lms/locale/bs.po +++ b/lms/locale/bs.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/de.po b/lms/locale/de.po index 91c9842f..30bf52a9 100644 --- a/lms/locale/de.po +++ b/lms/locale/de.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "Max. Versuche" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/eo.po b/lms/locale/eo.po index ed735b93..b7f51f3a 100644 --- a/lms/locale/eo.po +++ b/lms/locale/eo.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "crwdns150150:0crwdne150150:0" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "crwdns150152:0crwdne150152:0" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/es.po b/lms/locale/es.po index 47c52864..990f9ca9 100644 --- a/lms/locale/es.po +++ b/lms/locale/es.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "Intentos máximos" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "Intentos máximos" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/fa.po b/lms/locale/fa.po index 47a823bf..a53d970d 100644 --- a/lms/locale/fa.po +++ b/lms/locale/fa.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/fr.po b/lms/locale/fr.po index 5261d43a..fb35ea76 100644 --- a/lms/locale/fr.po +++ b/lms/locale/fr.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/hu.po b/lms/locale/hu.po index d3438f3d..95ac9a35 100644 --- a/lms/locale/hu.po +++ b/lms/locale/hu.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/main.pot b/lms/locale/main.pot index 675185dc..4eccc5d0 100644 --- a/lms/locale/main.pot +++ b/lms/locale/main.pot @@ -3042,7 +3042,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/pl.po b/lms/locale/pl.po index c82d6ab1..765a1678 100644 --- a/lms/locale/pl.po +++ b/lms/locale/pl.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/ru.po b/lms/locale/ru.po index 41d0d1f5..915fcb8a 100644 --- a/lms/locale/ru.po +++ b/lms/locale/ru.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "Максимум попыток" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/sv.po b/lms/locale/sv.po index 630da1f1..102d136a 100644 --- a/lms/locale/sv.po +++ b/lms/locale/sv.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "Maximalt antal försök" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "Maximalt antal försök" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/tr.po b/lms/locale/tr.po index ccad300a..7a2d33b1 100644 --- a/lms/locale/tr.po +++ b/lms/locale/tr.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "Maksimum Deneme" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch' diff --git a/lms/locale/zh.po b/lms/locale/zh.po index 766432a0..23d4f542 100644 --- a/lms/locale/zh.po +++ b/lms/locale/zh.po @@ -3031,7 +3031,7 @@ msgid "Max Attempts" msgstr "" #: frontend/src/pages/QuizForm.vue:58 -msgid "Maximun Attempts" +msgid "Maximum Attempts" msgstr "" #. Label of the medium (Select) field in DocType 'LMS Batch'