Merge branch 'main' of https://github.com/frappe/lms into lms-frappe-ui
This commit is contained in:
@@ -97,7 +97,7 @@ override_doctype_class = {
|
|||||||
# Hook on document methods and events
|
# Hook on document methods and events
|
||||||
|
|
||||||
doc_events = {
|
doc_events = {
|
||||||
"Discussion Reply": {"after_insert": "lms.lms.utils.create_notification_log"},
|
"Discussion Reply": {"after_insert": "lms.lms.utils.handle_notifications"},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Scheduled Tasks
|
# Scheduled Tasks
|
||||||
@@ -118,9 +118,9 @@ fixtures = ["Custom Field", "Function", "Industry"]
|
|||||||
# Overriding Methods
|
# Overriding Methods
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
#
|
#
|
||||||
# override_whitelisted_methods = {
|
override_whitelisted_methods = {
|
||||||
# "frappe.desk.doctype.event.event.get_events": "lms.event.get_events"
|
# "frappe.desk.search.get_names_for_mentions": "lms.lms.utils.get_names_for_mentions",
|
||||||
# }
|
}
|
||||||
#
|
#
|
||||||
# each overriding function accepts a `data` argument;
|
# each overriding function accepts a `data` argument;
|
||||||
# generated from the base implementation of the doctype dashboard,
|
# generated from the base implementation of the doctype dashboard,
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ frappe.ui.form.on("LMS Batch", {
|
|||||||
timetable_template: function (frm) {
|
timetable_template: function (frm) {
|
||||||
set_timetable(frm);
|
set_timetable(frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
refresh: (frm) => {
|
||||||
|
frm.add_web_link(`/batches/details/${frm.doc.name}`, "See on website");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const set_timetable = (frm) => {
|
const set_timetable = (frm) => {
|
||||||
|
|||||||
@@ -120,12 +120,14 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "start_time",
|
"fieldname": "start_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "Start Time"
|
"label": "Start Time",
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "end_time",
|
"fieldname": "end_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"label": "End Time"
|
"label": "End Time",
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "assessment_tab",
|
"fieldname": "assessment_tab",
|
||||||
@@ -281,7 +283,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-10-12 12:53:37.351989",
|
"modified": "2023-11-17 10:41:00.340418",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Batch",
|
"name": "LMS Batch",
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ class LMSBatch(Document):
|
|||||||
|
|
||||||
def send_confirmation_mail(self):
|
def send_confirmation_mail(self):
|
||||||
for student in self.students:
|
for student in self.students:
|
||||||
|
|
||||||
if not student.confirmation_email_sent:
|
if not student.confirmation_email_sent:
|
||||||
self.send_mail(student)
|
self.send_mail(student)
|
||||||
student.confirmation_email_sent = 1
|
student.confirmation_email_sent = 1
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
// Copyright (c) 2023, Frappe and contributors
|
// Copyright (c) 2023, Frappe and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
// frappe.ui.form.on("LMS Payment", {
|
frappe.ui.form.on("LMS Payment", {
|
||||||
// refresh(frm) {
|
onload(frm) {
|
||||||
|
frm.set_query("member", function (doc) {
|
||||||
// },
|
return {
|
||||||
// });
|
filters: {
|
||||||
|
ignore_user_type: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ def quiz_summary(quiz, results):
|
|||||||
|
|
||||||
question_details = frappe.db.get_value(
|
question_details = frappe.db.get_value(
|
||||||
"LMS Quiz Question",
|
"LMS Quiz Question",
|
||||||
{"parent": quiz, "idx": result["question_index"] + 1},
|
{"parent": quiz, "idx": result["question_index"]},
|
||||||
["question", "marks"],
|
["question", "marks"],
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
@@ -110,6 +110,7 @@ def quiz_summary(quiz, results):
|
|||||||
"score_out_of": score_out_of,
|
"score_out_of": score_out_of,
|
||||||
"submission": submission.name,
|
"submission": submission.name,
|
||||||
"pass": percentage == quiz_details.passing_percentage,
|
"pass": percentage == quiz_details.passing_percentage,
|
||||||
|
"percentage": percentage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,14 @@ import razorpay
|
|||||||
import requests
|
import requests
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result
|
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result
|
||||||
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
|
from frappe.desk.doctype.notification_log.notification_log import (
|
||||||
|
make_notification_logs,
|
||||||
|
enqueue_create_notification,
|
||||||
|
get_title,
|
||||||
|
)
|
||||||
|
from frappe.utils import get_fullname
|
||||||
|
from frappe.desk.search import get_user_groups
|
||||||
|
from frappe.desk.notifications import extract_mentions
|
||||||
from frappe.utils import (
|
from frappe.utils import (
|
||||||
add_months,
|
add_months,
|
||||||
cint,
|
cint,
|
||||||
@@ -548,6 +555,9 @@ def can_create_courses(course, member=None):
|
|||||||
if portal_course_creation == "Anyone" and member in instructors:
|
if portal_course_creation == "Anyone" and member in instructors:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if not course and has_course_instructor_role(member):
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -603,17 +613,20 @@ def validate_image(path):
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def create_notification_log(doc, method):
|
def handle_notifications(doc, method):
|
||||||
topic = frappe.db.get_value(
|
topic = frappe.db.get_value(
|
||||||
"Discussion Topic",
|
"Discussion Topic",
|
||||||
doc.topic,
|
doc.topic,
|
||||||
["reference_doctype", "reference_docname", "owner", "title"],
|
["reference_doctype", "reference_docname", "owner", "title"],
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
if topic.reference_doctype not in ["Course Lesson", "LMS Batch"]:
|
||||||
if topic.reference_doctype != "Course Lesson":
|
|
||||||
return
|
return
|
||||||
|
create_notification_log(doc, topic)
|
||||||
|
notify_mentions(doc, topic)
|
||||||
|
|
||||||
|
|
||||||
|
def create_notification_log(doc, topic):
|
||||||
course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course")
|
course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course")
|
||||||
instructors = frappe.db.get_all(
|
instructors = frappe.db.get_all(
|
||||||
"Course Instructor", {"parent": course}, pluck="instructor"
|
"Course Instructor", {"parent": course}, pluck="instructor"
|
||||||
@@ -640,6 +653,47 @@ def create_notification_log(doc, method):
|
|||||||
make_notification_logs(notification, users)
|
make_notification_logs(notification, users)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_mentions(doc, topic):
|
||||||
|
mentions = extract_mentions(doc.reply)
|
||||||
|
if not mentions:
|
||||||
|
return
|
||||||
|
|
||||||
|
sender_fullname = get_fullname(doc.owner)
|
||||||
|
recipients = [
|
||||||
|
frappe.db.get_value(
|
||||||
|
"User",
|
||||||
|
{"enabled": 1, "name": name},
|
||||||
|
"email",
|
||||||
|
)
|
||||||
|
for name in mentions
|
||||||
|
]
|
||||||
|
subject = _("{0} mentioned you in a comment").format(sender_fullname)
|
||||||
|
template = "mention_template"
|
||||||
|
|
||||||
|
if topic.reference_doctype == "LMS Batch":
|
||||||
|
link = f"/batches/{topic.reference_docname}#discussions"
|
||||||
|
if topic.reference_doctype == "Course Lesson":
|
||||||
|
course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course")
|
||||||
|
lesson_index = get_lesson_index(topic.reference_docname)
|
||||||
|
link = get_lesson_url(course, lesson_index)
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"sender": sender_fullname,
|
||||||
|
"content": doc.reply,
|
||||||
|
"link": link,
|
||||||
|
}
|
||||||
|
|
||||||
|
for recipient in recipients:
|
||||||
|
frappe.sendmail(
|
||||||
|
recipients=recipient,
|
||||||
|
subject=subject,
|
||||||
|
template=template,
|
||||||
|
args=args,
|
||||||
|
header=[subject, "green"],
|
||||||
|
retry=3,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_lesson_count(course):
|
def get_lesson_count(course):
|
||||||
lesson_count = 0
|
lesson_count = 0
|
||||||
chapters = frappe.get_all("Chapter Reference", {"parent": course}, ["chapter"])
|
chapters = frappe.get_all("Chapter Reference", {"parent": course}, ["chapter"])
|
||||||
|
|||||||
@@ -308,12 +308,14 @@ const open_batch_dialog = () => {
|
|||||||
label: __("Start Time"),
|
label: __("Start Time"),
|
||||||
fieldname: "start_time",
|
fieldname: "start_time",
|
||||||
default: batch_info && batch_info.start_time,
|
default: batch_info && batch_info.start_time,
|
||||||
|
reqd: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldtype: "Time",
|
fieldtype: "Time",
|
||||||
label: __("End Time"),
|
label: __("End Time"),
|
||||||
fieldname: "end_time",
|
fieldname: "end_time",
|
||||||
default: batch_info && batch_info.end_time,
|
default: batch_info && batch_info.end_time,
|
||||||
|
reqd: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldtype: "Link",
|
fieldtype: "Link",
|
||||||
|
|||||||
11
lms/templates/emails/mention_template.html
Normal file
11
lms/templates/emails/mention_template.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<p>
|
||||||
|
{{ _("{0} mentioned you in a comment in your batch.").format(sender) }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<blockquote>
|
||||||
|
{{ content | markdown }}
|
||||||
|
</blockquote>
|
||||||
|
</p>
|
||||||
|
<div class="more-info">
|
||||||
|
<a href="{{ link }}">{{ _("Check Discussion") }}</a>
|
||||||
|
</div>
|
||||||
@@ -10,9 +10,6 @@
|
|||||||
<li>
|
<li>
|
||||||
{{ _("You will have to get {0}% correct answers in order to pass the quiz.").format(quiz.passing_percentage) }}
|
{{ _("You will have to get {0}% correct answers in order to pass the quiz.").format(quiz.passing_percentage) }}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
{{ _("Without passing the quiz you won't be able to complete the lesson.") }}
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if quiz.max_attempts %}
|
{% if quiz.max_attempts %}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ frappe.ready(() => {
|
|||||||
this.answer = [];
|
this.answer = [];
|
||||||
this.is_correct = [];
|
this.is_correct = [];
|
||||||
this.show_answers = $("#quiz-title").data("show-answers");
|
this.show_answers = $("#quiz-title").data("show-answers");
|
||||||
|
this.current_index = 0;
|
||||||
localStorage.removeItem($("#quiz-title").data("name"));
|
localStorage.removeItem($("#quiz-title").data("name"));
|
||||||
|
|
||||||
$(".btn-start-quiz").click((e) => {
|
$(".btn-start-quiz").click((e) => {
|
||||||
@@ -37,7 +38,6 @@ frappe.ready(() => {
|
|||||||
$("#next").click((e) => {
|
$("#next").click((e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!this.show_answers) check_answer();
|
if (!this.show_answers) check_answer();
|
||||||
|
|
||||||
mark_active_question(e);
|
mark_active_question(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ frappe.ready(() => {
|
|||||||
|
|
||||||
const mark_active_question = (e = undefined) => {
|
const mark_active_question = (e = undefined) => {
|
||||||
let total_questions = $(".question").length;
|
let total_questions = $(".question").length;
|
||||||
let current_index = $(".active-question").attr("data-qt-index") || 0;
|
let current_index = this.current_index;
|
||||||
let next_index = parseInt(current_index) + 1;
|
let next_index = parseInt(current_index) + 1;
|
||||||
|
|
||||||
if (this.show_answers) {
|
if (this.show_answers) {
|
||||||
@@ -134,6 +134,9 @@ const quiz_summary = (e = undefined) => {
|
|||||||
$(".quiz-footer span").addClass("hide");
|
$(".quiz-footer span").addClass("hide");
|
||||||
$("#quiz-form").prepend(
|
$("#quiz-form").prepend(
|
||||||
`<div class="summary bold-heading text-center">
|
`<div class="summary bold-heading text-center">
|
||||||
|
${__("You got")} ${Math.ceil(data.message.percentage)}% ${__("correct answers")}
|
||||||
|
</div>
|
||||||
|
<div class="summary bold-heading text-center mt-2">
|
||||||
${__("Your score is")} ${data.message.score}
|
${__("Your score is")} ${data.message.score}
|
||||||
${__("out of")} ${data.message.score_out_of}
|
${__("out of")} ${data.message.score_out_of}
|
||||||
</div>`
|
</div>`
|
||||||
@@ -167,7 +170,7 @@ const check_answer = (e = undefined) => {
|
|||||||
e && e.preventDefault();
|
e && e.preventDefault();
|
||||||
let answer = $(".active-question textarea");
|
let answer = $(".active-question textarea");
|
||||||
let total_questions = $(".question").length;
|
let total_questions = $(".question").length;
|
||||||
let current_index = $(".active-question").attr("data-qt-index");
|
let current_index = this.current_index;
|
||||||
|
|
||||||
if (answer.length && !answer.val().trim()) {
|
if (answer.length && !answer.val().trim()) {
|
||||||
frappe.throw(__("Please enter your answer"));
|
frappe.throw(__("Please enter your answer"));
|
||||||
@@ -179,12 +182,13 @@ const check_answer = (e = undefined) => {
|
|||||||
$(".explanation").removeClass("hide");
|
$(".explanation").removeClass("hide");
|
||||||
$("#check").addClass("hide");
|
$("#check").addClass("hide");
|
||||||
|
|
||||||
if (current_index == total_questions) {
|
if (current_index == total_questions - 1) {
|
||||||
$("#summary").removeClass("hide");
|
$("#summary").removeClass("hide");
|
||||||
} else if (this.show_answers) {
|
} else if (this.show_answers) {
|
||||||
$("#next").removeClass("hide");
|
$("#next").removeClass("hide");
|
||||||
}
|
}
|
||||||
parse_options();
|
parse_options();
|
||||||
|
this.current_index += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parse_options = () => {
|
const parse_options = () => {
|
||||||
@@ -274,12 +278,10 @@ const add_icon = (element, icon) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const add_to_local_storage = () => {
|
const add_to_local_storage = () => {
|
||||||
let current_index = $(".active-question").attr("data-qt-index");
|
|
||||||
let quiz_name = $("#quiz-title").data("name");
|
let quiz_name = $("#quiz-title").data("name");
|
||||||
let quiz_stored = JSON.parse(localStorage.getItem(quiz_name));
|
let quiz_stored = JSON.parse(localStorage.getItem(quiz_name));
|
||||||
|
|
||||||
let quiz_obj = {
|
let quiz_obj = {
|
||||||
question_index: current_index - 1,
|
question_index: this.current_index,
|
||||||
answer: self.answer.join(),
|
answer: self.answer.join(),
|
||||||
is_correct: self.is_correct,
|
is_correct: self.is_correct,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
{{ _("Title") }}
|
{{ _("Title") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<input id="lesson-title" type="text" class="field-input" data-index="{{ lesson_index }}" data-chapter="{{ chapter }}" data-course="{{ course.name }}" {% if lesson.name %} data-lesson="{{ lesson.name }}" value="{{ lesson.title }}" {% endif %}>
|
<input id="lesson-title" type="text" class="field-input" data-index="{{ lesson_index }}" data-chapter="{{ chapter | urlencode }}" data-course="{{ course.name }}" {% if lesson.name %} data-lesson="{{ lesson.name }}" value="{{ lesson.title }}" {% endif %}>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ const save = () => {
|
|||||||
args: {
|
args: {
|
||||||
title: $("#lesson-title").val(),
|
title: $("#lesson-title").val(),
|
||||||
body: this.lesson_content_data,
|
body: this.lesson_content_data,
|
||||||
chapter: $("#lesson-title").data("chapter"),
|
chapter: decodeURIComponent($("#lesson-title").data("chapter")),
|
||||||
preview: $("#preview").prop("checked") ? 1 : 0,
|
preview: $("#preview").prop("checked") ? 1 : 0,
|
||||||
idx: $("#lesson-title").data("index"),
|
idx: $("#lesson-title").data("index"),
|
||||||
lesson: lesson ? lesson : "",
|
lesson: lesson ? lesson : "",
|
||||||
|
|||||||
@@ -658,7 +658,7 @@ const setup_calendar = (events) => {
|
|||||||
const calendar = new Calendar(container, options);
|
const calendar = new Calendar(container, options);
|
||||||
this.calendar_ = calendar;
|
this.calendar_ = calendar;
|
||||||
|
|
||||||
create_events(calendar, events);
|
create_events(calendar, events, calendar_id);
|
||||||
add_links_to_events(calendar, events);
|
add_links_to_events(calendar, events);
|
||||||
scroll_to_date(calendar, events);
|
scroll_to_date(calendar, events);
|
||||||
set_calendar_range(calendar, events);
|
set_calendar_range(calendar, events);
|
||||||
@@ -710,8 +710,8 @@ const create_events = (calendar, events, calendar_id) => {
|
|||||||
id: `event${idx}`,
|
id: `event${idx}`,
|
||||||
calendarId: calendar_id,
|
calendarId: calendar_id,
|
||||||
title: event.title,
|
title: event.title,
|
||||||
start: `${event.date}T${event.start_time}`,
|
start: `${event.date}T${format_time(event.start_time)}`,
|
||||||
end: `${event.date}T${event.end_time}`,
|
end: `${event.date}T${format_time(event.end_time)}`,
|
||||||
isAllday: event.start_time ? false : true,
|
isAllday: event.start_time ? false : true,
|
||||||
borderColor: clr,
|
borderColor: clr,
|
||||||
backgroundColor: "var(--fg-color)",
|
backgroundColor: "var(--fg-color)",
|
||||||
@@ -735,6 +735,12 @@ const create_events = (calendar, events, calendar_id) => {
|
|||||||
calendar.createEvents(calendar_events);
|
calendar.createEvents(calendar_events);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const format_time = (time) => {
|
||||||
|
let time_arr = time.split(":");
|
||||||
|
if (time_arr[0] < 10) time_arr[0] = "0" + time_arr[0];
|
||||||
|
return time_arr.join(":");
|
||||||
|
};
|
||||||
|
|
||||||
const add_links_to_events = (calendar) => {
|
const add_links_to_events = (calendar) => {
|
||||||
calendar.on("clickEvent", ({ event }) => {
|
calendar.on("clickEvent", ({ event }) => {
|
||||||
let event_date = event.start.d.d;
|
let event_date = event.start.d.d;
|
||||||
|
|||||||
@@ -147,6 +147,18 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-auto mb-2">
|
||||||
|
<svg class="icon icon-sm">
|
||||||
|
<use href="#icon-clock"></use>
|
||||||
|
</svg>
|
||||||
|
<span>
|
||||||
|
{{ frappe.utils.format_time(batch.start_time, "HH:mm a") }} -
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ frappe.utils.format_time(batch.end_time, "HH:mm a") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<svg class="icon icon-md">
|
<svg class="icon icon-md">
|
||||||
<use href="#icon-education"></use>
|
<use href="#icon-education"></use>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate, get_time_str, nowtime
|
||||||
from lms.lms.utils import (
|
from lms.lms.utils import (
|
||||||
has_course_moderator_role,
|
has_course_moderator_role,
|
||||||
has_course_evaluator_role,
|
has_course_evaluator_role,
|
||||||
@@ -19,6 +19,8 @@ def get_context(context):
|
|||||||
"description",
|
"description",
|
||||||
"start_date",
|
"start_date",
|
||||||
"end_date",
|
"end_date",
|
||||||
|
"start_time",
|
||||||
|
"end_time",
|
||||||
"paid_batch",
|
"paid_batch",
|
||||||
"amount",
|
"amount",
|
||||||
"currency",
|
"currency",
|
||||||
@@ -43,7 +45,11 @@ def get_context(context):
|
|||||||
)
|
)
|
||||||
if not batch.published:
|
if not batch.published:
|
||||||
private_batches.append(batch)
|
private_batches.append(batch)
|
||||||
elif getdate(batch.start_date) <= getdate():
|
elif getdate(batch.start_date) < getdate():
|
||||||
|
past_batches.append(batch)
|
||||||
|
elif (
|
||||||
|
getdate(batch.start_date) == getdate() and get_time_str(batch.start_time) < nowtime()
|
||||||
|
):
|
||||||
past_batches.append(batch)
|
past_batches.append(batch)
|
||||||
else:
|
else:
|
||||||
upcoming_batches.append(batch)
|
upcoming_batches.append(batch)
|
||||||
|
|||||||
@@ -13,11 +13,54 @@ def get_context(context):
|
|||||||
submission = frappe.form_dict["submission"]
|
submission = frappe.form_dict["submission"]
|
||||||
quiz_name = frappe.form_dict["quiz"]
|
quiz_name = frappe.form_dict["quiz"]
|
||||||
|
|
||||||
context.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",
|
||||||
|
"passing_percentage",
|
||||||
|
],
|
||||||
|
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",
|
||||||
|
filters={"parent": quiz.name},
|
||||||
|
fields=["question", "marks"],
|
||||||
|
order_by="idx",
|
||||||
|
)
|
||||||
|
|
||||||
|
for question in questions:
|
||||||
|
details = frappe.db.get_value("LMS Question", question.question, fields, as_dict=1)
|
||||||
|
details["marks"] = question.marks
|
||||||
|
quiz.questions.append(details)
|
||||||
|
context.quiz = quiz
|
||||||
|
|
||||||
|
context.all_submissions = frappe.get_all(
|
||||||
|
"LMS Quiz Submission",
|
||||||
|
{
|
||||||
|
"quiz": context.quiz.name,
|
||||||
|
"member": frappe.session.user,
|
||||||
|
},
|
||||||
|
["name", "score", "creation"],
|
||||||
|
order_by="creation desc",
|
||||||
|
)
|
||||||
|
|
||||||
|
context.no_of_attempts = len(context.all_submissions) or 0
|
||||||
|
|
||||||
if submission == "new-submission":
|
if submission == "new-submission":
|
||||||
context.submission = frappe._dict()
|
context.submission = frappe._dict()
|
||||||
context.no_of_attempts = 0
|
|
||||||
context.hide_quiz = False
|
context.hide_quiz = False
|
||||||
else:
|
else:
|
||||||
context.submission = frappe.db.get_value(
|
context.submission = frappe.db.get_value(
|
||||||
@@ -33,17 +76,6 @@ def get_context(context):
|
|||||||
if not context.quiz or not context.submission:
|
if not context.quiz or not context.submission:
|
||||||
raise frappe.PermissionError(_("Invalid Submission URL"))
|
raise frappe.PermissionError(_("Invalid Submission URL"))
|
||||||
|
|
||||||
context.all_submissions = frappe.get_all(
|
|
||||||
"LMS Quiz Submission",
|
|
||||||
{
|
|
||||||
"quiz": context.quiz.name,
|
|
||||||
"member": context.submission.member,
|
|
||||||
},
|
|
||||||
["name", "score", "creation"],
|
|
||||||
order_by="creation desc",
|
|
||||||
)
|
|
||||||
|
|
||||||
context.no_of_attempts = len(context.all_submissions) or 0
|
|
||||||
context.hide_quiz = (
|
context.hide_quiz = (
|
||||||
context.is_moderator and context.submission.member != frappe.session.user
|
context.is_moderator or context.submission.member != frappe.session.user
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user