@@ -16,9 +16,9 @@ cd frappe-bench
|
|||||||
|
|
||||||
# Use containers instead of localhost
|
# Use containers instead of localhost
|
||||||
bench set-mariadb-host mariadb
|
bench set-mariadb-host mariadb
|
||||||
bench set-redis-cache-host redis:6379
|
bench set-redis-cache-host redis://redis:6379
|
||||||
bench set-redis-queue-host redis:6379
|
bench set-redis-queue-host redis://redis:6379
|
||||||
bench set-redis-socketio-host redis:6379
|
bench set-redis-socketio-host redis://redis:6379
|
||||||
|
|
||||||
# Remove redis, watch from Procfile
|
# Remove redis, watch from Procfile
|
||||||
sed -i '/redis/d' ./Procfile
|
sed -i '/redis/d' ./Procfile
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ function submitEvaluation(close) {
|
|||||||
unavailabilityMessage = false
|
unavailabilityMessage = false
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.warn(__('Evaluator is unavailable'))
|
toast.warning(__('Evaluator is unavailable'))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ const getAnswers = () => {
|
|||||||
const checkAnswer = () => {
|
const checkAnswer = () => {
|
||||||
let answers = getAnswers()
|
let answers = getAnswers()
|
||||||
if (!answers.length) {
|
if (!answers.length) {
|
||||||
toast.warn(__('Please select an option'))
|
toast.warning(__('Please select an option'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
<header
|
<header
|
||||||
class="sticky top-0 z-10 flex items-center justify-between border-b bg-surface-white px-3 py-2.5 sm:px-5"
|
class="sticky top-0 z-10 flex items-center justify-between border-b bg-surface-white px-3 py-2.5 sm:px-5"
|
||||||
>
|
>
|
||||||
<Breadcrumbs v-if="submisisonDetails.doc" :items="breadcrumbs" />
|
<Breadcrumbs v-if="submissionDetails.doc" :items="breadcrumbs" />
|
||||||
<div class="space-x-2">
|
<div class="space-x-2">
|
||||||
<Badge
|
<Badge
|
||||||
v-if="submisisonDetails.isDirty"
|
v-if="submissionDetails.isDirty"
|
||||||
:label="__('Not Saved')"
|
:label="__('Not Saved')"
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
theme="orange"
|
theme="orange"
|
||||||
@@ -15,19 +15,19 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div v-if="submisisonDetails.doc" class="w-1/2 mx-auto py-5 space-y-5">
|
<div v-if="submissionDetails.doc" class="w-2/3 border-x mx-auto py-5">
|
||||||
<div class="text-xl font-semibold text-ink-gray-9">
|
<div class="text-xl px-10 font-semibold text-ink-gray-9 mb-5">
|
||||||
{{ submisisonDetails.doc.member_name }}
|
{{ submissionDetails.doc.member_name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4 border p-5 rounded-md">
|
<div class="space-y-4 border-b pb-5 px-10">
|
||||||
<div class="grid grid-cols-2 gap-5">
|
<div class="grid grid-cols-2 gap-5">
|
||||||
<FormControl
|
<FormControl
|
||||||
v-model="submisisonDetails.doc.quiz_title"
|
v-model="submissionDetails.doc.quiz_title"
|
||||||
:label="__('Quiz')"
|
:label="__('Quiz')"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
<FormControl
|
<FormControl
|
||||||
v-model="submisisonDetails.doc.member_name"
|
v-model="submissionDetails.doc.member_name"
|
||||||
:label="__('Member')"
|
:label="__('Member')"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
@@ -35,39 +35,39 @@
|
|||||||
|
|
||||||
<div class="grid grid-cols-2 gap-5">
|
<div class="grid grid-cols-2 gap-5">
|
||||||
<FormControl
|
<FormControl
|
||||||
v-model="submisisonDetails.doc.score"
|
v-model="submissionDetails.doc.score"
|
||||||
:label="__('Score')"
|
:label="__('Score')"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
<FormControl
|
<FormControl
|
||||||
v-model="submisisonDetails.doc.percentage"
|
v-model="submissionDetails.doc.percentage"
|
||||||
:label="__('Percentage')"
|
:label="__('Percentage')"
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="divide-y">
|
||||||
v-for="(row, index) in submisisonDetails.doc.result"
|
<div
|
||||||
class="border p-5 rounded-md space-y-4"
|
v-for="(row, index) in submissionDetails.doc.result"
|
||||||
>
|
class="py-5 px-10 space-y-4"
|
||||||
<div class="flex items-start space-x-1 font-semibold text-ink-gray-9">
|
>
|
||||||
<!-- <span>
|
<div class="text-ink-gray-9">
|
||||||
{{ index + 1 }}.
|
<span class="font-semibold"> {{ __('Question') }}: </span>
|
||||||
</span> -->
|
<span class="leading-5" v-html="row.question"> </span>
|
||||||
<span class="leading-5" v-html="row.question"> </span>
|
</div>
|
||||||
</div>
|
<div class="">
|
||||||
<div class="leading-5 text-ink-gray-7 space-x-1">
|
<span class="font-semibold"> {{ __('Answer') }} </span>
|
||||||
<span> {{ __('Answer') }}: </span>
|
<span class="leading-5" v-html="row.answer"></span>
|
||||||
<span v-html="row.answer"></span>
|
</div>
|
||||||
</div>
|
<div class="grid grid-cols-2 gap-5">
|
||||||
<div class="grid grid-cols-2 gap-5">
|
<FormControl v-model="row.marks" :label="__('Marks')" />
|
||||||
<FormControl v-model="row.marks" :label="__('Marks')" />
|
<FormControl
|
||||||
<FormControl
|
v-model="row.marks_out_of"
|
||||||
v-model="row.marks_out_of"
|
:label="__('Marks out of')"
|
||||||
:label="__('Marks out of')"
|
:disabled="true"
|
||||||
:disabled="true"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,7 +119,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const submisisonDetails = createDocumentResource({
|
const submissionDetails = createDocumentResource({
|
||||||
doctype: 'LMS Quiz Submission',
|
doctype: 'LMS Quiz Submission',
|
||||||
name: props.submission,
|
name: props.submission,
|
||||||
auto: true,
|
auto: true,
|
||||||
@@ -132,18 +132,18 @@ const breadcrumbs = computed(() => {
|
|||||||
route: {
|
route: {
|
||||||
name: 'QuizSubmissionList',
|
name: 'QuizSubmissionList',
|
||||||
params: {
|
params: {
|
||||||
quizID: submisisonDetails.doc.quiz,
|
quizID: submissionDetails.doc.quiz,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: submisisonDetails.doc.quiz_title,
|
label: submissionDetails.doc.quiz_title,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const saveSubmission = () => {
|
const saveSubmission = () => {
|
||||||
submisisonDetails.save.submit(
|
submissionDetails.save.submit(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
onError(err) {
|
onError(err) {
|
||||||
@@ -155,7 +155,7 @@ const saveSubmission = () => {
|
|||||||
|
|
||||||
usePageMeta(() => {
|
usePageMeta(() => {
|
||||||
return {
|
return {
|
||||||
title: `${submisisonDetails.doc.quiz_title}`,
|
title: `${submissionDetails.doc?.quiz_title}`,
|
||||||
icon: brand.favicon,
|
icon: brand.favicon,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -96,9 +96,7 @@ def set_total_marks(questions):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def quiz_summary(quiz, results):
|
def quiz_summary(quiz, results):
|
||||||
score = 0
|
|
||||||
results = results and json.loads(results)
|
results = results and json.loads(results)
|
||||||
is_open_ended = False
|
|
||||||
percentage = 0
|
percentage = 0
|
||||||
|
|
||||||
quiz_details = frappe.db.get_value(
|
quiz_details = frappe.db.get_value(
|
||||||
@@ -108,7 +106,32 @@ def quiz_summary(quiz, results):
|
|||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data = process_results(results, quiz)
|
||||||
|
results = data["results"]
|
||||||
|
score = data["score"]
|
||||||
|
is_open_ended = data["is_open_ended"]
|
||||||
|
|
||||||
score_out_of = quiz_details.total_marks
|
score_out_of = quiz_details.total_marks
|
||||||
|
percentage = (score / score_out_of) * 100 if score_out_of else 0
|
||||||
|
submission = create_submission(
|
||||||
|
quiz, results, score_out_of, quiz_details.passing_percentage
|
||||||
|
)
|
||||||
|
|
||||||
|
save_progress_after_quiz(quiz_details, percentage)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"score": score,
|
||||||
|
"score_out_of": score_out_of,
|
||||||
|
"submission": submission.name,
|
||||||
|
"pass": percentage == quiz_details.passing_percentage,
|
||||||
|
"percentage": percentage,
|
||||||
|
"is_open_ended": is_open_ended,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def process_results(results, quiz):
|
||||||
|
score = 0
|
||||||
|
is_open_ended = False
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
question_details = frappe.db.get_value(
|
question_details = frappe.db.get_value(
|
||||||
@@ -123,55 +146,28 @@ def quiz_summary(quiz, results):
|
|||||||
result["marks_out_of"] = question_details.marks
|
result["marks_out_of"] = question_details.marks
|
||||||
|
|
||||||
if question_details.type != "Open Ended":
|
if question_details.type != "Open Ended":
|
||||||
correct = result["is_correct"][0]
|
if len(result["is_correct"]) > 0:
|
||||||
for point in result["is_correct"]:
|
correct = result["is_correct"][0]
|
||||||
correct = correct and point
|
for point in result["is_correct"]:
|
||||||
result["is_correct"] = correct
|
correct = correct and point
|
||||||
|
result["is_correct"] = correct
|
||||||
|
else:
|
||||||
|
result["is_correct"] = 0
|
||||||
|
|
||||||
marks = question_details.marks if correct else 0
|
marks = question_details.marks if correct else 0
|
||||||
result["marks"] = marks
|
result["marks"] = marks
|
||||||
score += marks
|
score += marks
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result["is_correct"] = 0
|
|
||||||
is_open_ended = True
|
is_open_ended = True
|
||||||
|
result["is_correct"] = 0
|
||||||
percentage = (score / score_out_of) * 100
|
result["answer"] = re.sub(
|
||||||
result["answer"] = re.sub(
|
r'<img[^>]*src\s*=\s*["\'](?=data:)(.*?)["\']', _save_file, result["answer"]
|
||||||
r'<img[^>]*src\s*=\s*["\'](?=data:)(.*?)["\']', _save_file, result["answer"]
|
)
|
||||||
)
|
|
||||||
|
|
||||||
submission = frappe.new_doc("LMS Quiz Submission")
|
|
||||||
# Score and percentage are calculated by the controller function
|
|
||||||
submission.update(
|
|
||||||
{
|
|
||||||
"doctype": "LMS Quiz Submission",
|
|
||||||
"quiz": quiz,
|
|
||||||
"result": results,
|
|
||||||
"score": 0,
|
|
||||||
"score_out_of": score_out_of,
|
|
||||||
"member": frappe.session.user,
|
|
||||||
"percentage": 0,
|
|
||||||
"passing_percentage": quiz_details.passing_percentage,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
submission.save(ignore_permissions=True)
|
|
||||||
|
|
||||||
if (
|
|
||||||
percentage >= quiz_details.passing_percentage
|
|
||||||
and quiz_details.lesson
|
|
||||||
and quiz_details.course
|
|
||||||
):
|
|
||||||
save_progress(quiz_details.lesson, quiz_details.course)
|
|
||||||
elif not quiz_details.passing_percentage:
|
|
||||||
save_progress(quiz_details.lesson, quiz_details.course)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
"results": results,
|
||||||
"score": score,
|
"score": score,
|
||||||
"score_out_of": score_out_of,
|
|
||||||
"submission": submission.name,
|
|
||||||
"pass": percentage == quiz_details.passing_percentage,
|
|
||||||
"percentage": percentage,
|
|
||||||
"is_open_ended": is_open_ended,
|
"is_open_ended": is_open_ended,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +215,36 @@ def get_corrupted_image_msg():
|
|||||||
return _("Image: Corrupted Data Stream")
|
return _("Image: Corrupted Data Stream")
|
||||||
|
|
||||||
|
|
||||||
|
def create_submission(quiz, results, score_out_of, passing_percentage):
|
||||||
|
submission = frappe.new_doc("LMS Quiz Submission")
|
||||||
|
# Score and percentage are calculated by the controller function
|
||||||
|
submission.update(
|
||||||
|
{
|
||||||
|
"doctype": "LMS Quiz Submission",
|
||||||
|
"quiz": quiz,
|
||||||
|
"result": results,
|
||||||
|
"score": 0,
|
||||||
|
"score_out_of": score_out_of,
|
||||||
|
"member": frappe.session.user,
|
||||||
|
"percentage": 0,
|
||||||
|
"passing_percentage": passing_percentage,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
submission.save(ignore_permissions=True)
|
||||||
|
return submission
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress_after_quiz(quiz_details, percentage):
|
||||||
|
if (
|
||||||
|
percentage >= quiz_details.passing_percentage
|
||||||
|
and quiz_details.lesson
|
||||||
|
and quiz_details.course
|
||||||
|
):
|
||||||
|
save_progress(quiz_details.lesson, quiz_details.course)
|
||||||
|
elif not quiz_details.passing_percentage:
|
||||||
|
save_progress(quiz_details.lesson, quiz_details.course)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_question_details(question):
|
def get_question_details(question):
|
||||||
if frappe.db.exists("LMS Quiz Question", question):
|
if frappe.db.exists("LMS Quiz Question", question):
|
||||||
|
|||||||
Reference in New Issue
Block a user