Merge pull request #614 from pateljannat/timetable
feat: Batch Timetable
This commit is contained in:
@@ -10,25 +10,56 @@ frappe.ui.form.on("LMS Batch", {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
fetch_lessons: (frm) => {
|
frm.set_query("reference_doctype", "timetable", function () {
|
||||||
frm.clear_table("scheduled_flow");
|
let doctypes = ["Course Lesson", "LMS Quiz", "LMS Assignment"];
|
||||||
frappe.call({
|
return {
|
||||||
method: "lms.lms.doctype.lms_batch.lms_batch.fetch_lessons",
|
filters: {
|
||||||
args: {
|
name: ["in", doctypes],
|
||||||
courses: frm.doc.courses,
|
},
|
||||||
},
|
};
|
||||||
callback: (r) => {
|
|
||||||
if (r.message) {
|
|
||||||
r.message.forEach((lesson) => {
|
|
||||||
let row = frm.add_child("scheduled_flow");
|
|
||||||
row.lesson = lesson.name;
|
|
||||||
row.lesson_title = lesson.title;
|
|
||||||
});
|
|
||||||
frm.refresh_field("scheduled_flow");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
timetable_template: function (frm) {
|
||||||
|
if (frm.doc.timetable_template) {
|
||||||
|
frm.clear_table("timetable");
|
||||||
|
frm.refresh_fields();
|
||||||
|
|
||||||
|
frappe.call({
|
||||||
|
method: "frappe.client.get_list",
|
||||||
|
args: {
|
||||||
|
doctype: "LMS Batch Timetable",
|
||||||
|
parent: "LMS Timetable Template",
|
||||||
|
fields: [
|
||||||
|
"reference_doctype",
|
||||||
|
"reference_docname",
|
||||||
|
"date",
|
||||||
|
"start_time",
|
||||||
|
"end_time",
|
||||||
|
],
|
||||||
|
filters: {
|
||||||
|
parent: frm.doc.timetable_template,
|
||||||
|
},
|
||||||
|
order_by: "idx",
|
||||||
|
},
|
||||||
|
callback: (data) => {
|
||||||
|
add_timetable_rows(frm, data.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const add_timetable_rows = (frm, timetable) => {
|
||||||
|
timetable.forEach((row) => {
|
||||||
|
let child = frm.add_child("timetable");
|
||||||
|
child.reference_doctype = row.reference_doctype;
|
||||||
|
child.reference_docname = row.reference_docname;
|
||||||
|
child.date = row.date;
|
||||||
|
child.start_time = row.start_time;
|
||||||
|
child.end_time = row.end_time;
|
||||||
|
});
|
||||||
|
frm.refresh_field("timetable");
|
||||||
|
frm.save();
|
||||||
|
};
|
||||||
|
|||||||
@@ -35,8 +35,11 @@
|
|||||||
"assessment_tab",
|
"assessment_tab",
|
||||||
"assessment",
|
"assessment",
|
||||||
"schedule_tab",
|
"schedule_tab",
|
||||||
"fetch_lessons",
|
"timetable_template",
|
||||||
"scheduled_flow"
|
"column_break_anya",
|
||||||
|
"show_live_class",
|
||||||
|
"section_break_ontp",
|
||||||
|
"timetable"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -146,25 +149,14 @@
|
|||||||
"fieldtype": "Autocomplete",
|
"fieldtype": "Autocomplete",
|
||||||
"label": "Category"
|
"label": "Category"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "scheduled_flow",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"label": "Scheduled Flow",
|
|
||||||
"options": "Scheduled Flow"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_ubxi",
|
"fieldname": "section_break_ubxi",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "fetch_lessons",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"label": "Fetch Lessons"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "schedule_tab",
|
"fieldname": "schedule_tab",
|
||||||
"fieldtype": "Tab Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Schedule"
|
"label": "Timetable"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_gsac",
|
"fieldname": "section_break_gsac",
|
||||||
@@ -199,11 +191,37 @@
|
|||||||
"fieldname": "published",
|
"fieldname": "published",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Published"
|
"label": "Published"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "timetable",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Timetable",
|
||||||
|
"options": "LMS Batch Timetable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "timetable_template",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Timetable Template",
|
||||||
|
"options": "LMS Timetable Template"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_anya",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "show_live_class",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Show Live Class"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_ontp",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-09-12 12:30:06.565104",
|
"modified": "2023-09-20 11:25:10.683688",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Batch",
|
"name": "LMS Batch",
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import requests
|
|||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from datetime import timedelta
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cint, format_date, format_datetime
|
from frappe.utils import cint, format_date, format_datetime
|
||||||
from lms.lms.utils import get_lessons
|
from lms.lms.utils import get_lessons, get_lesson_index, get_lesson_url
|
||||||
|
from lms.www.utils import get_quiz_details, get_assignment_details
|
||||||
|
|
||||||
|
|
||||||
class LMSBatch(Document):
|
class LMSBatch(Document):
|
||||||
@@ -19,7 +21,7 @@ class LMSBatch(Document):
|
|||||||
self.validate_duplicate_students()
|
self.validate_duplicate_students()
|
||||||
self.validate_duplicate_assessments()
|
self.validate_duplicate_assessments()
|
||||||
self.validate_membership()
|
self.validate_membership()
|
||||||
self.validate_schedule()
|
self.validate_timetable()
|
||||||
|
|
||||||
def validate_duplicate_students(self):
|
def validate_duplicate_students(self):
|
||||||
students = [row.student for row in self.students]
|
students = [row.student for row in self.students]
|
||||||
@@ -68,8 +70,8 @@ class LMSBatch(Document):
|
|||||||
if cint(self.seat_count) < len(self.students):
|
if cint(self.seat_count) < len(self.students):
|
||||||
frappe.throw(_("There are no seats available in this batch."))
|
frappe.throw(_("There are no seats available in this batch."))
|
||||||
|
|
||||||
def validate_schedule(self):
|
def validate_timetable(self):
|
||||||
for schedule in self.scheduled_flow:
|
for schedule in self.timetable:
|
||||||
if schedule.start_time and schedule.end_time:
|
if schedule.start_time and schedule.end_time:
|
||||||
if (
|
if (
|
||||||
schedule.start_time > schedule.end_time or schedule.start_time == schedule.end_time
|
schedule.start_time > schedule.end_time or schedule.start_time == schedule.end_time
|
||||||
@@ -266,3 +268,66 @@ def add_course(course, parent, name=None, evaluator=None):
|
|||||||
doc.save()
|
doc.save()
|
||||||
|
|
||||||
return doc.name
|
return doc.name
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_batch_timetable(batch):
|
||||||
|
timetable = frappe.get_all(
|
||||||
|
"LMS Batch Timetable",
|
||||||
|
filters={"parent": batch},
|
||||||
|
fields=["reference_doctype", "reference_docname", "date", "start_time", "end_time"],
|
||||||
|
order_by="date",
|
||||||
|
)
|
||||||
|
|
||||||
|
show_live_class = frappe.db.get_value("LMS Batch", batch, "show_live_class")
|
||||||
|
if show_live_class:
|
||||||
|
live_classes = get_live_classes(batch)
|
||||||
|
timetable.extend(live_classes)
|
||||||
|
|
||||||
|
timetable = get_timetable_details(timetable)
|
||||||
|
return timetable
|
||||||
|
|
||||||
|
|
||||||
|
def get_live_classes(batch):
|
||||||
|
live_classes = frappe.get_all(
|
||||||
|
"LMS Live Class",
|
||||||
|
{"batch_name": batch},
|
||||||
|
["name", "title", "date", "time as start_time", "duration", "join_url as url"],
|
||||||
|
order_by="date",
|
||||||
|
)
|
||||||
|
for class_ in live_classes:
|
||||||
|
class_.end_time = class_.start_time + timedelta(minutes=class_.duration)
|
||||||
|
class_.reference_doctype = "LMS Live Class"
|
||||||
|
class_.reference_docname = class_.name
|
||||||
|
class_.icon = "icon-call"
|
||||||
|
|
||||||
|
return live_classes
|
||||||
|
|
||||||
|
|
||||||
|
def get_timetable_details(timetable):
|
||||||
|
for entry in timetable:
|
||||||
|
entry.title = frappe.db.get_value(
|
||||||
|
entry.reference_doctype, entry.reference_docname, "title"
|
||||||
|
)
|
||||||
|
assessment = frappe._dict({"assessment_name": entry.reference_docname})
|
||||||
|
|
||||||
|
if entry.reference_doctype == "Course Lesson":
|
||||||
|
entry.icon = "icon-list"
|
||||||
|
course = frappe.db.get_value(
|
||||||
|
entry.reference_doctype, entry.reference_docname, "course"
|
||||||
|
)
|
||||||
|
entry.url = get_lesson_url(course, get_lesson_index(entry.reference_docname))
|
||||||
|
|
||||||
|
elif entry.reference_doctype == "LMS Quiz":
|
||||||
|
entry.icon = "icon-quiz"
|
||||||
|
entry.url = "/quizzes"
|
||||||
|
details = get_quiz_details(assessment, frappe.session.user)
|
||||||
|
entry.update(details)
|
||||||
|
|
||||||
|
elif entry.reference_doctype == "LMS Assignment":
|
||||||
|
entry.icon = "icon-quiz"
|
||||||
|
details = get_assignment_details(assessment, frappe.session.user)
|
||||||
|
entry.update(details)
|
||||||
|
|
||||||
|
timetable = sorted(timetable, key=lambda k: k["date"])
|
||||||
|
return timetable
|
||||||
|
|||||||
0
lms/lms/doctype/lms_batch_timetable/__init__.py
Normal file
0
lms/lms/doctype/lms_batch_timetable/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2023, Frappe and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
// frappe.ui.form.on("LMS Batch Timetable", {
|
||||||
|
// refresh(frm) {
|
||||||
|
|
||||||
|
// },
|
||||||
|
// });
|
||||||
81
lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json
Normal file
81
lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "hash",
|
||||||
|
"creation": "2023-09-14 12:44:51.098956",
|
||||||
|
"default_view": "List",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"column_break_htdc",
|
||||||
|
"reference_doctype",
|
||||||
|
"reference_docname",
|
||||||
|
"date",
|
||||||
|
"column_break_merq",
|
||||||
|
"start_time",
|
||||||
|
"end_time",
|
||||||
|
"duration"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "reference_doctype",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Reference DocType",
|
||||||
|
"options": "DocType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reference_docname",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Reference DocName",
|
||||||
|
"options": "reference_doctype"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_merq",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "start_time",
|
||||||
|
"fieldtype": "Time",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Start Time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "duration",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Duration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_htdc",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "end_time",
|
||||||
|
"fieldtype": "Time",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "End Time"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2023-09-15 10:35:40.642660",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "LMS",
|
||||||
|
"name": "LMS Batch Timetable",
|
||||||
|
"naming_rule": "Random",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2023, Frappe and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class LMSBatchTimetable(Document):
|
||||||
|
pass
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2023, Frappe and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestLMSBatchTimetable(FrappeTestCase):
|
||||||
|
pass
|
||||||
@@ -10,16 +10,16 @@
|
|||||||
"title",
|
"title",
|
||||||
"host",
|
"host",
|
||||||
"batch_name",
|
"batch_name",
|
||||||
"password",
|
|
||||||
"auto_recording",
|
|
||||||
"column_break_astv",
|
"column_break_astv",
|
||||||
"description",
|
|
||||||
"section_break_glxh",
|
|
||||||
"date",
|
"date",
|
||||||
"timezone",
|
|
||||||
"column_break_spvt",
|
|
||||||
"time",
|
"time",
|
||||||
"duration",
|
"duration",
|
||||||
|
"section_break_glxh",
|
||||||
|
"description",
|
||||||
|
"column_break_spvt",
|
||||||
|
"timezone",
|
||||||
|
"password",
|
||||||
|
"auto_recording",
|
||||||
"section_break_yrpq",
|
"section_break_yrpq",
|
||||||
"start_url",
|
"start_url",
|
||||||
"column_break_yokr",
|
"column_break_yokr",
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-03-14 18:44:48.813103",
|
"modified": "2023-09-20 11:29:20.899897",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Live Class",
|
"name": "LMS Live Class",
|
||||||
@@ -157,8 +157,10 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"show_title_field_in_link": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": [],
|
"states": [],
|
||||||
|
"title_field": "title",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
0
lms/lms/doctype/lms_timetable_template/__init__.py
Normal file
0
lms/lms/doctype/lms_timetable_template/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2023, Frappe and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on("LMS Timetable Template", {
|
||||||
|
refresh(frm) {
|
||||||
|
frm.set_query("reference_doctype", "timetable", function () {
|
||||||
|
let doctypes = ["Course Lesson", "LMS Quiz", "LMS Assignment"];
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ["in", doctypes],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "hash",
|
||||||
|
"creation": "2023-09-18 14:16:16.964077",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"title",
|
||||||
|
"timetable"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "title",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "timetable",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Timetable",
|
||||||
|
"options": "LMS Batch Timetable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2023-09-18 17:57:15.819072",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "LMS",
|
||||||
|
"name": "LMS Timetable Template",
|
||||||
|
"naming_rule": "Random",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Moderator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"show_title_field_in_link": 1,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
|
"title_field": "title"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2023, Frappe and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class LMSTimetableTemplate(Document):
|
||||||
|
pass
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2023, Frappe and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestLMSTimetableTemplate(FrappeTestCase):
|
||||||
|
pass
|
||||||
@@ -2352,4 +2352,94 @@ select {
|
|||||||
left: 80%;
|
left: 80%;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-milestone {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-task {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-panel-resizer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-day-name__date {
|
||||||
|
font-size: var(--text-base) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-day-name__name {
|
||||||
|
font-size: var(--text-base) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-day-view-day-names, .toastui-calendar-week-view-day-names {
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-layout {
|
||||||
|
border: 1px solid var(--gray-200) !important;
|
||||||
|
border-radius: var(--border-radius-md) !important;
|
||||||
|
background-color: var(--gray-100) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-panel .toastui-calendar-day-names.toastui-calendar-week {
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-panel.toastui-calendar-time {
|
||||||
|
height: 80% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-panel.toastui-calendar-week-view-day-names {
|
||||||
|
background-color: var(--gray-50) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toastui-calendar-allday {
|
||||||
|
border-bottom: 1px solid var(--gray-200) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-navigation {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-range {
|
||||||
|
margin: 0 2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-event-title {
|
||||||
|
font-size: var(--text-md);
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-color {
|
||||||
|
width: 50px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-text {
|
||||||
|
color: var(--text-color);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-legends {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 50%;
|
||||||
|
margin: 0 auto 1rem;
|
||||||
}
|
}
|
||||||
@@ -105,13 +105,10 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if flow | length %}
|
{% if show_timetable %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" data-toggle="tab" href="#schedule">
|
<a class="nav-link" data-toggle="tab" href="#timetable">
|
||||||
{{ _("Schedule") }}
|
{{ _("Timetable") }}
|
||||||
<span class="course-list-count">
|
|
||||||
{{ flow | length }}
|
|
||||||
</span>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -169,9 +166,9 @@
|
|||||||
{{ CoursesSection(batch_info, batch_courses) }}
|
{{ CoursesSection(batch_info, batch_courses) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if flow | length %}
|
{% if show_timetable %}
|
||||||
<div class="tab-pane" id="schedule" role="tabpanel" aria-labelledby="schedule">
|
<div class="tab-pane" id="timetable" role="tabpanel" aria-labelledby="timetable">
|
||||||
{{ ScheduleSection(flow) }}
|
{{ Timetable() }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -513,79 +510,38 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
{% macro ScheduleSection(flow) %}
|
{% macro Timetable() %}
|
||||||
<article>
|
<article>
|
||||||
<header class="edit-header mb-5">
|
<header class="edit-header mb-5">
|
||||||
<div class="bold-heading">
|
<div class="bold-heading">
|
||||||
{{ _("Schedule") }}
|
{{ _("Timetable") }}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<div class="calendar-navigation">
|
||||||
<div>
|
<button class="btn icon-btn btn-default" id="prev-week">
|
||||||
{% for chapter in flow %}
|
<svg class="icon icon-md">
|
||||||
<div class="chapter-parent">
|
<use href="#icon-left"></use>
|
||||||
<div class="chapter-title" data-toggle="collapse" data-target="#{{ get_slugified_chapter_title(chapter.chapter_title) }}">
|
</svg>
|
||||||
<img class="chapter-icon" src="/assets/lms/icons/chevron-right.svg">
|
</button>
|
||||||
<div class="chapter-title-main">
|
<span class="calendar-range"></span>
|
||||||
{{ chapter.chapter_title }}
|
<button class="btn icon-btn btn-default" id="next-week">
|
||||||
</div>
|
<svg class="icon icon-md">
|
||||||
</div>
|
<use href="#icon-right"></use>
|
||||||
<div class="chapter-content lessons collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.chapter_title) }}">
|
</svg>
|
||||||
|
</button>
|
||||||
<div class="schedule-header">
|
</div>
|
||||||
<div class="w-50">
|
<div class="calendar-legends">
|
||||||
{{ _("Lesson") }}
|
{% for legend in legends %}
|
||||||
</div>
|
<div class="legend-item">
|
||||||
<div class="w-25">
|
<div class="legend-color" style="background-color: {{ legend.color }}"></div>
|
||||||
{{ _("Date") }}
|
<div class="legend-text">{{ legend.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-25 text-center">
|
|
||||||
{{ _("Start Time") }}
|
|
||||||
</div>
|
|
||||||
<div class="w-25 text-center">
|
|
||||||
{{ _("End Time") }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% for lesson in chapter.lessons %}
|
|
||||||
<div class="lesson-info flex align-center">
|
|
||||||
<a class="lesson-links w-50" href="{{ lesson.url }}">
|
|
||||||
<svg class="icon icon-sm mr-2">
|
|
||||||
<use class="" href="#{{ lesson.icon }}">
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
{{ lesson.title }}
|
|
||||||
|
|
||||||
{% if current_student.name and get_membership(lesson.course, current_student.name) %}
|
|
||||||
{% set lesson_progress = get_progress(lesson.course, lesson.name, current_student.name) %}
|
|
||||||
<svg class="icon icon-md lesson-progress-tick ml-3 {% if lesson_progress != 'Complete' %} hide {% endif %}">
|
|
||||||
<use class="" href="#icon-success">
|
|
||||||
</svg>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
<div class="w-25">
|
|
||||||
{{ frappe.utils.format_date(lesson.date, "medium") }}
|
|
||||||
</div>
|
|
||||||
<div class="w-25 text-center">
|
|
||||||
{% if lesson.start_time %}
|
|
||||||
{{ frappe.utils.format_time(lesson.start_time, "HH:mm a") }}
|
|
||||||
{% else %}
|
|
||||||
-
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="w-25 text-center">
|
|
||||||
{% if lesson.end_time %}
|
|
||||||
{{ frappe.utils.format_time(lesson.end_time, "HH:mm a") }}
|
|
||||||
{% else %}
|
|
||||||
-
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div id="calendar" class="timetable-calendar" style="height: 700px"
|
||||||
|
data-start="{{ batch_info.start_time }}" data-end="{{ batch_info.end_time }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
@@ -595,4 +551,6 @@
|
|||||||
frappe.boot.single_types = []
|
frappe.boot.single_types = []
|
||||||
let courses = {{ course_list | json }};
|
let courses = {{ course_list | json }};
|
||||||
</script>
|
</script>
|
||||||
|
<link rel="stylesheet" href="https://uicdn.toast.com/calendar/latest/toastui-calendar.min.css" />
|
||||||
|
<script src="https://uicdn.toast.com/calendar/latest/toastui-calendar.min.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -2,6 +2,24 @@ frappe.ready(() => {
|
|||||||
let self = this;
|
let self = this;
|
||||||
frappe.require("controls.bundle.js");
|
frappe.require("controls.bundle.js");
|
||||||
|
|
||||||
|
if ($("#calendar").length) {
|
||||||
|
setup_timetable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($("#calendar").length) {
|
||||||
|
$(document).on("click", "#prev-week", (e) => {
|
||||||
|
this.calendar_ && this.calendar_.prev();
|
||||||
|
set_calendar_range(this.calendar_, this.events);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($("#calendar").length) {
|
||||||
|
$(document).on("click", "#next-week", (e) => {
|
||||||
|
this.calendar_ && this.calendar_.next();
|
||||||
|
set_calendar_range(this.calendar_, this.events);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ($("#live-class-form").length) {
|
if ($("#live-class-form").length) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
make_live_class_form();
|
make_live_class_form();
|
||||||
@@ -606,3 +624,144 @@ const submit_evaluation_form = (values) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setup_timetable = () => {
|
||||||
|
let self = this;
|
||||||
|
frappe.call({
|
||||||
|
method: "lms.lms.doctype.lms_batch.lms_batch.get_batch_timetable",
|
||||||
|
args: {
|
||||||
|
batch: $(".class-details").data("batch"),
|
||||||
|
},
|
||||||
|
callback: (r) => {
|
||||||
|
if (r.message.length) {
|
||||||
|
setup_calendar(r.message);
|
||||||
|
self.events = r.message;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setup_calendar = (events) => {
|
||||||
|
const element = $("#calendar");
|
||||||
|
const Calendar = tui.Calendar;
|
||||||
|
const calendar_id = "calendar1";
|
||||||
|
const container = element[0];
|
||||||
|
const options = get_calendar_options(element, calendar_id);
|
||||||
|
const calendar = new Calendar(container, options);
|
||||||
|
this.calendar_ = calendar;
|
||||||
|
console.log(options);
|
||||||
|
create_events(calendar, events);
|
||||||
|
add_links_to_events(calendar, events);
|
||||||
|
scroll_to_date(calendar, events);
|
||||||
|
set_calendar_range(calendar, events);
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_calendar_options = (element, calendar_id) => {
|
||||||
|
const start_time = element.data("start");
|
||||||
|
const end_time = element.data("end");
|
||||||
|
|
||||||
|
return {
|
||||||
|
defaultView: "week",
|
||||||
|
usageStatistics: false,
|
||||||
|
week: {
|
||||||
|
narrowWeekend: true,
|
||||||
|
hourStart: parseInt(start_time.split(":")[0]) - 1,
|
||||||
|
/* hourEnd: parseInt(end_time.split(":")[0]) + 1, */
|
||||||
|
},
|
||||||
|
month: {
|
||||||
|
narrowWeekend: true,
|
||||||
|
},
|
||||||
|
taskView: false,
|
||||||
|
isReadOnly: true,
|
||||||
|
calendars: [
|
||||||
|
{
|
||||||
|
id: calendar_id,
|
||||||
|
name: "Timetable",
|
||||||
|
backgroundColor: "var(--fg-color)",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
template: {
|
||||||
|
time: function (event) {
|
||||||
|
return `<div class="calendar-event-time">
|
||||||
|
<div> ${frappe.datetime.get_time(event.start.d.d)} -
|
||||||
|
${frappe.datetime.get_time(event.end.d.d)} </div>
|
||||||
|
<div class="calendar-event-title"> ${event.title} </div>
|
||||||
|
</div>`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const create_events = (calendar, events, calendar_id) => {
|
||||||
|
let calendar_events = [];
|
||||||
|
|
||||||
|
events.forEach((event, idx) => {
|
||||||
|
calendar_events.push({
|
||||||
|
id: `event${idx}`,
|
||||||
|
calendarId: calendar_id,
|
||||||
|
title: event.title,
|
||||||
|
start: `${event.date}T${event.start_time}`,
|
||||||
|
end: `${event.date}T${event.end_time}`,
|
||||||
|
isAllday: event.start_time ? false : true,
|
||||||
|
borderColor: get_background_color(event.reference_doctype),
|
||||||
|
backgroundColor: "var(--fg-color)",
|
||||||
|
customStyle: {
|
||||||
|
borderRadius: "var(--border-radius-md)",
|
||||||
|
boxShadow: "var(--shadow-base)",
|
||||||
|
borderWidth: "8px",
|
||||||
|
padding: "0.25rem 0.5rem 0.5rem",
|
||||||
|
},
|
||||||
|
raw: {
|
||||||
|
url: event.url,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
calendar.createEvents(calendar_events);
|
||||||
|
};
|
||||||
|
|
||||||
|
const add_links_to_events = (calendar, events) => {
|
||||||
|
calendar.on("clickEvent", ({ event }) => {
|
||||||
|
const el = document.getElementById("clicked-event");
|
||||||
|
window.open(event.raw.url, "_blank");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const scroll_to_date = (calendar, events) => {
|
||||||
|
if (
|
||||||
|
new Date() < new Date(events[0].date) ||
|
||||||
|
new Date() > new Date(events.slice(-1).date)
|
||||||
|
) {
|
||||||
|
calendar.setDate(new Date(events[0].date));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const set_calendar_range = (calendar, events) => {
|
||||||
|
let week_start = moment(calendar.getDateRangeStart().d.d);
|
||||||
|
let week_end = moment(calendar.getDateRangeEnd().d.d);
|
||||||
|
|
||||||
|
$(".calendar-range").text(
|
||||||
|
`${moment(week_start).format("DD MMMM YYYY")} - ${moment(
|
||||||
|
week_end
|
||||||
|
).format("DD MMMM YYYY")}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (week_start.diff(moment(events[0].date), "days") <= 0) {
|
||||||
|
$("#prev-week").hide();
|
||||||
|
} else {
|
||||||
|
$("#prev-week").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (week_end.diff(moment(events.slice(-1)[0].date), "days") > 0) {
|
||||||
|
$("#next-week").hide();
|
||||||
|
} else {
|
||||||
|
$("#next-week").show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_background_color = (doctype) => {
|
||||||
|
if (doctype == "Course Lesson") return "var(--blue-400)";
|
||||||
|
if (doctype == "LMS Quiz") return "var(--green-400)";
|
||||||
|
if (doctype == "LMS Assignment") return "var(--orange-400)";
|
||||||
|
if (doctype == "LMS Live Class") return "var(--purple-400)";
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import getdate, cint
|
from frappe.utils import getdate, get_datetime
|
||||||
from lms.www.utils import get_assessments, is_student
|
from lms.www.utils import get_assessments, is_student
|
||||||
from lms.lms.utils import (
|
from lms.lms.utils import (
|
||||||
has_course_moderator_role,
|
has_course_moderator_role,
|
||||||
@@ -89,7 +89,13 @@ def get_context(context):
|
|||||||
)
|
)
|
||||||
context.all_assignments = get_all_assignments(batch_name)
|
context.all_assignments = get_all_assignments(batch_name)
|
||||||
context.all_quizzes = get_all_quizzes(batch_name)
|
context.all_quizzes = get_all_quizzes(batch_name)
|
||||||
context.flow = get_scheduled_flow(batch_name)
|
context.show_timetable = frappe.db.count(
|
||||||
|
"LMS Batch Timetable",
|
||||||
|
{
|
||||||
|
"parent": batch_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
context.legends = get_legends()
|
||||||
|
|
||||||
|
|
||||||
def get_all_quizzes(batch_name):
|
def get_all_quizzes(batch_name):
|
||||||
@@ -210,38 +216,6 @@ def sort_students(batch_students):
|
|||||||
return batch_students
|
return batch_students
|
||||||
|
|
||||||
|
|
||||||
def get_scheduled_flow(batch_name):
|
|
||||||
chapters = []
|
|
||||||
|
|
||||||
lessons = frappe.get_all(
|
|
||||||
"Scheduled Flow",
|
|
||||||
{"parent": batch_name},
|
|
||||||
["name", "lesson", "date", "start_time", "end_time"],
|
|
||||||
order_by="idx",
|
|
||||||
)
|
|
||||||
|
|
||||||
for lesson in lessons:
|
|
||||||
lesson = get_lesson_details(lesson, batch_name)
|
|
||||||
chapter_exists = [
|
|
||||||
chapter for chapter in chapters if chapter.chapter == lesson.chapter
|
|
||||||
]
|
|
||||||
|
|
||||||
if len(chapter_exists) == 0:
|
|
||||||
chapters.append(
|
|
||||||
frappe._dict(
|
|
||||||
{
|
|
||||||
"chapter": lesson.chapter,
|
|
||||||
"chapter_title": frappe.db.get_value("Course Chapter", lesson.chapter, "title"),
|
|
||||||
"lessons": [lesson],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
chapter_exists[0]["lessons"].append(lesson)
|
|
||||||
|
|
||||||
return chapters
|
|
||||||
|
|
||||||
|
|
||||||
def get_lesson_details(lesson, batch_name):
|
def get_lesson_details(lesson, batch_name):
|
||||||
lesson.update(
|
lesson.update(
|
||||||
frappe.db.get_value(
|
frappe.db.get_value(
|
||||||
@@ -277,3 +251,24 @@ def get_course_progress(batch_courses, student_details):
|
|||||||
student_details.courses[course.course] = membership.progress
|
student_details.courses[course.course] = membership.progress
|
||||||
else:
|
else:
|
||||||
student_details.courses[course.course] = 0
|
student_details.courses[course.course] = 0
|
||||||
|
|
||||||
|
|
||||||
|
def get_legends():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"title": "Lesson",
|
||||||
|
"color": "var(--blue-400)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Quiz",
|
||||||
|
"color": "var(--green-400)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Assignment",
|
||||||
|
"color": "var(--orange-400)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Live Class",
|
||||||
|
"color": "var(--purple-400)",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|||||||
@@ -136,9 +136,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{% if is_moderator or is_evaluator or is_student %}
|
{% if is_moderator or is_evaluator %}
|
||||||
<a class="btn btn-primary wide-button" href="/batches/{{ batch_info.name }}">
|
<a class="btn btn-primary wide-button" href="/batches/{{ batch_info.name }}">
|
||||||
{{ _("Checkout Batch") }}
|
{{ _("Manage Batch") }}
|
||||||
</a>
|
</a>
|
||||||
{% elif batch_info.paid_batch %}
|
{% elif batch_info.paid_batch %}
|
||||||
<a class="btn btn-primary wide-button {% if batch_info.seat_count and not seats_left %} hide {% endif %}"
|
<a class="btn btn-primary wide-button {% if batch_info.seat_count and not seats_left %} hide {% endif %}"
|
||||||
|
|||||||
@@ -31,10 +31,15 @@ def get_context(context):
|
|||||||
|
|
||||||
context.is_moderator = has_course_moderator_role()
|
context.is_moderator = has_course_moderator_role()
|
||||||
context.is_evaluator = has_course_evaluator_role()
|
context.is_evaluator = has_course_evaluator_role()
|
||||||
|
context.is_student = is_student(batch_name)
|
||||||
|
|
||||||
if not context.is_moderator and not context.batch_info.published:
|
if not context.is_moderator and not context.batch_info.published:
|
||||||
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
||||||
|
|
||||||
|
if context.is_student:
|
||||||
|
frappe.local.flags.redirect_location = f"/batches/{batch_name}"
|
||||||
|
raise frappe.Redirect
|
||||||
|
|
||||||
context.courses = frappe.get_all(
|
context.courses = frappe.get_all(
|
||||||
"Batch Course",
|
"Batch Course",
|
||||||
{"parent": batch_name},
|
{"parent": batch_name},
|
||||||
@@ -51,5 +56,3 @@ def get_context(context):
|
|||||||
|
|
||||||
context.student_count = frappe.db.count("Batch Student", {"parent": batch_name})
|
context.student_count = frappe.db.count("Batch Student", {"parent": batch_name})
|
||||||
context.seats_left = context.batch_info.seat_count - context.student_count
|
context.seats_left = context.batch_info.seat_count - context.student_count
|
||||||
|
|
||||||
context.is_student = is_student(batch_name)
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ def get_context(context):
|
|||||||
batch.seats_left = (
|
batch.seats_left = (
|
||||||
batch.seat_count - batch.student_count if batch.seat_count else None
|
batch.seat_count - batch.student_count if batch.seat_count else None
|
||||||
)
|
)
|
||||||
print(batch.name, batch.published)
|
|
||||||
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():
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def get_context(context):
|
|||||||
|
|
||||||
def validate_access(doctype, docname, module):
|
def validate_access(doctype, docname, module):
|
||||||
if frappe.session.user == "Guest":
|
if frappe.session.user == "Guest":
|
||||||
raise frappe.PermissionError(_("You are not allowed to access this page."))
|
raise frappe.PermissionError(_("Please login to continue with payment."))
|
||||||
|
|
||||||
if module not in ["course", "batch"]:
|
if module not in ["course", "batch"]:
|
||||||
raise ValueError(_("Module is incorrect."))
|
raise ValueError(_("Module is incorrect."))
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ def get_assignment_details(assessment, member):
|
|||||||
f"/assignment-submission/{assessment.assessment_name}/{submission_name}"
|
f"/assignment-submission/{assessment.assessment_name}/{submission_name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return assessment
|
||||||
|
|
||||||
|
|
||||||
def get_quiz_details(assessment, member):
|
def get_quiz_details(assessment, member):
|
||||||
assessment.title = frappe.db.get_value("LMS Quiz", assessment.assessment_name, "title")
|
assessment.title = frappe.db.get_value("LMS Quiz", assessment.assessment_name, "title")
|
||||||
@@ -131,6 +133,8 @@ def get_quiz_details(assessment, member):
|
|||||||
)
|
)
|
||||||
assessment.url = f"/quiz-submission/{assessment.assessment_name}/{submission_name}"
|
assessment.url = f"/quiz-submission/{assessment.assessment_name}/{submission_name}"
|
||||||
|
|
||||||
|
return assessment
|
||||||
|
|
||||||
|
|
||||||
def is_student(batch, member=None):
|
def is_student(batch, member=None):
|
||||||
if not member:
|
if not member:
|
||||||
|
|||||||
Reference in New Issue
Block a user