Merge branch 'main' of https://github.com/frappe/lms into class-revamp
This commit is contained in:
@@ -8,6 +8,8 @@ else
|
|||||||
echo "Creating new bench..."
|
echo "Creating new bench..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
export PATH="${NVM_DIR}/versions/node/v${NODE_VERSION_DEVELOP}/bin/:${PATH}"
|
||||||
|
|
||||||
bench init --skip-redis-config-generation frappe-bench
|
bench init --skip-redis-config-generation frappe-bench
|
||||||
|
|
||||||
cd frappe-bench
|
cd frappe-bench
|
||||||
@@ -36,4 +38,4 @@ bench --site lms.localhost clear-cache
|
|||||||
bench --site lms.localhost set-config mute_emails 1
|
bench --site lms.localhost set-config mute_emails 1
|
||||||
bench use lms.localhost
|
bench use lms.localhost
|
||||||
|
|
||||||
bench start
|
bench start
|
||||||
|
|||||||
10
lms/hooks.py
10
lms/hooks.py
@@ -103,11 +103,11 @@ doc_events = {
|
|||||||
|
|
||||||
# Scheduled Tasks
|
# Scheduled Tasks
|
||||||
# ---------------
|
# ---------------
|
||||||
# scheduler_events = {
|
scheduler_events = {
|
||||||
# "daily": [
|
"hourly": [
|
||||||
# "erpnext.stock.reorder_item.reorder_item"
|
"lms.lms.doctype.lms_certificate_request.lms_certificate_request.schedule_evals"
|
||||||
# ]
|
]
|
||||||
# }
|
}
|
||||||
|
|
||||||
fixtures = ["Custom Field", "Function", "Industry"]
|
fixtures = ["Custom Field", "Function", "Industry"]
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ def before_uninstall():
|
|||||||
def create_lms_roles():
|
def create_lms_roles():
|
||||||
create_course_creator_role()
|
create_course_creator_role()
|
||||||
create_moderator_role()
|
create_moderator_role()
|
||||||
|
create_evaluator_role()
|
||||||
|
|
||||||
|
|
||||||
def delete_lms_roles():
|
def delete_lms_roles():
|
||||||
@@ -91,6 +92,19 @@ def create_moderator_role():
|
|||||||
role.save(ignore_permissions=True)
|
role.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
|
def create_evaluator_role():
|
||||||
|
if not frappe.db.exists("Role", "Class Evaluator"):
|
||||||
|
role = frappe.new_doc("Role")
|
||||||
|
role.update(
|
||||||
|
{
|
||||||
|
"role_name": "Class Evaluator",
|
||||||
|
"home_page": "",
|
||||||
|
"desk_access": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
role.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
def delete_custom_fields():
|
def delete_custom_fields():
|
||||||
fields = [
|
fields = [
|
||||||
"user_category",
|
"user_category",
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"course",
|
"course",
|
||||||
"title"
|
"title",
|
||||||
|
"evaluator"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -23,14 +24,21 @@
|
|||||||
"fieldname": "title",
|
"fieldname": "title",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Title",
|
"label": "Course Title",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "evaluator",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Evaluator",
|
||||||
|
"options": "Course Evaluator"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-11-11 15:51:45.560864",
|
"modified": "2023-07-13 17:51:36.278393",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "Class Course",
|
"name": "Class Course",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-04-01 15:14:03.300260",
|
"modified": "2023-07-13 11:30:22.641076",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "Course Evaluator",
|
"name": "Course Evaluator",
|
||||||
@@ -45,6 +45,30 @@
|
|||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Moderator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Class Evaluator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from lms.lms.utils import get_evaluator
|
||||||
|
|
||||||
|
|
||||||
class CourseEvaluator(Document):
|
class CourseEvaluator(Document):
|
||||||
@@ -36,21 +37,26 @@ class CourseEvaluator(Document):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_schedule(course, date):
|
def get_schedule(course, date, class_name=None):
|
||||||
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
evaluator = get_evaluator(course, class_name)
|
||||||
|
|
||||||
all_slots = frappe.get_all(
|
all_slots = frappe.get_all(
|
||||||
"Evaluator Schedule",
|
"Evaluator Schedule",
|
||||||
filters={"parent": evaluator},
|
filters={"parent": evaluator},
|
||||||
fields=["day", "start_time", "end_time"],
|
fields=["day", "start_time", "end_time"],
|
||||||
|
order_by="start_time",
|
||||||
)
|
)
|
||||||
|
|
||||||
booked_slots = frappe.get_all(
|
booked_slots = frappe.get_all(
|
||||||
"LMS Certificate Request",
|
"LMS Certificate Request",
|
||||||
filters={"evaluator": evaluator, "date": date},
|
filters={"evaluator": evaluator, "date": date},
|
||||||
fields=["start_time"],
|
fields=["start_time", "day"],
|
||||||
)
|
)
|
||||||
|
|
||||||
for slot in booked_slots:
|
for slot in booked_slots:
|
||||||
same_slot = list(filter(lambda x: x.start_time == slot.start_time, all_slots))
|
same_slot = list(
|
||||||
|
filter(lambda x: x.start_time == slot.start_time and x.day == slot.day, all_slots)
|
||||||
|
)
|
||||||
if len(same_slot):
|
if len(same_slot):
|
||||||
all_slots.remove(same_slot[0])
|
all_slots.remove(same_slot[0])
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-02-22 16:00:34.361934",
|
"modified": "2023-07-13 11:30:53.432076",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Certificate Evaluation",
|
"name": "LMS Certificate Evaluation",
|
||||||
@@ -121,6 +121,18 @@
|
|||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Class Evaluator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"section_break_lifi",
|
"section_break_lifi",
|
||||||
"date",
|
"date",
|
||||||
"day",
|
"day",
|
||||||
|
"google_meet_link",
|
||||||
"column_break_ddyh",
|
"column_break_ddyh",
|
||||||
"start_time",
|
"start_time",
|
||||||
"end_time"
|
"end_time"
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "course.evaluator",
|
"fetch_from": "course.evaluator",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "evaluator",
|
"fieldname": "evaluator",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Evaluator",
|
"label": "Evaluator",
|
||||||
@@ -89,11 +91,17 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_ddyh",
|
"fieldname": "column_break_ddyh",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "google_meet_link",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Google Meet Link",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-02-28 19:53:17.534351",
|
"modified": "2023-07-21 16:00:11.795521",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Certificate Request",
|
"name": "LMS Certificate Request",
|
||||||
@@ -111,6 +119,30 @@
|
|||||||
"select": 1,
|
"select": 1,
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Class Evaluator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Moderator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
|||||||
@@ -5,26 +5,23 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from frappe.utils import format_date, format_time, getdate
|
from frappe.utils import format_date, format_time, getdate, add_to_date, get_datetime
|
||||||
|
from lms.lms.utils import get_evaluator
|
||||||
|
|
||||||
|
|
||||||
class LMSCertificateRequest(Document):
|
class LMSCertificateRequest(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_if_existing_requests()
|
self.validate_if_existing_requests()
|
||||||
|
|
||||||
def after_insert(self):
|
|
||||||
if frappe.db.get_single_value("LMS Settings", "send_calendar_invite_for_evaluations"):
|
|
||||||
self.create_event()
|
|
||||||
|
|
||||||
def validate_if_existing_requests(self):
|
def validate_if_existing_requests(self):
|
||||||
existing_requests = frappe.get_all(
|
existing_requests = frappe.get_all(
|
||||||
"LMS Certificate Request",
|
"LMS Certificate Request",
|
||||||
{"member": self.member, "course": self.course},
|
{"member": self.member, "course": self.course, "name": ["!=", self.name]},
|
||||||
["date", "start_time", "course"],
|
["date", "start_time", "course"],
|
||||||
)
|
)
|
||||||
|
|
||||||
for req in existing_requests:
|
for req in existing_requests:
|
||||||
if req.date == getdate(self.date) and getdate() <= getdate(self.date):
|
if req.date == getdate(self.date) or getdate() <= getdate(self.date):
|
||||||
course_title = frappe.db.get_value("LMS Course", req.course, "title")
|
course_title = frappe.db.get_value("LMS Course", req.course, "title")
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("You already have an evaluation on {0} at {1} for the course {2}.").format(
|
_("You already have an evaluation on {0} at {1} for the course {2}.").format(
|
||||||
@@ -34,69 +31,100 @@ class LMSCertificateRequest(Document):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_event(self):
|
|
||||||
calendar = frappe.db.get_value(
|
def schedule_evals():
|
||||||
"Google Calendar", {"user": self.evaluator, "enable": 1}, "name"
|
if frappe.db.get_single_value("LMS Settings", "send_calendar_invite_for_evaluations"):
|
||||||
|
one_hour_ago = add_to_date(get_datetime(), hours=-1)
|
||||||
|
evals = frappe.get_all(
|
||||||
|
"LMS Certificate Request",
|
||||||
|
{"creation": [">=", one_hour_ago], "google_meet_link": ["is", "not set"]},
|
||||||
|
["name", "member", "member_name", "evaluator", "date", "start_time", "end_time"],
|
||||||
)
|
)
|
||||||
|
for eval in evals:
|
||||||
|
setup_calendar_event(eval)
|
||||||
|
|
||||||
if calendar:
|
|
||||||
event = frappe.get_doc(
|
|
||||||
{
|
|
||||||
"doctype": "Event",
|
|
||||||
"subject": f"Evaluation of {self.member_name}",
|
|
||||||
"starts_on": f"{self.date} {self.start_time}",
|
|
||||||
"ends_on": f"{self.date} {self.end_time}",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
event.save()
|
|
||||||
|
|
||||||
participants = [self.member, self.evaluator]
|
def setup_calendar_event(eval):
|
||||||
for participant in participants:
|
calendar = frappe.db.get_value(
|
||||||
contact_name = frappe.db.get_value("Contact", {"email_id": participant}, "name")
|
"Google Calendar", {"user": eval.evaluator, "enable": 1}, "name"
|
||||||
frappe.get_doc(
|
)
|
||||||
{
|
|
||||||
"doctype": "Event Participants",
|
|
||||||
"reference_doctype": "Contact",
|
|
||||||
"reference_docname": contact_name,
|
|
||||||
"email": participant,
|
|
||||||
"parent": event.name,
|
|
||||||
"parenttype": "Event",
|
|
||||||
"parentfield": "event_participants",
|
|
||||||
}
|
|
||||||
).save()
|
|
||||||
|
|
||||||
event.reload()
|
if calendar:
|
||||||
event.update(
|
event = create_event(eval)
|
||||||
{
|
add_participants(eval, event)
|
||||||
"sync_with_google_calendar": 1,
|
update_meeting_details(eval, event, calendar)
|
||||||
"add_video_conferencing": 1,
|
|
||||||
"google_calendar": calendar,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
event.save()
|
|
||||||
|
def create_event(eval):
|
||||||
|
event = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Event",
|
||||||
|
"subject": f"Evaluation of {eval.member_name}",
|
||||||
|
"starts_on": f"{eval.date} {eval.start_time}",
|
||||||
|
"ends_on": f"{eval.date} {eval.end_time}",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
event.save()
|
||||||
|
return event
|
||||||
|
|
||||||
|
|
||||||
|
def add_participants(eval, event):
|
||||||
|
participants = [eval.member, eval.evaluator]
|
||||||
|
for participant in participants:
|
||||||
|
contact_name = frappe.db.get_value("Contact", {"email_id": participant}, "name")
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Event Participants",
|
||||||
|
"reference_doctype": "Contact",
|
||||||
|
"reference_docname": contact_name,
|
||||||
|
"email": participant,
|
||||||
|
"parent": event.name,
|
||||||
|
"parenttype": "Event",
|
||||||
|
"parentfield": "event_participants",
|
||||||
|
}
|
||||||
|
).save()
|
||||||
|
|
||||||
|
|
||||||
|
def update_meeting_details(eval, event, calendar):
|
||||||
|
event.reload()
|
||||||
|
event.update(
|
||||||
|
{
|
||||||
|
"sync_with_google_calendar": 1,
|
||||||
|
"add_video_conferencing": 1,
|
||||||
|
"google_calendar": calendar,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
event.save()
|
||||||
|
event.reload()
|
||||||
|
frappe.db.set_value(
|
||||||
|
"LMS Certificate Request", eval.name, "google_meet_link", event.google_meet_link
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def create_certificate_request(course, date, day, start_time, end_time):
|
def create_certificate_request(
|
||||||
|
course, date, day, start_time, end_time, class_name=None
|
||||||
|
):
|
||||||
is_member = frappe.db.exists(
|
is_member = frappe.db.exists(
|
||||||
{"doctype": "LMS Batch Membership", "course": course, "member": frappe.session.user}
|
{"doctype": "LMS Batch Membership", "course": course, "member": frappe.session.user}
|
||||||
)
|
)
|
||||||
|
|
||||||
if not is_member:
|
if not is_member:
|
||||||
return
|
return
|
||||||
|
eval = frappe.new_doc("LMS Certificate Request")
|
||||||
frappe.get_doc(
|
eval.update(
|
||||||
{
|
{
|
||||||
"doctype": "LMS Certificate Request",
|
|
||||||
"course": course,
|
"course": course,
|
||||||
|
"evaluator": get_evaluator(course, class_name),
|
||||||
"member": frappe.session.user,
|
"member": frappe.session.user,
|
||||||
"date": date,
|
"date": date,
|
||||||
"day": day,
|
"day": day,
|
||||||
"start_time": start_time,
|
"start_time": start_time,
|
||||||
"end_time": end_time,
|
"end_time": end_time,
|
||||||
}
|
}
|
||||||
).save(ignore_permissions=True)
|
)
|
||||||
|
eval.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -138,7 +138,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-06-22 15:57:25.190084",
|
"modified": "2023-07-13 11:30:09.097605",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Class",
|
"name": "LMS Class",
|
||||||
@@ -168,6 +168,18 @@
|
|||||||
"role": "Moderator",
|
"role": "Moderator",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Class Evaluator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
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
|
||||||
@@ -522,6 +521,14 @@ def has_course_moderator_role(member=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def has_course_evaluator_role(member=None):
|
||||||
|
return frappe.db.get_value(
|
||||||
|
"Has Role",
|
||||||
|
{"parent": member or frappe.session.user, "role": "Evaluator"},
|
||||||
|
"name",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_courses_under_review():
|
def get_courses_under_review():
|
||||||
return frappe.get_all(
|
return frappe.get_all(
|
||||||
"LMS Course",
|
"LMS Course",
|
||||||
@@ -753,3 +760,19 @@ def has_submitted_assessment(assessment, type, member=None):
|
|||||||
def has_graded_assessment(submission):
|
def has_graded_assessment(submission):
|
||||||
status = frappe.db.get_value("LMS Assignment Submission", submission, "status")
|
status = frappe.db.get_value("LMS Assignment Submission", submission, "status")
|
||||||
return False if status == "Not Graded" else True
|
return False if status == "Not Graded" else True
|
||||||
|
|
||||||
|
|
||||||
|
def get_evaluator(course, class_name=None):
|
||||||
|
evaluator = None
|
||||||
|
|
||||||
|
if class_name:
|
||||||
|
evaluator = frappe.db.get_value(
|
||||||
|
"Class Course",
|
||||||
|
{"parent": class_name, "course": course},
|
||||||
|
"evaluator",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not evaluator:
|
||||||
|
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
||||||
|
|
||||||
|
return evaluator
|
||||||
|
|||||||
@@ -56,3 +56,8 @@ lms.patches.v0_0.convert_course_description_to_html #11-05-2023
|
|||||||
lms.patches.v1_0.rename_assignment_doctype
|
lms.patches.v1_0.rename_assignment_doctype
|
||||||
execute:frappe.permissions.reset_perms("LMS Assignment")
|
execute:frappe.permissions.reset_perms("LMS Assignment")
|
||||||
execute:frappe.permissions.reset_perms("LMS Quiz")
|
execute:frappe.permissions.reset_perms("LMS Quiz")
|
||||||
|
lms.patches.v1_0.create_class_evaluator_role
|
||||||
|
execute:frappe.permissions.reset_perms("LMS Class")
|
||||||
|
execute:frappe.permissions.reset_perms("Course Evaluator")
|
||||||
|
execute:frappe.permissions.reset_perms("LMS Certificate Request")
|
||||||
|
execute:frappe.permissions.reset_perms("LMS Certificate Evaluation")
|
||||||
5
lms/patches/v1_0/create_class_evaluator_role.py
Normal file
5
lms/patches/v1_0/create_class_evaluator_role.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from lms.install import create_evaluator_role
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
create_evaluator_role()
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
setup_file_size();
|
setup_file_size();
|
||||||
pin_header();
|
pin_header();
|
||||||
|
setup_router();
|
||||||
|
|
||||||
$(".join-batch").click((e) => {
|
$(".join-batch").click((e) => {
|
||||||
join_course(e);
|
join_course(e);
|
||||||
@@ -42,6 +43,14 @@ frappe.ready(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setup_router = () => {
|
||||||
|
frappe.router = {
|
||||||
|
slug(name) {
|
||||||
|
return name.toLowerCase().replace(/ /g, "-");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const pin_header = () => {
|
const pin_header = () => {
|
||||||
const el = document.querySelector(".sticky");
|
const el = document.querySelector(".sticky");
|
||||||
if (el) {
|
if (el) {
|
||||||
|
|||||||
@@ -204,7 +204,7 @@
|
|||||||
{% if class_courses | length %}
|
{% if class_courses | length %}
|
||||||
<div class="cards-parent">
|
<div class="cards-parent">
|
||||||
{% for course in class_courses %}
|
{% for course in class_courses %}
|
||||||
<div>
|
<div class="h-100">
|
||||||
{{ widgets.CourseCard(course=course, read_only=False) }}
|
{{ widgets.CourseCard(course=course, read_only=False) }}
|
||||||
<button class="btn icon-btn btn-default btn-block btn-remove-course" data-course="{{ course.name }}">
|
<button class="btn icon-btn btn-default btn-block btn-remove-course" data-course="{{ course.name }}">
|
||||||
<svg class="icon icon-sm">
|
<svg class="icon icon-sm">
|
||||||
@@ -271,7 +271,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% for student in class_students %}
|
{% for student in class_students %}
|
||||||
{% set allow_progress = is_moderator or student.student == frappe.session.user %}
|
{% set allow_progress = is_moderator or student.student == frappe.session.user or is_evaluator %}
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="data-row row">
|
<div class="data-row row">
|
||||||
<a class="col grid-static-col {% if allow_progress %} clickable {% endif %}" {% if allow_progress %} href="/classes/{{ class_info.name }}/students/{{ student.username }}" {% endif %}>
|
<a class="col grid-static-col {% if allow_progress %} clickable {% endif %}" {% if allow_progress %} href="/classes/{{ class_info.name }}/students/{{ student.username }}" {% endif %}>
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ const show_student_modal = () => {
|
|||||||
filters: {
|
filters: {
|
||||||
ignore_user_type: 1,
|
ignore_user_type: 1,
|
||||||
},
|
},
|
||||||
|
filter_description: " ",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
primary_action_label: __("Add"),
|
primary_action_label: __("Add"),
|
||||||
@@ -448,13 +449,10 @@ const show_assessment_modal = (e) => {
|
|||||||
label: __("Assessment Type"),
|
label: __("Assessment Type"),
|
||||||
fieldname: "assessment_type",
|
fieldname: "assessment_type",
|
||||||
reqd: 1,
|
reqd: 1,
|
||||||
get_query: () => {
|
filters: {
|
||||||
return {
|
name: ["in", ["LMS Assignment", "LMS Quiz"]],
|
||||||
filters: {
|
|
||||||
name: ["in", ["LMS Assignment", "LMS Quiz"]],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
filter_description: " ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldtype: "Dynamic Link",
|
fieldtype: "Dynamic Link",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from frappe.utils import getdate
|
|||||||
from lms.www.utils import get_assessments
|
from lms.www.utils import get_assessments
|
||||||
from lms.lms.utils import (
|
from lms.lms.utils import (
|
||||||
has_course_moderator_role,
|
has_course_moderator_role,
|
||||||
|
has_course_evaluator_role,
|
||||||
get_course_progress,
|
get_course_progress,
|
||||||
has_submitted_assessment,
|
has_submitted_assessment,
|
||||||
has_graded_assessment,
|
has_graded_assessment,
|
||||||
@@ -14,6 +15,7 @@ def get_context(context):
|
|||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
class_name = frappe.form_dict["classname"]
|
class_name = frappe.form_dict["classname"]
|
||||||
context.is_moderator = has_course_moderator_role()
|
context.is_moderator = has_course_moderator_role()
|
||||||
|
context.is_evaluator = has_course_evaluator_role()
|
||||||
|
|
||||||
context.class_info = frappe.db.get_value(
|
context.class_info = frappe.db.get_value(
|
||||||
"LMS Class",
|
"LMS Class",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<div class="page-title">
|
<div class="page-title">
|
||||||
{{ _("{0}").format(student.full_name) }}
|
{{ _("{0}").format(student.full_name) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="vertically-center small">
|
<div class="vertically-center">
|
||||||
<a class="dark-links" href="/classes">
|
<a class="dark-links" href="/classes">
|
||||||
{{ _("All Classes") }}
|
{{ _("All Classes") }}
|
||||||
</a>
|
</a>
|
||||||
@@ -30,21 +30,27 @@
|
|||||||
{{ class_info.name }}
|
{{ class_info.name }}
|
||||||
</a>
|
</a>
|
||||||
<img class="icon icon-sm mr-0" src="/assets/lms/icons/chevron-right.svg">
|
<img class="icon icon-sm mr-0" src="/assets/lms/icons/chevron-right.svg">
|
||||||
<span class="breadcrumb-destination">{{ _("Student Progress").format(student.full_name) }}</span>
|
<span class="breadcrumb-destination">
|
||||||
|
{{ _("Student Progress").format(student.full_name) }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if is_moderator %}
|
|
||||||
<div class="align-self-center">
|
<div class="align-self-center">
|
||||||
<a class="btn btn-default btn-sm mr-2" href="/users/{{ student.username }}">
|
<a class="btn btn-default btn-sm" href="/users/{{ student.username }}">
|
||||||
{{ _("View Profile") }}
|
{{ _("View Profile") }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-primary btn-sm btn-evaluate" href=/evaluation/new?member={{student.name}}&date={{frappe.utils.getdate()}}&class={{class_info.name}}">
|
{% if student.name == frappe.session.user %}
|
||||||
|
<button class="btn btn-default btn-sm btn-schedule-eval ml-2">
|
||||||
|
{{ _("Schedule Evaluation") }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_moderator %}
|
||||||
|
<a class="btn btn-primary btn-sm btn-evaluate ml-2" href=/evaluation/new?member={{student.name}}&date={{frappe.utils.getdate()}}&class={{class_info.name}}">
|
||||||
{{ _("Evaluate") }}
|
{{ _("Evaluate") }}
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -52,59 +58,132 @@
|
|||||||
|
|
||||||
|
|
||||||
{% macro Progress(class_info, student) %}
|
{% macro Progress(class_info, student) %}
|
||||||
{% if assessments | length %}
|
{{ UpcomingEvals(upcoming_evals) }}
|
||||||
<article class="form-grid">
|
{{ Assessments(class_info, student) }}
|
||||||
<div class="grid-heading-row">
|
{% endmacro %}
|
||||||
<div class="grid-row">
|
|
||||||
<div class="data-row row">
|
|
||||||
<div class="col grid-static-col">
|
|
||||||
{{ _("Assessment") }}
|
|
||||||
</div>
|
|
||||||
<div class="col grid-static-col col-xs-2">
|
|
||||||
{{ _("Type") }}
|
|
||||||
</div>
|
|
||||||
<div class="col grid-static-col col-xs-2">
|
|
||||||
{{ _("Status/Score") }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% for assessment in assessments %}
|
|
||||||
{% set has_access = is_moderator and assessment.submission or frappe.session.user == student.name %}
|
|
||||||
<div class="grid-row">
|
|
||||||
<div class="data-row row">
|
|
||||||
<a class="col grid-static-col {% if has_access %} clickable {% endif %}" {% if has_access %} href="{{ assessment.url }}" {% endif %}>
|
|
||||||
{{ assessment.title }}
|
|
||||||
</a>
|
|
||||||
<div class="col grid-static-col col-xs-2">
|
|
||||||
{{ (assessment.assessment_type).split("LMS ")[1] }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col grid-static-col col-xs-2 mb-2">
|
{% macro UpcomingEvals(upcoming_evals) %}
|
||||||
{% if assessment.submission %}
|
<div class="mb-8">
|
||||||
{% if assessment.assessment_type == "LMS Assignment" %}
|
<div class="bold-heading mb-2">
|
||||||
{% set status = assessment.submission.status %}
|
{{ _("Upcoming Evaluations") }}
|
||||||
{% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %}
|
</div>
|
||||||
<div class="indicator-pill {{ color }}">
|
{% if upcoming_evals | length %}
|
||||||
{{ status }}
|
<article class="cards-parent">
|
||||||
</div>
|
{% for eval in upcoming_evals %}
|
||||||
{% else %}
|
<div class="common-card-style column-card">
|
||||||
<div>
|
<div class="flex align-center justify-between">
|
||||||
{{ assessment.submission.score }}
|
<div class="bold-heading">
|
||||||
</div>
|
{{ eval.course_title }}
|
||||||
{% endif %}
|
</div>
|
||||||
{% else %}
|
{% if eval.google_meet_link %}
|
||||||
<div class="indicator-pill red">
|
<a class="btn btn-default btn-sm pull-right" href="{{ eval.google_meet_link }}">
|
||||||
{{ _("Not Attempted") }}
|
{{ _("Join") }}
|
||||||
</div>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="vertically-center">
|
||||||
|
<svg class="icon icon-sm mr-1">
|
||||||
|
<use href="#icon-calendar"></use>
|
||||||
|
</svg>
|
||||||
|
<span>
|
||||||
|
{{ frappe.utils.format_date(eval.date, "medium") }} -
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ frappe.utils.format_time(eval.start_time, "hh:mm a") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="field-label">
|
||||||
|
{{ _("Evaluator") }}:
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{{ eval.evaluator_name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</article>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted"> {{ _("No Upcoming Evaluations") }} </p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro Assessments(class_info, student) %}
|
||||||
|
<div class="mb-8">
|
||||||
|
<div class="bold-heading mb-2">
|
||||||
|
{{ _("Assessments") }}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% if assessments | length %}
|
||||||
</article>
|
<article class="form-grid">
|
||||||
{% else %}
|
<div class="grid-heading-row">
|
||||||
<p class="text-muted mt-3"> {{ _("No Assessments") }} </p>
|
<div class="grid-row">
|
||||||
{% endif %}
|
<div class="data-row row">
|
||||||
{% endmacro %}
|
<div class="col grid-static-col">
|
||||||
|
{{ _("Assessment") }}
|
||||||
|
</div>
|
||||||
|
<div class="col grid-static-col col-xs-2">
|
||||||
|
{{ _("Type") }}
|
||||||
|
</div>
|
||||||
|
<div class="col grid-static-col col-xs-2">
|
||||||
|
{{ _("Status/Score") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% for assessment in assessments %}
|
||||||
|
{% set has_access = is_moderator and assessment.submission or frappe.session.user == student.name %}
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="data-row row">
|
||||||
|
<a class="col grid-static-col {% if has_access %} clickable {% endif %}" {% if has_access %} href="{{ assessment.url }}" {% endif %}>
|
||||||
|
{{ assessment.title }}
|
||||||
|
</a>
|
||||||
|
<div class="col grid-static-col col-xs-2">
|
||||||
|
{{ (assessment.assessment_type).split("LMS ")[1] }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col grid-static-col col-xs-2 mb-2">
|
||||||
|
{% if assessment.submission %}
|
||||||
|
{% if assessment.assessment_type == "LMS Assignment" %}
|
||||||
|
{% set status = assessment.submission.status %}
|
||||||
|
{% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %}
|
||||||
|
<div class="indicator-pill {{ color }}">
|
||||||
|
{{ status }}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div>
|
||||||
|
{{ assessment.submission.score }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<div class="indicator-pill red">
|
||||||
|
{{ _("Not Attempted") }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</article>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted"> {{ _("No Assessments") }} </p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{%- block script %}
|
||||||
|
{{ super() }}
|
||||||
|
<script>
|
||||||
|
frappe.boot.user = {
|
||||||
|
"can_create": [],
|
||||||
|
"can_select": ["LMS Course"],
|
||||||
|
"can_read": ["LMS Course"]
|
||||||
|
};
|
||||||
|
let courses = {{ courses | json }};
|
||||||
|
let class_name = "{{ class_info.name }}";
|
||||||
|
</script>
|
||||||
|
{{ include_script('controls.bundle.js') }}
|
||||||
|
{% endblock %}
|
||||||
@@ -2,4 +2,130 @@ frappe.ready(() => {
|
|||||||
$(".clickable-row").click((e) => {
|
$(".clickable-row").click((e) => {
|
||||||
window.location.href = $(e.currentTarget).data("href");
|
window.location.href = $(e.currentTarget).data("href");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".btn-schedule-eval").click((e) => {
|
||||||
|
open_evaluation_form(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", ".slot", (e) => {
|
||||||
|
mark_active_slot(e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const open_evaluation_form = (e) => {
|
||||||
|
this.eval_form = new frappe.ui.Dialog({
|
||||||
|
title: __("Schedule Evaluation"),
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldtype: "Link",
|
||||||
|
fieldname: "course",
|
||||||
|
label: __("Course"),
|
||||||
|
options: "LMS Course",
|
||||||
|
reqd: 1,
|
||||||
|
filters: {
|
||||||
|
name: ["in", courses],
|
||||||
|
},
|
||||||
|
filter_description: " ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "Date",
|
||||||
|
fieldname: "date",
|
||||||
|
label: __("Date"),
|
||||||
|
reqd: 1,
|
||||||
|
min_date: new Date(
|
||||||
|
frappe.datetime.add_days(frappe.datetime.get_today(), 1)
|
||||||
|
),
|
||||||
|
change: () => {
|
||||||
|
get_slots();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "HTML",
|
||||||
|
fieldname: "slots",
|
||||||
|
label: __("Slots"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primary_action: (values) => {
|
||||||
|
submit_evaluation_form(values);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.eval_form.show();
|
||||||
|
setTimeout(() => {
|
||||||
|
$(".modal-body").css("min-height", "300px");
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_slots = () => {
|
||||||
|
frappe.call({
|
||||||
|
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
||||||
|
args: {
|
||||||
|
course: this.eval_form.get_value("course"),
|
||||||
|
date: this.eval_form.get_value("date"),
|
||||||
|
class_name: class_name,
|
||||||
|
},
|
||||||
|
callback: (r) => {
|
||||||
|
if (r.message) {
|
||||||
|
display_slots(r.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const display_slots = (slots) => {
|
||||||
|
let slot_html = "";
|
||||||
|
let day = moment(this.eval_form.get_value("date")).format("dddd");
|
||||||
|
|
||||||
|
slots.forEach((slot) => {
|
||||||
|
if (slot.day == day) {
|
||||||
|
slot_html += `<div class="btn btn-sm btn-default slot" data-day="${
|
||||||
|
slot.day
|
||||||
|
}"
|
||||||
|
data-start="${slot.start_time}" data-end="${slot.end_time}">
|
||||||
|
${moment(slot.start_time, "hh:mm").format("hh:mm a")} -
|
||||||
|
${moment(slot.end_time, "hh:mm").format("hh:mm a")}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!slot_html) {
|
||||||
|
slot_html = `<div class="alert alert-danger" role="alert">
|
||||||
|
No slots available for this date.
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("[data-fieldname='slots']").html(slot_html);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mark_active_slot = (e) => {
|
||||||
|
$(".slot").removeClass("btn-outline-primary");
|
||||||
|
$(e.currentTarget).addClass("btn-outline-primary");
|
||||||
|
this.current_slot = $(e.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit_evaluation_form = (values) => {
|
||||||
|
if (!this.current_slot) {
|
||||||
|
frappe.throw(__("Please select a slot"));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eval_form.hide();
|
||||||
|
frappe.call({
|
||||||
|
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_certificate_request",
|
||||||
|
args: {
|
||||||
|
course: values.course,
|
||||||
|
date: values.date,
|
||||||
|
start_time: this.current_slot.data("start"),
|
||||||
|
end_time: this.current_slot.data("end"),
|
||||||
|
day: this.current_slot.data("day"),
|
||||||
|
class_name: class_name,
|
||||||
|
},
|
||||||
|
callback: (r) => {
|
||||||
|
frappe.show_alert({
|
||||||
|
message: __("Evaluation scheduled successfully"),
|
||||||
|
indicator: "green",
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from lms.lms.utils import has_course_moderator_role
|
from lms.lms.utils import has_course_moderator_role, has_course_evaluator_role
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from lms.www.utils import get_assessments
|
from lms.www.utils import get_assessments
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ def get_context(context):
|
|||||||
student = frappe.form_dict["username"]
|
student = frappe.form_dict["username"]
|
||||||
class_name = frappe.form_dict["classname"]
|
class_name = frappe.form_dict["classname"]
|
||||||
context.is_moderator = has_course_moderator_role()
|
context.is_moderator = has_course_moderator_role()
|
||||||
|
context.is_evaluator = has_course_evaluator_role()
|
||||||
|
|
||||||
context.student = frappe.db.get_value(
|
context.student = frappe.db.get_value(
|
||||||
"User",
|
"User",
|
||||||
@@ -17,8 +18,36 @@ def get_context(context):
|
|||||||
["first_name", "full_name", "name", "last_active", "username"],
|
["first_name", "full_name", "name", "last_active", "username"],
|
||||||
as_dict=True,
|
as_dict=True,
|
||||||
)
|
)
|
||||||
|
if (
|
||||||
|
not context.is_moderator
|
||||||
|
and not context.is_evaluator
|
||||||
|
and not context.student.name == frappe.session.user
|
||||||
|
):
|
||||||
|
raise frappe.PermissionError(_("You don't have permission to access this page."))
|
||||||
|
|
||||||
context.class_info = frappe.db.get_value(
|
context.class_info = frappe.db.get_value(
|
||||||
"LMS Class", class_name, ["name"], as_dict=True
|
"LMS Class", class_name, ["name"], as_dict=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
context.courses = frappe.get_all(
|
||||||
|
"Class Course", {"parent": class_name}, pluck="course"
|
||||||
|
)
|
||||||
|
|
||||||
context.assessments = get_assessments(class_name, context.student.name)
|
context.assessments = get_assessments(class_name, context.student.name)
|
||||||
|
|
||||||
|
upcoming_evals = frappe.get_all(
|
||||||
|
"LMS certificate Request",
|
||||||
|
{
|
||||||
|
"member": context.student.name,
|
||||||
|
"course": ["in", context.courses],
|
||||||
|
"date": [">=", frappe.utils.nowdate()],
|
||||||
|
},
|
||||||
|
["date", "start_time", "course", "evaluator", "google_meet_link"],
|
||||||
|
order_by="date",
|
||||||
|
)
|
||||||
|
|
||||||
|
for evals in upcoming_evals:
|
||||||
|
evals.course_title = frappe.db.get_value("LMS Course", evals.course, "title")
|
||||||
|
evals.evaluator_name = frappe.db.get_value("User", evals.evaluator, "full_name")
|
||||||
|
|
||||||
|
context.upcoming_evals = upcoming_evals
|
||||||
|
|||||||
Reference in New Issue
Block a user