diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 630341d4..aafbfa01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: - name: setup node uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '18' check-latest: true - name: setup cache for bench uses: actions/cache@v2 diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 0d0d96bc..d59e5acc 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -50,7 +50,7 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 check-latest: true - name: Add to Hosts diff --git a/lms/lms/doctype/lms_assignment/lms_assignment.json b/lms/lms/doctype/lms_assignment/lms_assignment.json index e7659c04..6cb778a1 100644 --- a/lms/lms/doctype/lms_assignment/lms_assignment.json +++ b/lms/lms/doctype/lms_assignment/lms_assignment.json @@ -46,7 +46,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-05-29 14:50:55.259990", + "modified": "2023-06-26 18:09:29.809564", "modified_by": "Administrator", "module": "LMS", "name": "LMS Assignment", @@ -64,9 +64,23 @@ "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": [] + "states": [], + "title_field": "title" } \ No newline at end of file diff --git a/lms/lms/doctype/lms_class/lms_class.json b/lms/lms/doctype/lms_class/lms_class.json index 6a69486d..3f3b61e3 100644 --- a/lms/lms/doctype/lms_class/lms_class.json +++ b/lms/lms/doctype/lms_class/lms_class.json @@ -50,7 +50,8 @@ { "fieldname": "description", "fieldtype": "Small Text", - "label": "Description" + "label": "Description", + "reqd": 1 }, { "fieldname": "section_break_6", @@ -137,7 +138,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-06-15 12:30:26.929156", + "modified": "2023-06-22 15:57:25.190084", "modified_by": "Administrator", "module": "LMS", "name": "LMS Class", diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py index 634f41e6..862bec75 100644 --- a/lms/lms/doctype/lms_class/lms_class.py +++ b/lms/lms/doctype/lms_class/lms_class.py @@ -2,19 +2,21 @@ # For license information, please see license.txt import frappe -from frappe.model.document import Document -from frappe import _ -from frappe.utils import cint, format_date, format_datetime import requests import base64 import json +from frappe import _ +from frappe.model.document import Document +from frappe.utils import cint, format_date, format_datetime class LMSClass(Document): def validate(self): if self.seat_count: self.validate_seats_left() + self.validate_duplicate_courses() self.validate_duplicate_students() + self.validate_duplicate_assessments() self.validate_membership() def validate_duplicate_students(self): @@ -27,6 +29,28 @@ class LMSClass(Document): ) ) + def validate_duplicate_courses(self): + courses = [row.course for row in self.courses] + duplicates = {course for course in courses if courses.count(course) > 1} + if len(duplicates): + title = frappe.db.get_value("LMS Course", next(iter(duplicates)), "title") + frappe.throw( + _("Course {0} has already been added to this class.").format(frappe.bold(title)) + ) + + def validate_duplicate_assessments(self): + assessments = [row.assessment_name for row in self.assessment] + for assessment in self.assessment: + if assessments.count(assessment.assessment_name) > 1: + title = frappe.db.get_value( + assessment.assessment_type, assessment.assessment_name, "title" + ) + frappe.throw( + _("Assessment {0} has already been added to this class.").format( + frappe.bold(title) + ) + ) + def validate_membership(self): for course in self.courses: for student in self.students: @@ -43,51 +67,30 @@ class LMSClass(Document): frappe.throw(_("There are no seats available in this class.")) -@frappe.whitelist() -def add_student(email, class_name): - if not frappe.db.exists("User", email): - frappe.throw(_("There is no such user. Please create a user with this Email ID.")) - - filters = { - "student": email, - "parent": class_name, - "parenttype": "LMS Class", - "parentfield": "students", - } - if frappe.db.exists("Class Student", filters): - frappe.throw( - _("Student {0} has already been added to this class.").format(frappe.bold(email)) - ) - - frappe.get_doc( - { - "doctype": "Class Student", - "student": email, - "student_name": frappe.db.get_value("User", email, "full_name"), - "parent": class_name, - "parenttype": "LMS Class", - "parentfield": "students", - } - ).save() - return True - - @frappe.whitelist() def remove_student(student, class_name): + frappe.only_for("Moderator") frappe.db.delete("Class Student", {"student": student, "parent": class_name}) @frappe.whitelist() def remove_course(course, parent): + frappe.only_for("Moderator") frappe.db.delete("Class Course", {"course": course, "parent": parent}) +@frappe.whitelist() +def remove_assessment(assessment, parent): + frappe.only_for("Moderator") + frappe.db.delete("LMS Assessment", {"assessment_name": assessment, "parent": parent}) + + @frappe.whitelist() def create_live_class( class_name, title, duration, date, time, timezone, auto_recording, description=None ): date = format_date(date, "yyyy-mm-dd", True) - + frappe.only_for("Moderator") payload = { "topic": title, "start_time": format_datetime(f"{date} {time}", "yyyy-MM-ddTHH:mm:ssZ"), @@ -164,6 +167,7 @@ def create_class( category=None, name=None, ): + frappe.only_for("Moderator") if name: class_details = frappe.get_doc("LMS Class", name) else: @@ -184,23 +188,3 @@ def create_class( ) class_details.save() return class_details - - -@frappe.whitelist() -def update_assessment(type, name, value, class_name): - value = cint(value) - filters = { - "assessment_type": type, - "assessment_name": name, - "parent": class_name, - "parenttype": "LMS Class", - "parentfield": "assessment", - } - exists = frappe.db.exists("LMS Assessment", filters) - - if exists and not value: - frappe.db.delete("LMS Assessment", exists) - elif not exists and value: - doc = frappe.new_doc("LMS Assessment") - doc.update(filters) - doc.insert() diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.json b/lms/lms/doctype/lms_quiz/lms_quiz.json index 7f3a8d48..39e9b282 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.json +++ b/lms/lms/doctype/lms_quiz/lms_quiz.json @@ -70,7 +70,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-06-21 09:13:01.322701", + "modified": "2023-06-23 12:35:25.204131", "modified_by": "Administrator", "module": "LMS", "name": "LMS Quiz", @@ -87,6 +87,18 @@ "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, diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 522084fe..6e2d981d 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -733,3 +733,23 @@ def is_onboarding_complete(): if course_created else None, } + + +def has_submitted_assessment(assessment, type, member=None): + if not member: + member = frappe.session.user + + doctype = ( + "LMS Assignment Submission" if type == "LMS Assignment" else "LMS Quiz Submission" + ) + docfield = "assignment" if type == "LMS Assignment" else "quiz" + + filters = {} + filters[docfield] = assessment + filters["member"] = member + return frappe.db.exists(doctype, filters) + + +def has_graded_assessment(submission): + status = frappe.db.get_value("LMS Assignment Submission", submission, "status") + return False if status == "Not Graded" else True diff --git a/lms/lms/widgets/CourseCard.html b/lms/lms/widgets/CourseCard.html index 78472396..486471c9 100644 --- a/lms/lms/widgets/CourseCard.html +++ b/lms/lms/widgets/CourseCard.html @@ -72,6 +72,9 @@ {% endif %}
{{ _("No Assessments") }}
@@ -376,7 +367,6 @@ {% macro CreateLiveClass(class_info) %} - {% if is_moderator %}{{ _("No Live Classes") }}
+{{ _("No Live Classes") }}
{% endif %}