mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 03:39:11 +00:00
Quiz: Quiz now displays correctly on the portal
Co-authored-by: Chinmay Pai <chinmaydpai@gmail.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "format:{question}",
|
"autoname": "format:QUESTION-{#####}",
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
"creation": "2018-10-01 15:58:00.696815",
|
"creation": "2018-10-01 15:58:00.696815",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-10-15 14:39:40.576374",
|
"modified": "2018-10-17 12:08:05.649254",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Education",
|
"module": "Education",
|
||||||
"name": "Question",
|
"name": "Question",
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ class OverlapError(frappe.ValidationError): pass
|
|||||||
|
|
||||||
def validate_overlap_for(doc, doctype, fieldname, value=None):
|
def validate_overlap_for(doc, doctype, fieldname, value=None):
|
||||||
"""Checks overlap for specified field.
|
"""Checks overlap for specified field.
|
||||||
|
|
||||||
:param fieldname: Checks Overlap for this field
|
:param fieldname: Checks Overlap for this field
|
||||||
"""
|
"""
|
||||||
|
|
||||||
existing = get_overlap_for(doc, doctype, fieldname, value)
|
existing = get_overlap_for(doc, doctype, fieldname, value)
|
||||||
if existing:
|
if existing:
|
||||||
frappe.throw(_("This {0} conflicts with {1} for {2} {3}").format(doc.doctype, existing.name,
|
frappe.throw(_("This {0} conflicts with {1} for {2} {3}").format(doc.doctype, existing.name,
|
||||||
doc.meta.get_label(fieldname) if not value else fieldname , value or doc.get(fieldname)), OverlapError)
|
doc.meta.get_label(fieldname) if not value else fieldname , value or doc.get(fieldname)), OverlapError)
|
||||||
|
|
||||||
def get_overlap_for(doc, doctype, fieldname, value=None):
|
def get_overlap_for(doc, doctype, fieldname, value=None):
|
||||||
"""Returns overlaping document for specified field.
|
"""Returns overlaping document for specified field.
|
||||||
|
|
||||||
:param fieldname: Checks Overlap for this field
|
:param fieldname: Checks Overlap for this field
|
||||||
"""
|
"""
|
||||||
|
|
||||||
existing = frappe.db.sql("""select name, from_time, to_time from `tab{0}`
|
existing = frappe.db.sql("""select name, from_time, to_time from `tab{0}`
|
||||||
@@ -42,7 +42,7 @@ def get_overlap_for(doc, doctype, fieldname, value=None):
|
|||||||
}, as_dict=True)
|
}, as_dict=True)
|
||||||
|
|
||||||
return existing[0] if existing else None
|
return existing[0] if existing else None
|
||||||
|
|
||||||
def validate_duplicate_student(students):
|
def validate_duplicate_student(students):
|
||||||
unique_students= []
|
unique_students= []
|
||||||
for stud in students:
|
for stud in students:
|
||||||
@@ -54,7 +54,7 @@ def validate_duplicate_student(students):
|
|||||||
|
|
||||||
def get_student_name(email=None):
|
def get_student_name(email=None):
|
||||||
"""Returns student user name, example EDU-STU-2018-00001 (Based on the naming series).
|
"""Returns student user name, example EDU-STU-2018-00001 (Based on the naming series).
|
||||||
|
|
||||||
:param user: a user email address
|
:param user: a user email address
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@@ -65,7 +65,7 @@ def get_student_name(email=None):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def evaluate_quiz(quiz_response, **kwargs):
|
def evaluate_quiz(quiz_response, **kwargs):
|
||||||
"""LMS Function: Evaluates a simple multiple choice quiz. It recieves arguments from `www/lms/course.js` as dictionary using FormData[1].
|
"""LMS Function: Evaluates a simple multiple choice quiz. It recieves arguments from `www/lms/course.js` as dictionary using FormData[1].
|
||||||
|
|
||||||
|
|
||||||
:param quiz_response: contains user selected choices for a quiz in the form of a string formatted as a dictionary. The function uses `json.loads()` to convert it to a python dictionary.
|
:param quiz_response: contains user selected choices for a quiz in the form of a string formatted as a dictionary. The function uses `json.loads()` to convert it to a python dictionary.
|
||||||
[1]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
|
[1]: https://developer.mozilla.org/en-US/docs/Web/API/FormData
|
||||||
@@ -192,7 +192,7 @@ def get_course_enrollment(course, email):
|
|||||||
|
|
||||||
def get_student_id(email):
|
def get_student_id(email):
|
||||||
"""Returns Student ID, example EDU-STU-2018-00001 from email address
|
"""Returns Student ID, example EDU-STU-2018-00001 from email address
|
||||||
|
|
||||||
:params email: email address of the student"""
|
:params email: email address of the student"""
|
||||||
try:
|
try:
|
||||||
return frappe.get_list('Student', filters={'student_email_id': email})[0].name
|
return frappe.get_list('Student', filters={'student_email_id': email})[0].name
|
||||||
@@ -200,21 +200,32 @@ def get_student_id(email):
|
|||||||
frappe.throw("Student Account with email:{0} does not exist".format(email))
|
frappe.throw("Student Account with email:{0} does not exist".format(email))
|
||||||
|
|
||||||
def get_quiz(content):
|
def get_quiz(content):
|
||||||
|
try:
|
||||||
|
quiz_doc = frappe.get_doc("Content", content)
|
||||||
|
if quiz_doc.content_type != "Quiz":
|
||||||
|
frappe.throw("<b>{0}</b> is not a Quiz".format(content))
|
||||||
|
quiz = [frappe.get_doc("Question", item.question_link) for item in quiz_doc.questions]
|
||||||
|
return quiz
|
||||||
|
except frappe.DoesNotExistError:
|
||||||
|
frappe.throw("The quiz \"{0}\" does not exist".format(content))
|
||||||
|
|
||||||
|
def get_quiz_as_dict(content):
|
||||||
"""Helper Function to get questions for a quiz
|
"""Helper Function to get questions for a quiz
|
||||||
|
|
||||||
:params content: name of a Content doctype with content_type quiz"""
|
:params content: name of a Content doctype with content_type quiz"""
|
||||||
try:
|
try:
|
||||||
quiz_doc = frappe.get_doc("Content", content)
|
quiz_doc = frappe.get_doc("Content", content)
|
||||||
if quiz_doc.content_type != "Quiz":
|
if quiz_doc.content_type != "Quiz":
|
||||||
frappe.throw("<b>{0}</b> is not a Quiz".format(content))
|
frappe.throw("<b>{0}</b> is not a Quiz".format(content))
|
||||||
|
|
||||||
import json
|
import json
|
||||||
quiz = [frappe.get_doc("Question", item.question_link) for item in quiz_doc.questions]
|
quiz = [frappe.get_doc("Question", item.question_link) for item in quiz_doc.questions]
|
||||||
data = []
|
data = []
|
||||||
for question in quiz:
|
for question in quiz:
|
||||||
d = {}
|
d = {}
|
||||||
d['Question'] = question.question
|
d['id'] = question.name
|
||||||
d['Options'] = [item.option for item in quiz[0].options]
|
d['question'] = question.question
|
||||||
|
d['options'] = [item.option for item in quiz[0].options]
|
||||||
data.append(d)
|
data.append(d)
|
||||||
return data
|
return data
|
||||||
except frappe.DoesNotExistError:
|
except frappe.DoesNotExistError:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="content-holder" data-type="{{current_content.content_type}}" data-content="{{ current_content.name }}" data-course="{{ current_course.name }}" data-program="{{ current_program }}">
|
<div id="content-holder" data-type="{{current_content.content_type}}" data-content="{{ current_content.name }}" data-course="{{ current_course.name }}" data-program="{{ current_program }}">
|
||||||
{% with current_content = current_content, next_content = next_content, course_name = current_course.name, program=current_program%}
|
{% with quiz = quiz, current_content = current_content, next_content = next_content, course_name = course_name, program=current_program%}
|
||||||
{% include "www/lms/templates/includes/" + current_content.content_type.lower() + ".html" %}
|
{% include "www/lms/templates/includes/" + current_content.content_type.lower() + ".html" %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
padding-top: 3rem !important;
|
padding-top: 3rem !important;
|
||||||
padding-bottom: 1rem !important;
|
padding-bottom: 1rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-description-section {
|
.video-description-section {
|
||||||
padding-top: 0em !important;
|
padding-top: 0em !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import erpnext.education.utils as utils
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
if frappe.form_dict['course']:
|
if frappe.form_dict['course']:
|
||||||
context.current_course = frappe.get_doc("Course", frappe.form_dict["course"])
|
|
||||||
context.current_content = frappe.get_doc("Content", frappe.form_dict["content"])
|
context.current_content = frappe.get_doc("Content", frappe.form_dict["content"])
|
||||||
|
context.course_name = frappe.form_dict["course"]
|
||||||
|
context.current_course = utils.get_contents_in_course(context.course_name)
|
||||||
context.current_program = frappe.form_dict["program"]
|
context.current_program = frappe.form_dict["program"]
|
||||||
context.next_content = get_next_content(context)
|
context.next_content = get_next_content(context)
|
||||||
|
if context.current_content.content_type == "Quiz":
|
||||||
|
context.questions = utils.get_quiz_as_dict(context.current_content.name)
|
||||||
|
|
||||||
|
|
||||||
def get_next_content(context):
|
def get_next_content(context):
|
||||||
if context.current_course:
|
if context.current_course:
|
||||||
course_data = [content_item.content for content_item in context.current_course.course_content]
|
course_data = [content.name for content in context.current_course]
|
||||||
try:
|
try:
|
||||||
return course_data[course_data.index(context.current_content.name) + 1]
|
return course_data[course_data.index(context.current_content.name) + 1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return None
|
return None
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
{% macro quiz(loop_index, question_id, question, options) %}
|
{% macro quiz(loop_index, question) %}
|
||||||
<div class="question mt-4" id="question" data-question="{{ question_id }}">
|
<div class="question mt-4" id="question['question']" data-question="{{ question['id'] }}">
|
||||||
<h5>{{ loop_index }}{{ question }}</h5>
|
<h5>{{ loop_index }}{{ question['question'] }}</h5>
|
||||||
<div class="options ml-2">
|
<div class="options ml-2">
|
||||||
<div class="form-check pb-1 hidden">
|
<div class="form-check pb-1 hidden">
|
||||||
<input class="form-check-input" type="radio" name="{{ question_id }}" value="0" checked>
|
<input class="form-check-input" type="radio" name="{{ question['id'] }}" value="0" checked>
|
||||||
</div>
|
</div>
|
||||||
{% for option in options %}
|
{% for option in question['options'] %}
|
||||||
<div class="form-check pb-1">
|
<div class="form-check pb-1">
|
||||||
<input class="form-check-input" type="radio" name="{{ question_id }}" id="{{loop_index}}-{{ option }}" value="{{ loop.index|str }}">
|
<input class="form-check-input" type="radio" name="{{ question['id'] }}" id="{{loop_index}}-{{ option }}" value="{{ option }}">
|
||||||
<label class="form-check-label" for="{{loop_index}}-{{ option }}">
|
<label class="form-check-label" for="{{loop_index}}-{{ option }}">
|
||||||
{{ option }}
|
{{ option }}
|
||||||
</label>
|
</label>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
<section class="quiz-section">
|
<section class="quiz-section">
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<div class="mt-3 row">
|
<div class="mt-3 row">
|
||||||
@@ -28,9 +27,8 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<form id="quiz" name="{{ current_content.name }}">
|
<form id="quiz" name="{{ current_content.name }}">
|
||||||
<div id="quiz-body">
|
<div id="quiz-body">
|
||||||
{% for quiz_item in current_content.quiz %}
|
{% for q in questions %}
|
||||||
{{ quiz(loop.index|str +". ", quiz_item.name, quiz_item.question, [ quiz_item.option_1, quiz_item.option_2,
|
{{ quiz(loop.index|str +". ", q) }}
|
||||||
quiz_item.option_3, quiz_item.option_4]) }}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
@@ -43,12 +41,12 @@
|
|||||||
<h3>Your Score: <span id="result"></span></h3>
|
<h3>Your Score: <span id="result"></span></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 text-right">
|
<div class="col-md-4 text-right">
|
||||||
<a class='btn btn-outline-secondary' href="#">Previous</a>
|
<a class='btn btn-outline-secondary' href="#">Previous</a>
|
||||||
{% if next_content != None %}
|
{% if next_content != None %}
|
||||||
<a class='btn btn-primary' href="/lms/course?program={{ program }}&course={{ course_name }}&content={{ next_content }}">Next</a>
|
<a class='btn btn-primary' href="/lms/course?program={{ program }}&course={{ course_name }}&content={{ next_content }}">Next</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class='btn btn-primary' href="/lms/program?program={{ program }}">Finish Course</a>
|
<a class='btn btn-primary' href="/lms/program?program={{ program }}">Finish Course</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user