diff --git a/lms/hooks.py b/lms/hooks.py index b0e04048..1bb0f1f0 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -103,11 +103,11 @@ doc_events = { # Scheduled Tasks # --------------- -# scheduler_events = { -# "daily": [ -# "erpnext.stock.reorder_item.reorder_item" -# ] -# } +scheduler_events = { + "hourly": [ + "lms.lms.doctype.lms_certificate_request.lms_certificate_request.schedule_evals" + ] +} fixtures = ["Custom Field", "Function", "Industry"] diff --git a/lms/install.py b/lms/install.py index 8265d694..fca317b0 100644 --- a/lms/install.py +++ b/lms/install.py @@ -52,6 +52,7 @@ def before_uninstall(): def create_lms_roles(): create_course_creator_role() create_moderator_role() + create_evaluator_role() def delete_lms_roles(): @@ -91,6 +92,19 @@ def create_moderator_role(): 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(): fields = [ "user_category", diff --git a/lms/lms/doctype/class_course/class_course.json b/lms/lms/doctype/class_course/class_course.json index f53619c4..6412b74a 100644 --- a/lms/lms/doctype/class_course/class_course.json +++ b/lms/lms/doctype/class_course/class_course.json @@ -7,7 +7,8 @@ "engine": "InnoDB", "field_order": [ "course", - "title" + "title", + "evaluator" ], "fields": [ { @@ -23,14 +24,21 @@ "fieldname": "title", "fieldtype": "Data", "in_list_view": 1, - "label": "Title", + "label": "Course Title", "read_only": 1 + }, + { + "fieldname": "evaluator", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Evaluator", + "options": "Course Evaluator" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-11-11 15:51:45.560864", + "modified": "2023-07-13 17:51:36.278393", "modified_by": "Administrator", "module": "LMS", "name": "Class Course", diff --git a/lms/lms/doctype/course_evaluator/course_evaluator.json b/lms/lms/doctype/course_evaluator/course_evaluator.json index 07cbcb20..cac4f195 100644 --- a/lms/lms/doctype/course_evaluator/course_evaluator.json +++ b/lms/lms/doctype/course_evaluator/course_evaluator.json @@ -27,7 +27,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-04-01 15:14:03.300260", + "modified": "2023-07-13 11:30:22.641076", "modified_by": "Administrator", "module": "LMS", "name": "Course Evaluator", @@ -45,6 +45,30 @@ "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 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Class Evaluator", + "share": 1, + "write": 1 } ], "sort_field": "modified", diff --git a/lms/lms/doctype/course_evaluator/course_evaluator.py b/lms/lms/doctype/course_evaluator/course_evaluator.py index 7f151612..a7ed55a2 100644 --- a/lms/lms/doctype/course_evaluator/course_evaluator.py +++ b/lms/lms/doctype/course_evaluator/course_evaluator.py @@ -4,6 +4,7 @@ import frappe from frappe import _ from frappe.model.document import Document +from lms.lms.utils import get_evaluator class CourseEvaluator(Document): @@ -36,13 +37,16 @@ class CourseEvaluator(Document): @frappe.whitelist() -def get_schedule(course, date): - evaluator = frappe.db.get_value("LMS Course", course, "evaluator") +def get_schedule(course, date, class_name=None): + evaluator = get_evaluator(course, class_name) + all_slots = frappe.get_all( "Evaluator Schedule", filters={"parent": evaluator}, fields=["day", "start_time", "end_time"], + order_by="start_time", ) + booked_slots = frappe.get_all( "LMS Certificate Request", filters={"evaluator": evaluator, "date": date}, diff --git a/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json b/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json index 87960137..fbc3af60 100644 --- a/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json +++ b/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json @@ -104,7 +104,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-02-22 16:00:34.361934", + "modified": "2023-07-13 11:30:53.432076", "modified_by": "Administrator", "module": "LMS", "name": "LMS Certificate Evaluation", @@ -121,6 +121,18 @@ "role": "System Manager", "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", diff --git a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json index 3532d24b..deb300ce 100644 --- a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json +++ b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json @@ -14,6 +14,7 @@ "section_break_lifi", "date", "day", + "google_meet_link", "column_break_ddyh", "start_time", "end_time" @@ -38,6 +39,7 @@ }, { "fetch_from": "course.evaluator", + "fetch_if_empty": 1, "fieldname": "evaluator", "fieldtype": "Link", "label": "Evaluator", @@ -89,11 +91,17 @@ { "fieldname": "column_break_ddyh", "fieldtype": "Column Break" + }, + { + "fieldname": "google_meet_link", + "fieldtype": "Data", + "label": "Google Meet Link", + "read_only": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-02-28 19:53:17.534351", + "modified": "2023-07-21 16:00:11.795521", "modified_by": "Administrator", "module": "LMS", "name": "LMS Certificate Request", @@ -111,6 +119,30 @@ "select": 1, "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 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Moderator", + "share": 1, + "write": 1 } ], "sort_field": "modified", diff --git a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py index 0570d615..475643f1 100644 --- a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py +++ b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.py @@ -5,26 +5,23 @@ import frappe from frappe import _ from frappe.model.document import Document 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): def validate(self): 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): existing_requests = frappe.get_all( "LMS Certificate Request", - {"member": self.member, "course": self.course}, + {"member": self.member, "course": self.course, "name": ["!=", self.name]}, ["date", "start_time", "course"], ) 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") frappe.throw( _("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( - "Google Calendar", {"user": self.evaluator, "enable": 1}, "name" + +def schedule_evals(): + 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] - 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 setup_calendar_event(eval): + calendar = frappe.db.get_value( + "Google Calendar", {"user": eval.evaluator, "enable": 1}, "name" + ) - event.reload() - event.update( - { - "sync_with_google_calendar": 1, - "add_video_conferencing": 1, - "google_calendar": calendar, - } - ) + if calendar: + event = create_event(eval) + add_participants(eval, event) + update_meeting_details(eval, event, 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() -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( {"doctype": "LMS Batch Membership", "course": course, "member": frappe.session.user} ) if not is_member: return - - frappe.get_doc( + eval = frappe.new_doc("LMS Certificate Request") + eval.update( { - "doctype": "LMS Certificate Request", "course": course, + "evaluator": get_evaluator(course, class_name), "member": frappe.session.user, "date": date, "day": day, "start_time": start_time, "end_time": end_time, } - ).save(ignore_permissions=True) + ) + eval.save() @frappe.whitelist() diff --git a/lms/lms/doctype/lms_class/lms_class.json b/lms/lms/doctype/lms_class/lms_class.json index 3f3b61e3..7253100b 100644 --- a/lms/lms/doctype/lms_class/lms_class.json +++ b/lms/lms/doctype/lms_class/lms_class.json @@ -138,7 +138,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-06-22 15:57:25.190084", + "modified": "2023-07-13 11:30:09.097605", "modified_by": "Administrator", "module": "LMS", "name": "LMS Class", @@ -168,6 +168,18 @@ "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", diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 6e2d981d..efece300 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -1,6 +1,5 @@ import re import string - import frappe from frappe import _ 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(): return frappe.get_all( "LMS Course", @@ -753,3 +760,19 @@ def has_submitted_assessment(assessment, type, member=None): def has_graded_assessment(submission): status = frappe.db.get_value("LMS Assignment Submission", submission, "status") 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 diff --git a/lms/patches.txt b/lms/patches.txt index 22e92dab..f0d194df 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -56,3 +56,8 @@ lms.patches.v0_0.convert_course_description_to_html #11-05-2023 lms.patches.v1_0.rename_assignment_doctype execute:frappe.permissions.reset_perms("LMS Assignment") 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") \ No newline at end of file diff --git a/lms/patches/v1_0/create_class_evaluator_role.py b/lms/patches/v1_0/create_class_evaluator_role.py new file mode 100644 index 00000000..ffabe2ea --- /dev/null +++ b/lms/patches/v1_0/create_class_evaluator_role.py @@ -0,0 +1,5 @@ +from lms.install import create_evaluator_role + + +def execute(): + create_evaluator_role() diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index 2eeb43ae..62ad81f3 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -1,6 +1,7 @@ frappe.ready(() => { setup_file_size(); pin_header(); + setup_router(); $(".join-batch").click((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 el = document.querySelector(".sticky"); if (el) { diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index 3193e05a..c81d56a1 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -180,7 +180,7 @@ {% if class_courses | length %}
{% for course in class_courses %} -
+
{{ widgets.CourseCard(course=course, read_only=False) }}
{% 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 %}
diff --git a/lms/www/classes/class.js b/lms/www/classes/class.js index 0c8d99d6..a8a45a9e 100644 --- a/lms/www/classes/class.js +++ b/lms/www/classes/class.js @@ -374,6 +374,7 @@ const show_student_modal = () => { filters: { ignore_user_type: 1, }, + filter_description: " ", }, ], primary_action_label: __("Add"), @@ -448,13 +449,10 @@ const show_assessment_modal = (e) => { label: __("Assessment Type"), fieldname: "assessment_type", reqd: 1, - get_query: () => { - return { - filters: { - name: ["in", ["LMS Assignment", "LMS Quiz"]], - }, - }; + filters: { + name: ["in", ["LMS Assignment", "LMS Quiz"]], }, + filter_description: " ", }, { fieldtype: "Dynamic Link", diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py index 59932854..74b4b5a3 100644 --- a/lms/www/classes/class.py +++ b/lms/www/classes/class.py @@ -4,6 +4,7 @@ from frappe.utils import getdate from lms.www.utils import get_assessments from lms.lms.utils import ( has_course_moderator_role, + has_course_evaluator_role, get_course_progress, has_submitted_assessment, has_graded_assessment, @@ -14,6 +15,7 @@ def get_context(context): context.no_cache = 1 class_name = frappe.form_dict["classname"] context.is_moderator = has_course_moderator_role() + context.is_evaluator = has_course_evaluator_role() context.class_info = frappe.db.get_value( "LMS Class", diff --git a/lms/www/classes/progress.html b/lms/www/classes/progress.html index 84d030b9..2639eda7 100644 --- a/lms/www/classes/progress.html +++ b/lms/www/classes/progress.html @@ -21,7 +21,7 @@
{{ _("{0}").format(student.full_name) }}
-
+
{{ _("All Classes") }} @@ -30,21 +30,27 @@ {{ class_info.name }} - {{ _("Student Progress").format(student.full_name) }} + + {{ _("Student Progress").format(student.full_name) }} +
- {% if is_moderator %} - {% endif %} -
@@ -52,59 +58,132 @@ {% macro Progress(class_info, student) %} -{% if assessments | length %} -
-
-
-
-
- {{ _("Assessment") }} -
-
- {{ _("Type") }} -
-
- {{ _("Status/Score") }} -
-
-
-
- {% for assessment in assessments %} - {% set has_access = is_moderator and assessment.submission or frappe.session.user == student.name %} -
-
- - {{ assessment.title }} - -
- {{ (assessment.assessment_type).split("LMS ")[1] }} -
+ {{ UpcomingEvals(upcoming_evals) }} + {{ Assessments(class_info, student) }} +{% endmacro %} -
- {% 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" %} -
- {{ status }} -
- {% else %} -
- {{ assessment.submission.score }} -
- {% endif %} - {% else %} -
- {{ _("Not Attempted") }} -
+{% macro UpcomingEvals(upcoming_evals) %} +
+
+ {{ _("Upcoming Evaluations") }} +
+ {% if upcoming_evals | length %} +
+ {% for eval in upcoming_evals %} +
+
+
+ {{ eval.course_title }} +
+ {% if eval.google_meet_link %} + + {{ _("Join") }} + {% endif %}
+
+ + + + + {{ frappe.utils.format_date(eval.date, "medium") }} -  + + + {{ frappe.utils.format_time(eval.start_time, "hh:mm a") }} + +
+
+ + {{ _("Evaluator") }}: + + + {{ eval.evaluator_name }} + +
+ {% endfor %} +
+ {% else %} +

{{ _("No Upcoming Evaluations") }}

+ {% endif %} +
+{% endmacro %} + +{% macro Assessments(class_info, student) %} +
+
+ {{ _("Assessments") }}
- {% endfor %} -
-{% else %} -

{{ _("No Assessments") }}

-{% endif %} -{% endmacro %} \ No newline at end of file + {% if assessments | length %} +
+
+
+
+
+ {{ _("Assessment") }} +
+
+ {{ _("Type") }} +
+
+ {{ _("Status/Score") }} +
+
+
+
+ {% for assessment in assessments %} + {% set has_access = is_moderator and assessment.submission or frappe.session.user == student.name %} +
+
+ + {{ assessment.title }} + +
+ {{ (assessment.assessment_type).split("LMS ")[1] }} +
+ +
+ {% 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" %} +
+ {{ status }} +
+ {% else %} +
+ {{ assessment.submission.score }} +
+ {% endif %} + {% else %} +
+ {{ _("Not Attempted") }} +
+ {% endif %} +
+ +
+
+ {% endfor %} +
+ {% else %} +

{{ _("No Assessments") }}

+ {% endif %} +
+ +{% endmacro %} + +{%- block script %} + {{ super() }} + + {{ include_script('controls.bundle.js') }} +{% endblock %} \ No newline at end of file diff --git a/lms/www/classes/progress.js b/lms/www/classes/progress.js index 6c136c9a..44c4268b 100644 --- a/lms/www/classes/progress.js +++ b/lms/www/classes/progress.js @@ -2,4 +2,130 @@ frappe.ready(() => { $(".clickable-row").click((e) => { 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 += `
+ ${moment(slot.start_time, "hh:mm").format("hh:mm a")} - + ${moment(slot.end_time, "hh:mm").format("hh:mm a")} +
`; + } + }); + + if (!slot_html) { + slot_html = ``; + } + + $("[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); + }, + }); +}; diff --git a/lms/www/classes/progress.py b/lms/www/classes/progress.py index be922dd1..eef9cbee 100644 --- a/lms/www/classes/progress.py +++ b/lms/www/classes/progress.py @@ -1,5 +1,5 @@ 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 lms.www.utils import get_assessments @@ -10,6 +10,7 @@ def get_context(context): student = frappe.form_dict["username"] class_name = frappe.form_dict["classname"] context.is_moderator = has_course_moderator_role() + context.is_evaluator = has_course_evaluator_role() context.student = frappe.db.get_value( "User", @@ -17,8 +18,36 @@ def get_context(context): ["first_name", "full_name", "name", "last_active", "username"], 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( "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) + + 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