From 1d5d86ef6c0be7b49f9bc0d922d4a52ae23468f8 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 9 Nov 2022 16:36:26 +0530 Subject: [PATCH 01/10] feat: claasses --- lms/lms/doctype/class_course/__init__.py | 0 .../doctype/class_course/class_course.json | 34 +++++++ lms/lms/doctype/class_course/class_course.py | 8 ++ lms/lms/doctype/class_student/__init__.py | 0 .../doctype/class_student/class_student.js | 8 ++ .../doctype/class_student/class_student.json | 43 +++++++++ .../doctype/class_student/class_student.py | 8 ++ .../class_student/test_class_student.py | 9 ++ lms/lms/doctype/lms_class/__init__.py | 0 lms/lms/doctype/lms_class/lms_class.js | 8 ++ lms/lms/doctype/lms_class/lms_class.json | 89 +++++++++++++++++++ lms/lms/doctype/lms_class/lms_class.py | 8 ++ lms/lms/doctype/lms_class/test_lms_class.py | 9 ++ lms/www/classes/__init__.py | 0 lms/www/classes/class.html | 0 lms/www/classes/class.py | 0 lms/www/classes/index.html | 25 ++++++ lms/www/classes/index.py | 4 + 18 files changed, 253 insertions(+) create mode 100644 lms/lms/doctype/class_course/__init__.py create mode 100644 lms/lms/doctype/class_course/class_course.json create mode 100644 lms/lms/doctype/class_course/class_course.py create mode 100644 lms/lms/doctype/class_student/__init__.py create mode 100644 lms/lms/doctype/class_student/class_student.js create mode 100644 lms/lms/doctype/class_student/class_student.json create mode 100644 lms/lms/doctype/class_student/class_student.py create mode 100644 lms/lms/doctype/class_student/test_class_student.py create mode 100644 lms/lms/doctype/lms_class/__init__.py create mode 100644 lms/lms/doctype/lms_class/lms_class.js create mode 100644 lms/lms/doctype/lms_class/lms_class.json create mode 100644 lms/lms/doctype/lms_class/lms_class.py create mode 100644 lms/lms/doctype/lms_class/test_lms_class.py create mode 100644 lms/www/classes/__init__.py create mode 100644 lms/www/classes/class.html create mode 100644 lms/www/classes/class.py create mode 100644 lms/www/classes/index.html create mode 100644 lms/www/classes/index.py diff --git a/lms/lms/doctype/class_course/__init__.py b/lms/lms/doctype/class_course/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/lms/doctype/class_course/class_course.json b/lms/lms/doctype/class_course/class_course.json new file mode 100644 index 00000000..f5a570a2 --- /dev/null +++ b/lms/lms/doctype/class_course/class_course.json @@ -0,0 +1,34 @@ +{ + "actions": [], + "autoname": "autoincrement", + "creation": "2022-11-09 16:23:26.454527", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "course" + ], + "fields": [ + { + "fieldname": "course", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Course", + "options": "LMS Course", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2022-11-09 16:25:01.648986", + "modified_by": "Administrator", + "module": "LMS", + "name": "Class Course", + "naming_rule": "Autoincrement", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/lms/lms/doctype/class_course/class_course.py b/lms/lms/doctype/class_course/class_course.py new file mode 100644 index 00000000..17aac44b --- /dev/null +++ b/lms/lms/doctype/class_course/class_course.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class ClassCourse(Document): + pass diff --git a/lms/lms/doctype/class_student/__init__.py b/lms/lms/doctype/class_student/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/lms/doctype/class_student/class_student.js b/lms/lms/doctype/class_student/class_student.js new file mode 100644 index 00000000..20668248 --- /dev/null +++ b/lms/lms/doctype/class_student/class_student.js @@ -0,0 +1,8 @@ +// Copyright (c) 2022, Frappe and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Class Student', { + // refresh: function(frm) { + + // } +}); diff --git a/lms/lms/doctype/class_student/class_student.json b/lms/lms/doctype/class_student/class_student.json new file mode 100644 index 00000000..4791e664 --- /dev/null +++ b/lms/lms/doctype/class_student/class_student.json @@ -0,0 +1,43 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2022-11-09 16:20:44.602545", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "student", + "student_name" + ], + "fields": [ + { + "fieldname": "student", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Student", + "options": "User", + "reqd": 1 + }, + { + "fetch_from": "student.full_name", + "fieldname": "student_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Student Name", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2022-11-09 16:25:07.819344", + "modified_by": "Administrator", + "module": "LMS", + "name": "Class Student", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/lms/lms/doctype/class_student/class_student.py b/lms/lms/doctype/class_student/class_student.py new file mode 100644 index 00000000..74c8df36 --- /dev/null +++ b/lms/lms/doctype/class_student/class_student.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class ClassStudent(Document): + pass diff --git a/lms/lms/doctype/class_student/test_class_student.py b/lms/lms/doctype/class_student/test_class_student.py new file mode 100644 index 00000000..41f8ed09 --- /dev/null +++ b/lms/lms/doctype/class_student/test_class_student.py @@ -0,0 +1,9 @@ +# Copyright (c) 2022, Frappe and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestClassStudent(FrappeTestCase): + pass diff --git a/lms/lms/doctype/lms_class/__init__.py b/lms/lms/doctype/lms_class/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/lms/doctype/lms_class/lms_class.js b/lms/lms/doctype/lms_class/lms_class.js new file mode 100644 index 00000000..dca66f76 --- /dev/null +++ b/lms/lms/doctype/lms_class/lms_class.js @@ -0,0 +1,8 @@ +// Copyright (c) 2022, Frappe and contributors +// For license information, please see license.txt + +frappe.ui.form.on('LMS Class', { + // refresh: function(frm) { + + // } +}); diff --git a/lms/lms/doctype/lms_class/lms_class.json b/lms/lms/doctype/lms_class/lms_class.json new file mode 100644 index 00000000..d2fe0821 --- /dev/null +++ b/lms/lms/doctype/lms_class/lms_class.json @@ -0,0 +1,89 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "format: CLS-{#####}", + "creation": "2022-11-09 16:14:05.876933", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "data_2", + "end_date", + "column_break_4", + "description", + "section_break_6", + "students", + "courses" + ], + "fields": [ + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "data_2", + "fieldtype": "Date", + "label": "Start Date" + }, + { + "fieldname": "end_date", + "fieldtype": "Date", + "label": "End Date" + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Description" + }, + { + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, + { + "fieldname": "students", + "fieldtype": "Table", + "label": "Students", + "options": "Class Student" + }, + { + "fieldname": "courses", + "fieldtype": "Table", + "label": "Courses", + "options": "Class Course" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2022-11-09 16:24:28.502317", + "modified_by": "Administrator", + "module": "LMS", + "name": "LMS Class", + "naming_rule": "Expression (old style)", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py new file mode 100644 index 00000000..46090ef9 --- /dev/null +++ b/lms/lms/doctype/lms_class/lms_class.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class LMSClass(Document): + pass diff --git a/lms/lms/doctype/lms_class/test_lms_class.py b/lms/lms/doctype/lms_class/test_lms_class.py new file mode 100644 index 00000000..6e1f2659 --- /dev/null +++ b/lms/lms/doctype/lms_class/test_lms_class.py @@ -0,0 +1,9 @@ +# Copyright (c) 2022, Frappe and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestLMSClass(FrappeTestCase): + pass diff --git a/lms/www/classes/__init__.py b/lms/www/classes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html new file mode 100644 index 00000000..e69de29b diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/www/classes/index.html b/lms/www/classes/index.html new file mode 100644 index 00000000..b70968c4 --- /dev/null +++ b/lms/www/classes/index.html @@ -0,0 +1,25 @@ +{% extends "templates/base.html" %} +{% block title %} + {{ _("All Classes") }} +{% endblock %} + +{% block content %} +
+
+ + {{ _("Create Class") }} + +
{{ _("All Classes") }}
+ {% if classes %} + {% else %} +
+ +
+
{{ _("No Classes") }}
+
{{ _("There are no classes on this site.") }}
+
+
+ {% endif %} +
+
+{% endblock %} diff --git a/lms/www/classes/index.py b/lms/www/classes/index.py new file mode 100644 index 00000000..426be804 --- /dev/null +++ b/lms/www/classes/index.py @@ -0,0 +1,4 @@ +import frappe + +def get_context(context): + context.no_cache = 1 From 3e1f29af4872d531a5c4a232ba45d2622659e116 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 14 Nov 2022 16:20:13 +0530 Subject: [PATCH 02/10] feat: add and remove students and courses from class --- lms/hooks.py | 1 + .../doctype/class_course/class_course.json | 13 +- lms/lms/doctype/lms_class/lms_class.json | 26 +++- lms/lms/doctype/lms_class/lms_class.py | 45 +++++- lms/lms/web_form/class/__init__.py | 0 lms/lms/web_form/class/class.js | 3 + lms/lms/web_form/class/class.json | 87 +++++++++++ lms/lms/web_form/class/class.py | 5 + lms/public/css/style.css | 44 +++++- lms/public/js/common_functions.js | 19 +++ lms/www/classes/class.html | 142 ++++++++++++++++++ lms/www/classes/class.js | 67 +++++++++ lms/www/classes/class.py | 17 +++ lms/www/classes/index.html | 26 +++- lms/www/classes/index.py | 1 + lms/www/courses/index.js | 6 - lms/www/profiles/profile.js | 16 -- 17 files changed, 478 insertions(+), 40 deletions(-) create mode 100644 lms/lms/web_form/class/__init__.py create mode 100644 lms/lms/web_form/class/class.js create mode 100644 lms/lms/web_form/class/class.json create mode 100644 lms/lms/web_form/class/class.py create mode 100644 lms/www/classes/class.js diff --git a/lms/hooks.py b/lms/hooks.py index 8fb9cb6f..a79fc683 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -143,6 +143,7 @@ website_route_rules = [ }, {"from_route": "/quizzes", "to_route": "batch/quiz_list"}, {"from_route": "/quizzes/", "to_route": "batch/quiz"}, + {"from_route": "/classes/", "to_route": "classes/class"}, {"from_route": "/courses//progress", "to_route": "batch/progress"}, {"from_route": "/courses//join", "to_route": "batch/join"}, {"from_route": "/courses//manage", "to_route": "cohorts"}, diff --git a/lms/lms/doctype/class_course/class_course.json b/lms/lms/doctype/class_course/class_course.json index f5a570a2..f53619c4 100644 --- a/lms/lms/doctype/class_course/class_course.json +++ b/lms/lms/doctype/class_course/class_course.json @@ -6,7 +6,8 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "course" + "course", + "title" ], "fields": [ { @@ -16,12 +17,20 @@ "label": "Course", "options": "LMS Course", "reqd": 1 + }, + { + "fetch_from": "course.title", + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "read_only": 1 } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-11-09 16:25:01.648986", + "modified": "2022-11-11 15:51:45.560864", "modified_by": "Administrator", "module": "LMS", "name": "Class Course", diff --git a/lms/lms/doctype/lms_class/lms_class.json b/lms/lms/doctype/lms_class/lms_class.json index d2fe0821..3611d320 100644 --- a/lms/lms/doctype/lms_class/lms_class.json +++ b/lms/lms/doctype/lms_class/lms_class.json @@ -9,7 +9,7 @@ "engine": "InnoDB", "field_order": [ "title", - "data_2", + "start_date", "end_date", "column_break_4", "description", @@ -25,11 +25,6 @@ "label": "Title", "reqd": 1 }, - { - "fieldname": "data_2", - "fieldtype": "Date", - "label": "Start Date" - }, { "fieldname": "end_date", "fieldtype": "Date", @@ -59,11 +54,16 @@ "fieldtype": "Table", "label": "Courses", "options": "Class Course" + }, + { + "fieldname": "start_date", + "fieldtype": "Date", + "label": "Start Date" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-11-09 16:24:28.502317", + "modified": "2022-11-11 17:41:05.472822", "modified_by": "Administrator", "module": "LMS", "name": "LMS Class", @@ -81,6 +81,18 @@ "role": "System Manager", "share": 1, "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Course Moderator", + "share": 1, + "write": 1 } ], "sort_field": "modified", diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py index 46090ef9..58b26443 100644 --- a/lms/lms/doctype/lms_class/lms_class.py +++ b/lms/lms/doctype/lms_class/lms_class.py @@ -1,8 +1,51 @@ # Copyright (c) 2022, Frappe and contributors # For license information, please see license.txt -# import frappe +import frappe from frappe.model.document import Document +from frappe import _ +from frappe.utils import cint class LMSClass(Document): pass + + +@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.")) + + 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.db.delete("Class Student", { + "student": student, + "parent": class_name + }) + return True + + +@frappe.whitelist() +def update_course(class_name, course, value): + if cint(value): + doc = frappe.get_doc({ + "doctype": "Class Course", + "parent": class_name, + "course": course, + "parenttype": "LMS Class", + "parentfield": "courses" + }) + doc.save() + else: + frappe.db.delete("Class Course", {"parent": class_name, "course": course}) + return True diff --git a/lms/lms/web_form/class/__init__.py b/lms/lms/web_form/class/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/lms/web_form/class/class.js b/lms/lms/web_form/class/class.js new file mode 100644 index 00000000..699703c5 --- /dev/null +++ b/lms/lms/web_form/class/class.js @@ -0,0 +1,3 @@ +frappe.ready(function() { + // bind events here +}) \ No newline at end of file diff --git a/lms/lms/web_form/class/class.json b/lms/lms/web_form/class/class.json new file mode 100644 index 00000000..c98783da --- /dev/null +++ b/lms/lms/web_form/class/class.json @@ -0,0 +1,87 @@ +{ + "accept_payment": 0, + "allow_comments": 0, + "allow_delete": 0, + "allow_edit": 0, + "allow_incomplete": 0, + "allow_multiple": 0, + "allow_print": 0, + "amount": 0.0, + "amount_based_on_field": 0, + "apply_document_permissions": 0, + "button_label": "Save", + "creation": "2022-11-11 12:10:29.640675", + "custom_css": "", + "doc_type": "LMS Class", + "docstatus": 0, + "doctype": "Web Form", + "idx": 0, + "is_standard": 1, + "list_columns": [], + "login_required": 0, + "max_attachment_size": 0, + "modified": "2022-11-11 12:23:14.664297", + "modified_by": "Administrator", + "module": "LMS", + "name": "class", + "owner": "Administrator", + "payment_button_label": "Buy Now", + "published": 1, + "route": "class", + "show_attachments": 0, + "show_list": 0, + "show_sidebar": 0, + "success_title": "", + "success_url": "/classes", + "title": "Class", + "web_form_fields": [ + { + "allow_read_on_all_link_options": 0, + "fieldname": "title", + "fieldtype": "Data", + "hidden": 0, + "label": "Title", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "start_date", + "fieldtype": "Date", + "hidden": 0, + "label": "Start Date", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "end_date", + "fieldtype": "Date", + "hidden": 0, + "label": "End Date", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "description", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Description", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + } + ] +} \ No newline at end of file diff --git a/lms/lms/web_form/class/class.py b/lms/lms/web_form/class/class.py new file mode 100644 index 00000000..e1ada619 --- /dev/null +++ b/lms/lms/web_form/class/class.py @@ -0,0 +1,5 @@ +import frappe + +def get_context(context): + # do your magic here + pass diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 65ef4106..7ec1ff67 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -9,7 +9,21 @@ body { } input[type=checkbox] { - appearance: auto; + appearance: auto; + position: relative; + width: var(--checkbox-size)!important; + height: var(--checkbox-size); + margin-right: var(--checkbox-right-margin)!important; + background-repeat: no-repeat; + background-position: center; + border: 1px solid var(--gray-400); + box-sizing: border-box; + box-shadow: 0 1px 2px #0000001a; + border-radius: 4px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-print-color-adjust: exact; } .course-image { @@ -1747,10 +1761,6 @@ li { padding: 0 1.5rem !important; } -.modal-footer { - padding: 0.75rem 1.5rem !important; -} - .modal-content { font-size: var(--text-base) !important; } @@ -1764,9 +1774,9 @@ li { } .modal-footer { + padding: 0.75rem 1.5rem !important; border-top: none !important; background-color: var(--gray-200) !important; - justify-content: flex-end !important; } .modal-header .modal-title { @@ -1808,3 +1818,25 @@ select { .course-list-cta { float: right; } + +.modal-title { + font-size: var(--text-base) !important; +} + +.class-form-title { + font-size: var(--text-base); +} + +.remove-student { + cursor: pointer; +} + +.class-course-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + grid-gap: 1rem; +} + +.class-cours { + cursor: pointer; +} diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index f60b4721..542c32e3 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -17,6 +17,14 @@ frappe.ready(() => { save_chapter(e); }); + $(".nav-link").click((e) => { + change_hash(e); + }); + + if (window.location.hash) { + open_tab(); + } + if (window.location.pathname == "/statistics") { generate_graph("New Signups", "#new-signups"); generate_graph("Course Enrollments", "#course-enrollments"); @@ -197,6 +205,7 @@ const render_chart = (data, chart_name, element, type) => { }); }; + const generate_course_completion_graph = () => { frappe.call({ method: "lms.lms.utils.get_course_completion_data", @@ -210,3 +219,13 @@ const generate_course_completion_graph = () => { }, }); }; + + +const change_hash = (e) => { + window.location.hash = $(e.currentTarget).attr("href"); +}; + + +const open_tab = () => { + $(`a[href="${window.location.hash}"]`).click(); +}; diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index e69de29b..5c21eaa4 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -0,0 +1,142 @@ +{% extends "templates/base.html" %} +{% block title %} + {{ _(class_info.title) }} +{% endblock %} + + +{% block content %} +
+
+ {{ BreadCrumb(class_info) }} +
+ {{ ClassDetails(class_info) }} + {{ ClassSections(class_info, class_courses, class_students, published_courses) }} +
+
+
+{% endblock %} + + + +{% macro BreadCrumb(class_info) %} + +{% endmacro %} + + + +{% macro ClassDetails(class_info) %} +
+
+ {{ class_info.title }} +
+
+ {{ class_info.description }} +
+
+ {% if class_info.start_date %} + + {{ frappe.utils.format_date(class_info.start_date, "medium") }} - + + {% endif %} + {% if class_info.end_date %} + + {{ frappe.utils.format_date(class_info.end_date, "medium") }} + + {% endif %} +
+
+{% endmacro %} + + + +{% macro ClassSections(class_info, class_courses, class_students, published_courses) %} +
+ + +
+ +
+
+ {{ CoursesSection(class_info, class_courses, published_courses) }} +
+ +
+ {{ StudentsSection(class_info, class_students) }} +
+ +
+
+{% endmacro %} + + +{% macro CoursesSection(class_info, class_courses, published_courses) %} +
+ {% if published_courses | length %} + {% for course in published_courses %} + {% set checked = course.name in class_courses %} + + {% endfor %} + {% endif %} +
+{% endmacro %} + + +{% macro StudentsSection(class_info, class_students) %} +
+ {{ AddStudents() }} + + {% if class_students | length %} +
+ {% for student in class_students %} +
+ {{ student.student_name }} + + + +
+ {% if not loop.last %}
{% endif %} + {% endfor %} +
+ {% else %} +

{{ _("No Students are added to this class.") }}

+ {% endif %} +
+{% endmacro %} + + +{% macro AddStudents() %} +
+
+ {{ _("Add Student") }} +
+
+
+
+ +
+
+ +
+
+{% endmacro %} diff --git a/lms/www/classes/class.js b/lms/www/classes/class.js new file mode 100644 index 00000000..3e9ce267 --- /dev/null +++ b/lms/www/classes/class.js @@ -0,0 +1,67 @@ +frappe.ready(() => { + + $("#submit-student").click((e) => { + submit_student(e); + }); + + $(".remove-student").click((e) => { + remove_student(e); + }); + + $(".class-course").click((e) => { + update_course(e); + }); + +}); + + +const submit_student = (e) => { + e.preventDefault(); + frappe.call({ + method: "lms.lms.doctype.lms_class.lms_class.add_student", + args: { + "email": $("#student-email").val(), + "class_name": $(".class-details").data("class") + }, + callback: (data) => { + frappe.show_alert({ + message: __("Student added successfully"), + indicator: "green", + } ,3); + window.location.reload(); + } + }) +}; + + +const remove_student = (e) => { + frappe.confirm("Are you sure you want to remove this student from the class?", + () => { + frappe.call({ + method: "lms.lms.doctype.lms_class.lms_class.remove_student", + args: { + "student": $(e.currentTarget).data("student"), + "class_name": $(".class-details").data("class") + }, + callback: (data) => { + frappe.show_alert({ + message: __("Student removed successfully"), + indicator: "green", + }, 3); + window.location.reload(); + } + }); + }) +} + + +const update_course = (e) => { + frappe.call({ + method: "lms.lms.doctype.lms_class.lms_class.update_course", + args: { + "course": $(e.currentTarget).data("course"), + "value": $(e.currentTarget).children("input").prop("checked") ? 1 : 0, + "class_name": $(".class-details").data("class") + } + }) +}; diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py index e69de29b..7949f919 100644 --- a/lms/www/classes/class.py +++ b/lms/www/classes/class.py @@ -0,0 +1,17 @@ +import frappe + + +def get_context(context): + context.no_cache = 1 + class_name = frappe.form_dict["classname"] + + context.class_info = frappe.db.get_value("LMS Class", class_name, ["name", "title", "start_date", "end_date", "description"], as_dict=True) + context.published_courses = frappe.get_all("LMS Course", {"published": 1}, ["name", "title"]) + + context.class_courses = frappe.get_all("Class Course", { + "parent": class_name + }, pluck="course") + + context.class_students = frappe.get_all("Class Student", { + "parent": class_name + }, ["student", "student_name"]) diff --git a/lms/www/classes/index.html b/lms/www/classes/index.html index b70968c4..e9aae9ab 100644 --- a/lms/www/classes/index.html +++ b/lms/www/classes/index.html @@ -6,17 +6,39 @@ {% block content %}
- + {{ _("Create Class") }}
{{ _("All Classes") }}
{% if classes %} +
+ {% for class in classes %} +
+
+ {{ class.title }} +
+
+ {% if class.start_date %} + + {{ frappe.utils.format_date(class.start_date, "medium") }} - + + {% endif %} + {% if class.end_date %} + + {{ frappe.utils.format_date(class.end_date, "medium") }} + + {% endif %} +
+ +
+ {% endfor %} +
{% else %}
{{ _("No Classes") }}
-
{{ _("There are no classes on this site.") }}
+
{{ _("Nothing to see here.") }}
{% endif %} diff --git a/lms/www/classes/index.py b/lms/www/classes/index.py index 426be804..89108673 100644 --- a/lms/www/classes/index.py +++ b/lms/www/classes/index.py @@ -2,3 +2,4 @@ import frappe def get_context(context): context.no_cache = 1 + context.classes = frappe.get_all("LMS Class", fields=["name", "title", "start_date", "end_date"]) diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js index f3bc44ec..a78fd836 100644 --- a/lms/www/courses/index.js +++ b/lms/www/courses/index.js @@ -1,11 +1,5 @@ frappe.ready(() => { - $(".nav-link").click((e) => { - change_hash(e); - }); - if (window.location.hash) { - open_tab(); - } }); const change_hash = (e) => { diff --git a/lms/www/profiles/profile.js b/lms/www/profiles/profile.js index 9349c69b..7a5d90f3 100644 --- a/lms/www/profiles/profile.js +++ b/lms/www/profiles/profile.js @@ -4,14 +4,6 @@ frappe.ready(() => { $(".role").change((e) => { save_role(e); }); - - $(".nav-link").click((e) => { - change_hash(e); - }); - - if (window.location.hash) { - open_tab(); - } }); const make_profile_active_in_navbar = () => { @@ -46,11 +38,3 @@ const save_role = (e) => { }, }); }; - -const change_hash = (e) => { - window.location.hash = $(e.currentTarget).attr("href"); -}; - -const open_tab = () => { - $(`a[href="${window.location.hash}"]`).click(); -}; From d9e44e0f91dbfa944b7b0003807f84330ee81440 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 14 Nov 2022 17:25:07 +0530 Subject: [PATCH 03/10] fix: renamed instructor and moderator roles --- lms/lms/doctype/lms_class/lms_class.json | 4 ++-- lms/lms/utils.py | 4 ++-- lms/patches.txt | 1 + lms/patches/v0_0/change_role_names.py | 5 +++++ lms/www/profiles/profile.html | 8 ++++---- 5 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 lms/patches/v0_0/change_role_names.py diff --git a/lms/lms/doctype/lms_class/lms_class.json b/lms/lms/doctype/lms_class/lms_class.json index 3611d320..f90a0f30 100644 --- a/lms/lms/doctype/lms_class/lms_class.json +++ b/lms/lms/doctype/lms_class/lms_class.json @@ -63,7 +63,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-11-11 17:41:05.472822", + "modified": "2022-11-14 17:08:03.206840", "modified_by": "Administrator", "module": "LMS", "name": "LMS Class", @@ -90,7 +90,7 @@ "print": 1, "read": 1, "report": 1, - "role": "Course Moderator", + "role": "Moderator", "share": 1, "write": 1 } diff --git a/lms/lms/utils.py b/lms/lms/utils.py index edb256b0..d17229ab 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -486,7 +486,7 @@ def redirect_to_courses_list(): def has_course_instructor_role(member=None): return frappe.db.get_value( "Has Role", - {"parent": member or frappe.session.user, "role": "Course Instructor"}, + {"parent": member or frappe.session.user, "role": "Instructor"}, "name", ) @@ -506,7 +506,7 @@ def can_create_courses(member=None): def has_course_moderator_role(member=None): return frappe.db.get_value( "Has Role", - {"parent": member or frappe.session.user, "role": "Course Moderator"}, + {"parent": member or frappe.session.user, "role": "Moderator"}, "name", ) diff --git a/lms/patches.txt b/lms/patches.txt index 012a7f4c..872f96c9 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -37,3 +37,4 @@ lms.patches.v0_0.set_courses_page_as_home lms.patches.v0_0.set_member_in_progress #09-11-2022 lms.patches.v0_0.convert_progress_to_float lms.patches.v0_0.add_pages_to_nav #11-11-2022 +lms.patches.v0_0.change_role_names diff --git a/lms/patches/v0_0/change_role_names.py b/lms/patches/v0_0/change_role_names.py new file mode 100644 index 00000000..9653ef6f --- /dev/null +++ b/lms/patches/v0_0/change_role_names.py @@ -0,0 +1,5 @@ +import frappe + +def execute(): + frappe.rename_doc("Role", "Course Instructor", "Instructor") + frappe.rename_doc("Role", "Course Moderator", "Moderator") diff --git a/lms/www/profiles/profile.html b/lms/www/profiles/profile.html index 1a979f51..e355db95 100644 --- a/lms/www/profiles/profile.html +++ b/lms/www/profiles/profile.html @@ -205,14 +205,14 @@
{{ _("Role Settings") }}
From ae2c15fe8ccd38e5b805959b40f0b75dc7a31cd5 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 15 Nov 2022 18:56:45 +0530 Subject: [PATCH 04/10] feat: progress page --- lms/hooks.py | 38 ++++------ .../doctype/class_student/class_student.json | 12 ++- .../doctype/course_lesson/course_lesson.py | 2 + lms/lms/doctype/lms_class/lms_class.py | 16 +++- lms/lms/doctype/lms_quiz/lms_quiz.json | 27 ++++++- lms/lms/doctype/lms_quiz/lms_quiz.py | 7 ++ .../lms_quiz_submission.json | 20 +++-- lms/public/css/style.css | 34 ++++++--- lms/www/classes/class.html | 7 +- lms/www/classes/class.py | 12 ++- lms/www/classes/index.py | 11 +++ lms/www/classes/progress.html | 76 +++++++++++++++++++ lms/www/classes/progress.py | 26 +++++++ 13 files changed, 240 insertions(+), 48 deletions(-) create mode 100644 lms/www/classes/progress.html create mode 100644 lms/www/classes/progress.py diff --git a/lms/hooks.py b/lms/hooks.py index a79fc683..15ce3873 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -95,7 +95,8 @@ override_doctype_class = { # Hook on document methods and events doc_events = { - "Discussion Reply": {"after_insert": "lms.lms.utils.create_notification_log"} + "Discussion Reply": {"after_insert": "lms.lms.utils.create_notification_log"}, + "Course Lesson": {"on_update": "lms.lms.doctype.lms_quiz.lms_quiz.update_lesson_info"} } # Scheduled Tasks @@ -137,35 +138,28 @@ website_route_rules = [ {"from_route": "/courses/", "to_route": "courses/course"}, {"from_route": "/courses//", "to_route": "courses/certificate"}, {"from_route": "/courses//learn", "to_route": "batch/learn"}, - { - "from_route": "/courses//learn/.", - "to_route": "batch/learn", - }, + {"from_route": "/courses//learn/.", + "to_route": "batch/learn"}, {"from_route": "/quizzes", "to_route": "batch/quiz_list"}, {"from_route": "/quizzes/", "to_route": "batch/quiz"}, {"from_route": "/classes/", "to_route": "classes/class"}, {"from_route": "/courses//progress", "to_route": "batch/progress"}, {"from_route": "/courses//join", "to_route": "batch/join"}, {"from_route": "/courses//manage", "to_route": "cohorts"}, - {"from_route": "/courses//cohorts/", "to_route": "cohorts/cohort"}, - { - "from_route": "/courses//cohorts//", - "to_route": "cohorts/cohort", - }, - { - "from_route": "/courses//subgroups//", - "to_route": "cohorts/subgroup", - }, - { - "from_route": "/courses//subgroups///", - "to_route": "cohorts/subgroup", - }, - { - "from_route": "/courses//join///", - "to_route": "cohorts/join", - }, + {"from_route": "/courses//cohorts/", + "to_route": "cohorts/cohort"}, + {"from_route": "/courses//cohorts//", + "to_route": "cohorts/cohort"}, + {"from_route": "/courses//subgroups//", + "to_route": "cohorts/subgroup"}, + {"from_route": "/courses//subgroups///", + "to_route": "cohorts/subgroup"}, + {"from_route": "/courses//join///", + "to_route": "cohorts/join"}, {"from_route": "/users", "to_route": "profiles/profile"}, {"from_route": "/jobs/", "to_route": "jobs/job"}, + {"from_route": "/classes//students/", + "to_route": "/classes/progress"} ] website_redirects = [ diff --git a/lms/lms/doctype/class_student/class_student.json b/lms/lms/doctype/class_student/class_student.json index 4791e664..3442dd7c 100644 --- a/lms/lms/doctype/class_student/class_student.json +++ b/lms/lms/doctype/class_student/class_student.json @@ -8,7 +8,8 @@ "engine": "InnoDB", "field_order": [ "student", - "student_name" + "student_name", + "username" ], "fields": [ { @@ -26,12 +27,19 @@ "in_list_view": 1, "label": "Student Name", "read_only": 1 + }, + { + "fetch_from": "student.username", + "fieldname": "username", + "fieldtype": "Data", + "label": "Username", + "read_only": 1 } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-11-09 16:25:07.819344", + "modified": "2022-11-15 11:13:39.410578", "modified_by": "Administrator", "module": "LMS", "name": "Class Student", diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index 3a29ee4d..acc3bc7e 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -33,6 +33,7 @@ class CourseLesson(Document): e = frappe.get_doc(doctype_map[section], name) e.lesson = self.name e.index_ = index + e.course = self.course e.save(ignore_permissions=True) index += 1 self.update_orphan_documents(doctype_map[section], documents) @@ -49,6 +50,7 @@ class CourseLesson(Document): for name in orphan_documents: ex = frappe.get_doc(doctype, name) ex.lesson = None + ex.course = None ex.index_ = 0 ex.index_label = "" ex.save() diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py index 58b26443..d7495aff 100644 --- a/lms/lms/doctype/lms_class/lms_class.py +++ b/lms/lms/doctype/lms_class/lms_class.py @@ -7,7 +7,21 @@ from frappe import _ from frappe.utils import cint class LMSClass(Document): - pass + + def validate(self): + validate_membership(self) + + +def validate_membership(self): + for course in self.courses: + for student in self.students: + filters = { + "doctype": "LMS Batch Membership", + "member": student.student, + "course": course.course + } + if not frappe.db.exists(filters): + frappe.get_doc(filters).save() @frappe.whitelist() diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.json b/lms/lms/doctype/lms_quiz/lms_quiz.json index 99ffc184..a3221040 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.json +++ b/lms/lms/doctype/lms_quiz/lms_quiz.json @@ -9,9 +9,12 @@ "field_order": [ "title", "questions", - "lesson", + "section_break_3", "max_attempts", - "time" + "time", + "column_break_5", + "lesson", + "course" ], "fields": [ { @@ -46,11 +49,27 @@ "fieldname": "time", "fieldtype": "Int", "label": "Time Per Question (in Seconds)" + }, + { + "fetch_from": "lesson.course", + "fieldname": "course", + "fieldtype": "Link", + "label": "Course", + "options": "LMS Course", + "read_only": 1 + }, + { + "fieldname": "column_break_5", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_3", + "fieldtype": "Section Break" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-08-19 17:54:41.685182", + "modified": "2022-11-15 15:36:39.585488", "modified_by": "Administrator", "module": "LMS", "name": "LMS Quiz", @@ -69,8 +88,10 @@ "write": 1 } ], + "show_title_field_in_link": 1, "sort_field": "modified", "sort_order": "DESC", "states": [], + "title_field": "title", "track_changes": 1 } \ No newline at end of file diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.py b/lms/lms/doctype/lms_quiz/lms_quiz.py index 6879c773..539eb33d 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/lms_quiz.py @@ -60,6 +60,13 @@ class LMSQuiz(Document): return result[0] +def update_lesson_info(doc, method): + if doc.quiz_id: + frappe.db.set_value("LMS Quiz", doc.quiz_id, { + "lesson": doc.name, + "course": doc.course + }) + @frappe.whitelist() def quiz_summary(quiz, results): score = 0 diff --git a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json index a2b13222..80ca9ffd 100644 --- a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json +++ b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json @@ -5,11 +5,12 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "member", - "member_name", - "column_break_3", "quiz", "score", + "course", + "column_break_3", + "member", + "member_name", "section_break_6", "result" ], @@ -46,7 +47,8 @@ "fetch_from": "member.full_name", "fieldname": "member_name", "fieldtype": "Data", - "label": "Member Name" + "label": "Member Name", + "read_only": 1 }, { "fieldname": "column_break_3", @@ -55,12 +57,20 @@ { "fieldname": "section_break_6", "fieldtype": "Section Break" + }, + { + "fetch_from": "quiz.course", + "fieldname": "course", + "fieldtype": "Link", + "label": "Course", + "options": "LMS Course", + "read_only": 1 } ], "in_create": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2022-10-10 18:57:42.813738", + "modified": "2022-11-15 15:27:07.770945", "modified_by": "Administrator", "module": "LMS", "name": "LMS Quiz Submission", diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 7ec1ff67..94c7ead0 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -87,9 +87,9 @@ input[type=checkbox] { } .common-page-style { - padding: 2rem 0 5rem; - padding-top: 3rem; - background-color: var(--bg-color); + padding: 2rem 0 5rem; + padding-top: 3rem; + background-color: var(--bg-color); } .common-card-style { @@ -443,10 +443,6 @@ input[type=checkbox] { padding: 2rem 1rem; } -.member-card .talk-title { - font-weight: bold; -} - .break { flex-basis: 100%; flex-grow: 1; @@ -978,10 +974,6 @@ pre { } } -.section-heading { - font-size: var(--text-4xl); -} - .testimonial-card { flex-direction: column; padding: 2rem; @@ -1835,8 +1827,28 @@ select { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); grid-gap: 1rem; + font-size: var(--text-base); } .class-cours { cursor: pointer; } + +.subheading { + font-weight: 500; + color: var(--gray-900); +} + +.progress-course-header { + display: flex; + justify-content: space-between; + background-color: var(--gray-100); + padding: 0.5rem; + border-radius: var(--border-radius-sm); +} + +.section-heading { + font-size: 1rem; + color: var(--gray-900); + font-weight: 500; +} diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index 5c21eaa4..31f650fe 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -1,6 +1,6 @@ {% extends "templates/base.html" %} {% block title %} - {{ _(class_info.title) }} + {{ _(class_info.title) }} {% endblock %} @@ -33,7 +33,7 @@
{{ class_info.title }}
-
+
{{ class_info.description }}
@@ -108,11 +108,12 @@ {% if class_students | length %}
{% for student in class_students %} -
+
{{ student.student_name }} +
{% if not loop.last %}
{% endif %} {% endfor %} diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py index 7949f919..2ccc3c77 100644 --- a/lms/www/classes/class.py +++ b/lms/www/classes/class.py @@ -1,8 +1,18 @@ import frappe +from lms.lms.utils import has_course_moderator_role +from frappe import _ def get_context(context): context.no_cache = 1 + + if not has_course_moderator_role(): + message = "Only Moderators have access to this page." + if frappe.session.user == "Guest": + message = "Please login to access this page." + + raise frappe.PermissionError(_(message)) + class_name = frappe.form_dict["classname"] context.class_info = frappe.db.get_value("LMS Class", class_name, ["name", "title", "start_date", "end_date", "description"], as_dict=True) @@ -14,4 +24,4 @@ def get_context(context): context.class_students = frappe.get_all("Class Student", { "parent": class_name - }, ["student", "student_name"]) + }, ["student", "student_name", "username"]) diff --git a/lms/www/classes/index.py b/lms/www/classes/index.py index 89108673..0f0c030f 100644 --- a/lms/www/classes/index.py +++ b/lms/www/classes/index.py @@ -1,5 +1,16 @@ import frappe +from lms.lms.utils import has_course_moderator_role +from frappe import _ + def get_context(context): context.no_cache = 1 + + if not has_course_moderator_role(): + message = "Only Moderators have access to this page." + if frappe.session.user == "Guest": + message = "Please login to access this page." + + raise frappe.PermissionError(_(message)) + context.classes = frappe.get_all("LMS Class", fields=["name", "title", "start_date", "end_date"]) diff --git a/lms/www/classes/progress.html b/lms/www/classes/progress.html new file mode 100644 index 00000000..78908e2d --- /dev/null +++ b/lms/www/classes/progress.html @@ -0,0 +1,76 @@ +{% extends "templates/base.html" %} +{% block title %} + {{ student.first_name }} 's {{ _("Progress") }} +{% endblock %} + + +{% block content %} +
+
+ {{ BreadCrumb(class_info, student) }} +
+
+ {{ student.full_name }} +
+ {{ Progress(class_courses, student) }} +
+
+
+{% endblock %} + + +{% macro BreadCrumb(class_info, student) %} + +{% endmacro %} + + +{% macro Progress(class_info, student) %} +
+ {% for course in class_courses %} +
+
+
{{ course.title }}
+
{{ frappe.utils.cint(course.membership.progress) }}%
+
+ + + {% for quiz in course.quizzes %} + + {% set filters = { "member": student.name, "course": course.course } %} + {% set submitted = frappe.db.exists("LMS Quiz Submission", filters) %} + {% set score = frappe.db.get_value("LMS Quiz Submission", filters, ["score"]) %} + +
+
{{ _("Quiz") }}:
+
+
+ {{ quiz.title }} +
+ {% if submitted %} +
+ {{ score }} +
+ {% else %} +
+ Not Attempted +
+ {% endif %} +
+
+ + {% endfor %} + {% for quiz in class_courses.assignments %} +
+ {{ assignments.assignment }} +
+ {% endfor %} +
+ {% endfor %} +
+{% endmacro %} diff --git a/lms/www/classes/progress.py b/lms/www/classes/progress.py new file mode 100644 index 00000000..d5049332 --- /dev/null +++ b/lms/www/classes/progress.py @@ -0,0 +1,26 @@ +import frappe + + +def get_context(context): + context.no_cache = 1 + + student = frappe.form_dict["username"] + classname = frappe.form_dict["classname"] + + context.student = frappe.db.get_value("User", {"username": student}, ["first_name", "full_name", "name"], as_dict=True) + context.class_info = frappe.db.get_value("LMS Class", classname, ["name"], as_dict=True) + + class_courses = frappe.get_all("Class Course", { + "parent": classname + }, ["course", "title"]) + + for course in class_courses: + course.membership = frappe.db.get_value("LMS Batch Membership", { + "member": context.student.name, + "course": course.course + }, ["progress"], as_dict=True) + course.quizzes = frappe.get_all("LMS Quiz", {"course": course.course}, ["name", "title"]) + course.assignments = frappe.get_all("Lesson Assignment", {"course": course.course}, ["name", "assignment"]) + + print(class_courses) + context.class_courses = class_courses From a4ec058a81a726826bcaf1e603694bdb90fadfaa Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 16 Nov 2022 18:43:10 +0530 Subject: [PATCH 05/10] feat: student progress --- lms/hooks.py | 3 +- .../lesson_assignment/lesson_assignment.json | 33 ++++- .../lesson_assignment/lesson_assignment.py | 2 +- lms/plugins.py | 2 +- lms/public/css/style.css | 8 +- lms/templates/assignment.html | 23 ++-- lms/www/assignments/assignment.html | 36 +++++ lms/www/assignments/assignment.py | 16 +++ lms/www/classes/class.py | 1 + lms/www/classes/progress.html | 124 ++++++++++++++---- lms/www/classes/progress.py | 13 +- 11 files changed, 211 insertions(+), 50 deletions(-) create mode 100644 lms/www/assignments/assignment.html create mode 100644 lms/www/assignments/assignment.py diff --git a/lms/hooks.py b/lms/hooks.py index 15ce3873..ea03c729 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -159,7 +159,8 @@ website_route_rules = [ {"from_route": "/users", "to_route": "profiles/profile"}, {"from_route": "/jobs/", "to_route": "jobs/job"}, {"from_route": "/classes//students/", - "to_route": "/classes/progress"} + "to_route": "/classes/progress"}, + {"from_route": "/assignments/", "to_route": "assignments/assignment"} ] website_redirects = [ diff --git a/lms/lms/doctype/lesson_assignment/lesson_assignment.json b/lms/lms/doctype/lesson_assignment/lesson_assignment.json index 18e41b8a..46f316f3 100644 --- a/lms/lms/doctype/lesson_assignment/lesson_assignment.json +++ b/lms/lms/doctype/lesson_assignment/lesson_assignment.json @@ -9,9 +9,11 @@ "assignment", "lesson", "course", + "status", "column_break_3", "member", - "member_name" + "member_name", + "comments" ], "fields": [ { @@ -59,12 +61,24 @@ "in_standard_filter": 1, "label": "Course", "read_only": 1 + }, + { + "default": "Not Graded", + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "options": "Pass\nFail\nNot Graded" + }, + { + "fieldname": "comments", + "fieldtype": "Small Text", + "label": "Comments" } ], "index_web_pages_for_search": 1, "links": [], "make_attachments_public": 1, - "modified": "2022-10-31 13:18:09.609729", + "modified": "2022-11-16 12:11:59.472025", "modified_by": "Administrator", "module": "LMS", "name": "Lesson Assignment", @@ -85,6 +99,19 @@ ], "sort_field": "modified", "sort_order": "DESC", - "states": [], + "states": [ + { + "color": "Green", + "title": "Pass" + }, + { + "color": "Orange", + "title": "Not Graded" + }, + { + "color": "Red", + "title": "Fail" + } + ], "title_field": "lesson" } \ No newline at end of file diff --git a/lms/lms/doctype/lesson_assignment/lesson_assignment.py b/lms/lms/doctype/lesson_assignment/lesson_assignment.py index 8c61faa2..426ee0ae 100644 --- a/lms/lms/doctype/lesson_assignment/lesson_assignment.py +++ b/lms/lms/doctype/lesson_assignment/lesson_assignment.py @@ -12,7 +12,7 @@ class LessonAssignment(Document): def validate_duplicates(self): if frappe.db.exists( - "Lesson Assignment", {"lesson": self.lesson, "member": self.member} + "Lesson Assignment", {"lesson": self.lesson, "member": self.member, "name": ["!=", self.name]} ): lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title") frappe.throw( diff --git a/lms/plugins.py b/lms/plugins.py index 0c9bdb63..f20f94dc 100644 --- a/lms/plugins.py +++ b/lms/plugins.py @@ -152,7 +152,7 @@ def assignment_renderer(detail): file_type = detail.split("-")[1] accept = supported_types[file_type] if file_type else "" return frappe.render_template( - "templates/assignment.html", {"question": question, "accept": accept} + "templates/assignment.html", {"question": question, "accept": accept, "file_type": file_type} ) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 94c7ead0..5c7b7ca2 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1841,10 +1841,8 @@ select { .progress-course-header { display: flex; - justify-content: space-between; background-color: var(--gray-100); padding: 0.5rem; - border-radius: var(--border-radius-sm); } .section-heading { @@ -1852,3 +1850,9 @@ select { color: var(--gray-900); font-weight: 500; } + +.table th { + color: var(--gray-900); + font-weight: 500; + border-bottom: 1px solid var(--gray-300); +} diff --git a/lms/templates/assignment.html b/lms/templates/assignment.html index f32fcb99..a0f04659 100644 --- a/lms/templates/assignment.html +++ b/lms/templates/assignment.html @@ -1,12 +1,15 @@
-
-

{{ _("Assignment") }}

-
{{ _(question) }}
- -
{{ _("Submit") }}
-
- -
{{ _("Change") }}
-
-
+
+

{{ _("Assignment") }}

+
{{ _(question) }}
+
+ {{ _("Only files of type {0} will be accepted").format(file_type) }} +
+ +
{{ _("Submit") }}
+
+ +
{{ _("Change") }}
+
+
diff --git a/lms/www/assignments/assignment.html b/lms/www/assignments/assignment.html new file mode 100644 index 00000000..7165a6c8 --- /dev/null +++ b/lms/www/assignments/assignment.html @@ -0,0 +1,36 @@ +{% extends "templates/base.html" %} +{% block title %} + {{ _("Assignments") }} +{% endblock %} + + +{% block content %} +
+
+
+
{{ _("Save") }}
+
{{ _("Assignments") }}
+
+
+ +
+ +
+
+
+
{% if assignment.comments %}{{ assignment.comments }}{% endif %}
+
+
+
+
+
+{% endblock %} diff --git a/lms/www/assignments/assignment.py b/lms/www/assignments/assignment.py new file mode 100644 index 00000000..ebf38eed --- /dev/null +++ b/lms/www/assignments/assignment.py @@ -0,0 +1,16 @@ +import frappe +from lms.lms.utils import has_course_moderator_role +from frappe import _ + +def get_context(context): + context.no_cache = 1 + assignment = frappe.form_dict["assignment"] + + if not has_course_moderator_role(): + message = "Only Moderators have access to this page." + if frappe.session.user == "Guest": + message = "Please login to access this page." + + raise frappe.PermissionError(_(message)) + + context.assignment = frappe.db.get_value("Lesson Assignment", assignment, ["assignment", "comments", "status", "name"], as_dict=True) diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py index 2ccc3c77..7eda4d07 100644 --- a/lms/www/classes/class.py +++ b/lms/www/classes/class.py @@ -1,6 +1,7 @@ import frappe from lms.lms.utils import has_course_moderator_role from frappe import _ +from lms.lms.utils import has_course_moderator_role def get_context(context): diff --git a/lms/www/classes/progress.html b/lms/www/classes/progress.html index 78908e2d..0fdacccc 100644 --- a/lms/www/classes/progress.html +++ b/lms/www/classes/progress.html @@ -36,40 +36,106 @@
{{ course.title }}
-
{{ frappe.utils.cint(course.membership.progress) }}%
+
{{ frappe.utils.cint(course.membership.progress) }}%
- - {% for quiz in course.quizzes %} - - {% set filters = { "member": student.name, "course": course.course } %} - {% set submitted = frappe.db.exists("LMS Quiz Submission", filters) %} - {% set score = frappe.db.get_value("LMS Quiz Submission", filters, ["score"]) %} - + {% if course.quizzes | length or course.assignments | length %}
-
{{ _("Quiz") }}:
-
-
- {{ quiz.title }} -
- {% if submitted %} -
- {{ score }} -
- {% else %} -
- Not Attempted -
- {% endif %} -
-
+ + + + + + + + {% for quiz in course.quizzes %} - {% endfor %} - {% for quiz in class_courses.assignments %} -
- {{ assignments.assignment }} + {% set filters = { "member": student.name, "course": course.course } %} + {% set has_submitted = frappe.db.exists("LMS Quiz Submission", filters) %} + {% set submission = frappe.db.get_value("LMS Quiz Submission", filters, ["score", "creation"], as_dict=True) %} + +
+ + + {% if has_submitted %} + + + {% else %} + + + {% endif %} + + {% endfor %} + + {% for assignment in course.assignments %} + + {% set filters = { "member": student.name, "course": course.course, "lesson": assignment.name } %} + {% set has_submitted = frappe.db.exists("Lesson Assignment", filters) %} + {% set submission = frappe.db.get_value("Lesson Assignment", filters, ["assignment", "creation", "status"], as_dict=True) %} + {% set status = submission.status %} + {% set color = "green" if status == "Pass" else "red" if status == "Fail" else "orange" %} + + + + + {% if has_submitted %} + + + {% else %} + + + {% endif %} + + {% endfor %} +
+ {{ _("Activity") }} + + {{ _("Type") }} + + {{ _("Score/Status") }} + + {{ _("Last Attempt Date") }} +
+ {{ quiz.title }} + + {{ _("Quiz") }} + + {{ submission.score }} + + {{ frappe.utils.format_date(submission.creation, "medium") }} + + - + +
+ {{ _("Not Attempted") }} +
+
+ {{ assignment.title }} + + {{ _("Assignment") }} + + {% if status == "Not Graded" %} + {{ _("Grade") }} + {% else %} +
+ {{ status }} +
+ {% endif %} +
+ {{ frappe.utils.format_date(submission.creation, "medium") }} + + - + +
+ {{ _("Not Attempted") }} +
+
- {% endfor %} + {% else %} +
+ {{ _("There are no activities in this course.") }} +
+ {% endif %}
{% endfor %}
diff --git a/lms/www/classes/progress.py b/lms/www/classes/progress.py index d5049332..ba2fd726 100644 --- a/lms/www/classes/progress.py +++ b/lms/www/classes/progress.py @@ -1,9 +1,17 @@ import frappe - +from lms.lms.utils import has_course_moderator_role +from frappe import _ def get_context(context): context.no_cache = 1 + if not has_course_moderator_role(): + message = "Only Moderators have access to this page." + if frappe.session.user == "Guest": + message = "Please login to access this page." + + raise frappe.PermissionError(_(message)) + student = frappe.form_dict["username"] classname = frappe.form_dict["classname"] @@ -20,7 +28,6 @@ def get_context(context): "course": course.course }, ["progress"], as_dict=True) course.quizzes = frappe.get_all("LMS Quiz", {"course": course.course}, ["name", "title"]) - course.assignments = frappe.get_all("Lesson Assignment", {"course": course.course}, ["name", "assignment"]) + course.assignments = frappe.get_all("Course Lesson", {"course": course.course, "question": ["is", "set"]}, ["name", "title"]) - print(class_courses) context.class_courses = class_courses From 74210245cf75c7fdc337bcf6a6babc8bda4e06cc Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 18 Nov 2022 17:05:38 +0530 Subject: [PATCH 06/10] feat: assignment submission and ui --- lms/hooks.py | 43 ++++++----- lms/lms/doctype/class_course/class_course.py | 1 + .../doctype/class_student/class_student.js | 3 +- .../doctype/class_student/class_student.py | 1 + .../lesson_assignment/lesson_assignment.py | 11 ++- lms/lms/doctype/lms_class/lms_class.js | 3 +- lms/lms/doctype/lms_class/lms_class.py | 35 ++++----- lms/lms/doctype/lms_quiz/lms_quiz.py | 8 +-- lms/lms/web_form/class/class.js | 4 +- lms/lms/web_form/class/class.py | 1 + lms/patches/v0_0/change_role_names.py | 1 + lms/plugins.py | 3 +- lms/public/css/style.css | 25 ++++++- lms/public/js/common_functions.js | 3 - lms/www/assignments/__init__.py | 0 lms/www/assignments/assignment.html | 63 +++++++++++----- lms/www/assignments/assignment.js | 50 +++++++++++++ lms/www/assignments/assignment.py | 8 ++- lms/www/classes/class.html | 11 +-- lms/www/classes/class.js | 71 ++++++++++--------- lms/www/classes/class.py | 24 ++++--- lms/www/classes/index.py | 4 +- lms/www/classes/progress.html | 6 +- lms/www/classes/progress.py | 35 ++++++--- lms/www/courses/index.js | 4 +- 25 files changed, 284 insertions(+), 134 deletions(-) create mode 100644 lms/www/assignments/__init__.py create mode 100644 lms/www/assignments/assignment.js diff --git a/lms/hooks.py b/lms/hooks.py index ea03c729..52a1a34f 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -96,7 +96,7 @@ override_doctype_class = { doc_events = { "Discussion Reply": {"after_insert": "lms.lms.utils.create_notification_log"}, - "Course Lesson": {"on_update": "lms.lms.doctype.lms_quiz.lms_quiz.update_lesson_info"} + "Course Lesson": {"on_update": "lms.lms.doctype.lms_quiz.lms_quiz.update_lesson_info"}, } # Scheduled Tasks @@ -138,29 +138,40 @@ website_route_rules = [ {"from_route": "/courses/", "to_route": "courses/course"}, {"from_route": "/courses//", "to_route": "courses/certificate"}, {"from_route": "/courses//learn", "to_route": "batch/learn"}, - {"from_route": "/courses//learn/.", - "to_route": "batch/learn"}, + { + "from_route": "/courses//learn/.", + "to_route": "batch/learn", + }, {"from_route": "/quizzes", "to_route": "batch/quiz_list"}, {"from_route": "/quizzes/", "to_route": "batch/quiz"}, {"from_route": "/classes/", "to_route": "classes/class"}, {"from_route": "/courses//progress", "to_route": "batch/progress"}, {"from_route": "/courses//join", "to_route": "batch/join"}, {"from_route": "/courses//manage", "to_route": "cohorts"}, - {"from_route": "/courses//cohorts/", - "to_route": "cohorts/cohort"}, - {"from_route": "/courses//cohorts//", - "to_route": "cohorts/cohort"}, - {"from_route": "/courses//subgroups//", - "to_route": "cohorts/subgroup"}, - {"from_route": "/courses//subgroups///", - "to_route": "cohorts/subgroup"}, - {"from_route": "/courses//join///", - "to_route": "cohorts/join"}, + {"from_route": "/courses//cohorts/", "to_route": "cohorts/cohort"}, + { + "from_route": "/courses//cohorts//", + "to_route": "cohorts/cohort", + }, + { + "from_route": "/courses//subgroups//", + "to_route": "cohorts/subgroup", + }, + { + "from_route": "/courses//subgroups///", + "to_route": "cohorts/subgroup", + }, + { + "from_route": "/courses//join///", + "to_route": "cohorts/join", + }, {"from_route": "/users", "to_route": "profiles/profile"}, {"from_route": "/jobs/", "to_route": "jobs/job"}, - {"from_route": "/classes//students/", - "to_route": "/classes/progress"}, - {"from_route": "/assignments/", "to_route": "assignments/assignment"} + { + "from_route": "/classes//students/", + "to_route": "/classes/progress", + }, + {"from_route": "/assignments/", "to_route": "assignments/assignment"}, ] website_redirects = [ diff --git a/lms/lms/doctype/class_course/class_course.py b/lms/lms/doctype/class_course/class_course.py index 17aac44b..64b9f410 100644 --- a/lms/lms/doctype/class_course/class_course.py +++ b/lms/lms/doctype/class_course/class_course.py @@ -4,5 +4,6 @@ # import frappe from frappe.model.document import Document + class ClassCourse(Document): pass diff --git a/lms/lms/doctype/class_student/class_student.js b/lms/lms/doctype/class_student/class_student.js index 20668248..69567d23 100644 --- a/lms/lms/doctype/class_student/class_student.js +++ b/lms/lms/doctype/class_student/class_student.js @@ -1,8 +1,7 @@ // Copyright (c) 2022, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('Class Student', { +frappe.ui.form.on("Class Student", { // refresh: function(frm) { - // } }); diff --git a/lms/lms/doctype/class_student/class_student.py b/lms/lms/doctype/class_student/class_student.py index 74c8df36..cfe37fa1 100644 --- a/lms/lms/doctype/class_student/class_student.py +++ b/lms/lms/doctype/class_student/class_student.py @@ -4,5 +4,6 @@ # import frappe from frappe.model.document import Document + class ClassStudent(Document): pass diff --git a/lms/lms/doctype/lesson_assignment/lesson_assignment.py b/lms/lms/doctype/lesson_assignment/lesson_assignment.py index 426ee0ae..83507aba 100644 --- a/lms/lms/doctype/lesson_assignment/lesson_assignment.py +++ b/lms/lms/doctype/lesson_assignment/lesson_assignment.py @@ -12,7 +12,8 @@ class LessonAssignment(Document): def validate_duplicates(self): if frappe.db.exists( - "Lesson Assignment", {"lesson": self.lesson, "member": self.member, "name": ["!=", self.name]} + "Lesson Assignment", + {"lesson": self.lesson, "member": self.member, "name": ["!=", self.name]}, ): lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title") frappe.throw( @@ -50,3 +51,11 @@ def get_assignment(lesson): "File", {"file_url": assignment.assignment}, "file_name" ) return assignment + + +@frappe.whitelist() +def grade_assignment(name, result, comments): + doc = frappe.get_doc("Lesson Assignment", name) + doc.status = result + doc.comments = comments + doc.save() diff --git a/lms/lms/doctype/lms_class/lms_class.js b/lms/lms/doctype/lms_class/lms_class.js index dca66f76..78508cbf 100644 --- a/lms/lms/doctype/lms_class/lms_class.js +++ b/lms/lms/doctype/lms_class/lms_class.js @@ -1,8 +1,7 @@ // Copyright (c) 2022, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('LMS Class', { +frappe.ui.form.on("LMS Class", { // refresh: function(frm) { - // } }); diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py index d7495aff..281bbe78 100644 --- a/lms/lms/doctype/lms_class/lms_class.py +++ b/lms/lms/doctype/lms_class/lms_class.py @@ -6,8 +6,8 @@ from frappe.model.document import Document from frappe import _ from frappe.utils import cint -class LMSClass(Document): +class LMSClass(Document): def validate(self): validate_membership(self) @@ -18,7 +18,7 @@ def validate_membership(self): filters = { "doctype": "LMS Batch Membership", "member": student.student, - "course": course.course + "course": course.course, } if not frappe.db.exists(filters): frappe.get_doc(filters).save() @@ -29,36 +29,37 @@ 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.")) - 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() + 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.db.delete("Class Student", { - "student": student, - "parent": class_name - }) + frappe.db.delete("Class Student", {"student": student, "parent": class_name}) return True @frappe.whitelist() def update_course(class_name, course, value): if cint(value): - doc = frappe.get_doc({ + doc = frappe.get_doc( + { "doctype": "Class Course", "parent": class_name, "course": course, "parenttype": "LMS Class", - "parentfield": "courses" - }) + "parentfield": "courses", + } + ) doc.save() else: frappe.db.delete("Class Course", {"parent": class_name, "course": course}) diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.py b/lms/lms/doctype/lms_quiz/lms_quiz.py index 539eb33d..6d5b4a47 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/lms_quiz.py @@ -62,10 +62,10 @@ class LMSQuiz(Document): def update_lesson_info(doc, method): if doc.quiz_id: - frappe.db.set_value("LMS Quiz", doc.quiz_id, { - "lesson": doc.name, - "course": doc.course - }) + frappe.db.set_value( + "LMS Quiz", doc.quiz_id, {"lesson": doc.name, "course": doc.course} + ) + @frappe.whitelist() def quiz_summary(quiz, results): diff --git a/lms/lms/web_form/class/class.js b/lms/lms/web_form/class/class.js index 699703c5..8f56ebb3 100644 --- a/lms/lms/web_form/class/class.js +++ b/lms/lms/web_form/class/class.js @@ -1,3 +1,3 @@ -frappe.ready(function() { +frappe.ready(function () { // bind events here -}) \ No newline at end of file +}); diff --git a/lms/lms/web_form/class/class.py b/lms/lms/web_form/class/class.py index e1ada619..80b7b873 100644 --- a/lms/lms/web_form/class/class.py +++ b/lms/lms/web_form/class/class.py @@ -1,5 +1,6 @@ import frappe + def get_context(context): # do your magic here pass diff --git a/lms/patches/v0_0/change_role_names.py b/lms/patches/v0_0/change_role_names.py index 9653ef6f..3e01336f 100644 --- a/lms/patches/v0_0/change_role_names.py +++ b/lms/patches/v0_0/change_role_names.py @@ -1,5 +1,6 @@ import frappe + def execute(): frappe.rename_doc("Role", "Course Instructor", "Instructor") frappe.rename_doc("Role", "Course Moderator", "Moderator") diff --git a/lms/plugins.py b/lms/plugins.py index f20f94dc..f542143f 100644 --- a/lms/plugins.py +++ b/lms/plugins.py @@ -152,7 +152,8 @@ def assignment_renderer(detail): file_type = detail.split("-")[1] accept = supported_types[file_type] if file_type else "" return frappe.render_template( - "templates/assignment.html", {"question": question, "accept": accept, "file_type": file_type} + "templates/assignment.html", + {"question": question, "accept": accept, "file_type": file_type}, ) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 5c7b7ca2..acd82e96 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -895,6 +895,7 @@ pre { .column-card { flex-direction: column; padding: 1.25rem; + height: 100%; } .empty-state { @@ -1674,9 +1675,9 @@ li { } .indicator-pill::before { - width: 0; - height: 0; - margin-right: 0; + width: 0 !important; + height: 0 !important; + margin-right: 0 !important; } .role { @@ -1855,4 +1856,22 @@ select { color: var(--gray-900); font-weight: 500; border-bottom: 1px solid var(--gray-300); + border-top: none; +} + +.lms-dropdown { + border: 1px solid var(--gray-400); + border-radius: var(--border-radius-sm); + padding: 0.25rem 2rem; + cursor: pointer; + text-align: center; +} + +.lms-menu { + background-image: url(/assets/lms/icons/down-arrow.svg); + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 0.75rem; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; } diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index 542c32e3..9b15f6a9 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -205,7 +205,6 @@ const render_chart = (data, chart_name, element, type) => { }); }; - const generate_course_completion_graph = () => { frappe.call({ method: "lms.lms.utils.get_course_completion_data", @@ -220,12 +219,10 @@ const generate_course_completion_graph = () => { }); }; - const change_hash = (e) => { window.location.hash = $(e.currentTarget).attr("href"); }; - const open_tab = () => { $(`a[href="${window.location.hash}"]`).click(); }; diff --git a/lms/www/assignments/__init__.py b/lms/www/assignments/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/www/assignments/assignment.html b/lms/www/assignments/assignment.html index 7165a6c8..f56cb38a 100644 --- a/lms/www/assignments/assignment.html +++ b/lms/www/assignments/assignment.html @@ -8,26 +8,53 @@
-
{{ _("Save") }}
-
{{ _("Assignments") }}
-
-
- -
- +
{{ _("Assignment Grading") }}
+
+ + {{ _("Open Attachment") }} + + + +
+ + {{ _("Member") }}: + + + {{ assignment.member_name }} + +
+
+ {% set course_title = frappe.db.get_value("LMS Course", assignment.course, "title") %} + + {{ _("Course") }}: + + + {{ course_title }} + +
+
+ {% set lesson_title = frappe.db.get_value("Course Lesson", assignment.lesson, "title") %} + {{ _("Lesson") }}: + + {{ lesson_title }} + +
+ +
{{ _("Comments") }}:
+
+
+
-
-
{% if assignment.comments %}{{ assignment.comments }}{% endif %}
+ +
+ {{ _("Save") }}
diff --git a/lms/www/assignments/assignment.js b/lms/www/assignments/assignment.js new file mode 100644 index 00000000..7995e672 --- /dev/null +++ b/lms/www/assignments/assignment.js @@ -0,0 +1,50 @@ +frappe.ready(() => { + + this.result; + let self = this; + + set_result(); + + $("#save-assignment").click((e) => { + save_assignment(e); + }); + + $("#result").change((e) => { + $("#result option:selected").each(function () { + self.result = $(this).val(); + }); + }); + +}); + + +const set_result = () => { + let self = this; + let result = $("#result").data("type"); + if (result) { + $("#result option").each((i, elem) => { + if ($(elem).val() == result) { + $(elem).attr("selected", true); + self.result = result; + } + }); + } +}; + + +const save_assignment = (e) => { + frappe.call({ + method: "lms.lms.doctype.lesson_assignment.lesson_assignment.grade_assignment", + args: { + "name": $(e.currentTarget).data("assignment"), + "result": self.result, + "comments": $("#comments").val(), + }, + callback: (data) => { + frappe.show_alert({ + message: __("Saved"), + indicator: "green", + }); + } + }) +} diff --git a/lms/www/assignments/assignment.py b/lms/www/assignments/assignment.py index ebf38eed..dbbd5509 100644 --- a/lms/www/assignments/assignment.py +++ b/lms/www/assignments/assignment.py @@ -2,6 +2,7 @@ import frappe from lms.lms.utils import has_course_moderator_role from frappe import _ + def get_context(context): context.no_cache = 1 assignment = frappe.form_dict["assignment"] @@ -13,4 +14,9 @@ def get_context(context): raise frappe.PermissionError(_(message)) - context.assignment = frappe.db.get_value("Lesson Assignment", assignment, ["assignment", "comments", "status", "name"], as_dict=True) + context.assignment = frappe.db.get_value( + "Lesson Assignment", + assignment, + ["assignment", "comments", "status", "name", "member_name", "course", "lesson"], + as_dict=True, + ) diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index 31f650fe..d2e1ccd2 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -33,9 +33,11 @@
{{ class_info.title }}
+ {% if class_info.description %}
{{ class_info.description }}
+ {% endif %}
{% if class_info.start_date %} @@ -108,18 +110,19 @@ {% if class_students | length %}
{% for student in class_students %} -
- {{ student.student_name }} + {% if not loop.last %}
{% endif %} {% endfor %}
{% else %} -

{{ _("No Students are added to this class.") }}

+

{{ _("No Students are added to this class.") }}

{% endif %}
{% endmacro %} diff --git a/lms/www/classes/class.js b/lms/www/classes/class.js index 3e9ce267..23b9c3ca 100644 --- a/lms/www/classes/class.js +++ b/lms/www/classes/class.js @@ -1,5 +1,4 @@ frappe.ready(() => { - $("#submit-student").click((e) => { submit_student(e); }); @@ -11,57 +10,61 @@ frappe.ready(() => { $(".class-course").click((e) => { update_course(e); }); - }); - const submit_student = (e) => { e.preventDefault(); frappe.call({ method: "lms.lms.doctype.lms_class.lms_class.add_student", args: { - "email": $("#student-email").val(), - "class_name": $(".class-details").data("class") + email: $("#student-email").val(), + class_name: $(".class-details").data("class"), }, callback: (data) => { - frappe.show_alert({ + frappe.show_alert( + { message: __("Student added successfully"), indicator: "green", - } ,3); + }, + 3 + ); window.location.reload(); - } - }) + }, + }); }; - const remove_student = (e) => { - frappe.confirm("Are you sure you want to remove this student from the class?", - () => { - frappe.call({ - method: "lms.lms.doctype.lms_class.lms_class.remove_student", - args: { - "student": $(e.currentTarget).data("student"), - "class_name": $(".class-details").data("class") - }, - callback: (data) => { - frappe.show_alert({ - message: __("Student removed successfully"), - indicator: "green", - }, 3); - window.location.reload(); - } - }); - }) -} - + frappe.confirm( + "Are you sure you want to remove this student from the class?", + () => { + frappe.call({ + method: "lms.lms.doctype.lms_class.lms_class.remove_student", + args: { + student: $(e.currentTarget).data("student"), + class_name: $(".class-details").data("class"), + }, + callback: (data) => { + frappe.show_alert( + { + message: __("Student removed successfully"), + indicator: "green", + }, + 3 + ); + window.location.reload(); + }, + }); + } + ); +}; const update_course = (e) => { frappe.call({ method: "lms.lms.doctype.lms_class.lms_class.update_course", args: { - "course": $(e.currentTarget).data("course"), - "value": $(e.currentTarget).children("input").prop("checked") ? 1 : 0, - "class_name": $(".class-details").data("class") - } - }) + course: $(e.currentTarget).data("course"), + value: $(e.currentTarget).children("input").prop("checked") ? 1 : 0, + class_name: $(".class-details").data("class"), + }, + }); }; diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py index 7eda4d07..14f598db 100644 --- a/lms/www/classes/class.py +++ b/lms/www/classes/class.py @@ -1,7 +1,6 @@ import frappe from lms.lms.utils import has_course_moderator_role from frappe import _ -from lms.lms.utils import has_course_moderator_role def get_context(context): @@ -16,13 +15,20 @@ def get_context(context): class_name = frappe.form_dict["classname"] - context.class_info = frappe.db.get_value("LMS Class", class_name, ["name", "title", "start_date", "end_date", "description"], as_dict=True) - context.published_courses = frappe.get_all("LMS Course", {"published": 1}, ["name", "title"]) + context.class_info = frappe.db.get_value( + "LMS Class", + class_name, + ["name", "title", "start_date", "end_date", "description"], + as_dict=True, + ) + context.published_courses = frappe.get_all( + "LMS Course", {"published": 1}, ["name", "title"] + ) - context.class_courses = frappe.get_all("Class Course", { - "parent": class_name - }, pluck="course") + context.class_courses = frappe.get_all( + "Class Course", {"parent": class_name}, pluck="course" + ) - context.class_students = frappe.get_all("Class Student", { - "parent": class_name - }, ["student", "student_name", "username"]) + context.class_students = frappe.get_all( + "Class Student", {"parent": class_name}, ["student", "student_name", "username"] + ) diff --git a/lms/www/classes/index.py b/lms/www/classes/index.py index 0f0c030f..7f5153f6 100644 --- a/lms/www/classes/index.py +++ b/lms/www/classes/index.py @@ -13,4 +13,6 @@ def get_context(context): raise frappe.PermissionError(_(message)) - context.classes = frappe.get_all("LMS Class", fields=["name", "title", "start_date", "end_date"]) + context.classes = frappe.get_all( + "LMS Class", fields=["name", "title", "start_date", "end_date"] + ) diff --git a/lms/www/classes/progress.html b/lms/www/classes/progress.html index 0fdacccc..0eb1f5b4 100644 --- a/lms/www/classes/progress.html +++ b/lms/www/classes/progress.html @@ -33,6 +33,7 @@ {% macro Progress(class_info, student) %}
{% for course in class_courses %} + {% set progress = course.membership.progress %}
{{ course.title }}
@@ -56,11 +57,12 @@ {{ _("Last Attempt Date") }} - {% for quiz in course.quizzes %} + {% for quiz in course.quizzes %} {% set filters = { "member": student.name, "course": course.course } %} {% set has_submitted = frappe.db.exists("LMS Quiz Submission", filters) %} {% set submission = frappe.db.get_value("LMS Quiz Submission", filters, ["score", "creation"], as_dict=True) %} + {% set total_questions = frappe.db.count("LMS Quiz Question", {"parent": quiz.name}) %} @@ -71,7 +73,7 @@ {% if has_submitted %} - {{ submission.score }} + {{ submission.score }}/{{ total_questions }} {{ frappe.utils.format_date(submission.creation, "medium") }} diff --git a/lms/www/classes/progress.py b/lms/www/classes/progress.py index ba2fd726..88b7397f 100644 --- a/lms/www/classes/progress.py +++ b/lms/www/classes/progress.py @@ -2,6 +2,7 @@ import frappe from lms.lms.utils import has_course_moderator_role from frappe import _ + def get_context(context): context.no_cache = 1 @@ -15,19 +16,31 @@ def get_context(context): student = frappe.form_dict["username"] classname = frappe.form_dict["classname"] - context.student = frappe.db.get_value("User", {"username": student}, ["first_name", "full_name", "name"], as_dict=True) - context.class_info = frappe.db.get_value("LMS Class", classname, ["name"], as_dict=True) + context.student = frappe.db.get_value( + "User", {"username": student}, ["first_name", "full_name", "name"], as_dict=True + ) + context.class_info = frappe.db.get_value( + "LMS Class", classname, ["name"], as_dict=True + ) - class_courses = frappe.get_all("Class Course", { - "parent": classname - }, ["course", "title"]) + class_courses = frappe.get_all( + "Class Course", {"parent": classname}, ["course", "title"] + ) for course in class_courses: - course.membership = frappe.db.get_value("LMS Batch Membership", { - "member": context.student.name, - "course": course.course - }, ["progress"], as_dict=True) - course.quizzes = frappe.get_all("LMS Quiz", {"course": course.course}, ["name", "title"]) - course.assignments = frappe.get_all("Course Lesson", {"course": course.course, "question": ["is", "set"]}, ["name", "title"]) + course.membership = frappe.db.get_value( + "LMS Batch Membership", + {"member": context.student.name, "course": course.course}, + ["progress"], + as_dict=True, + ) + course.quizzes = frappe.get_all( + "LMS Quiz", {"course": course.course}, ["name", "title"] + ) + course.assignments = frappe.get_all( + "Course Lesson", + {"course": course.course, "question": ["is", "set"]}, + ["name", "title"], + ) context.class_courses = class_courses diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js index a78fd836..d6b84fca 100644 --- a/lms/www/courses/index.js +++ b/lms/www/courses/index.js @@ -1,6 +1,4 @@ -frappe.ready(() => { - -}); +frappe.ready(() => {}); const change_hash = (e) => { window.location.hash = $(e.currentTarget).attr("href"); From ed2fababffe617d0e8b8ba67009cd028bcc9c838 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 21 Nov 2022 12:08:17 +0530 Subject: [PATCH 07/10] feat: assignment comments display --- .../lesson_assignment/lesson_assignment.py | 2 +- lms/lms/doctype/lms_class/lms_class.json | 8 +- lms/lms/web_form/class/class.json | 6 +- lms/public/css/style.css | 807 +++++++++--------- lms/templates/assignment.html | 11 +- lms/templates/quiz.html | 181 ++-- lms/www/batch/learn.js | 14 + lms/www/classes/index.html | 63 +- 8 files changed, 569 insertions(+), 523 deletions(-) diff --git a/lms/lms/doctype/lesson_assignment/lesson_assignment.py b/lms/lms/doctype/lesson_assignment/lesson_assignment.py index 83507aba..9a22b52e 100644 --- a/lms/lms/doctype/lesson_assignment/lesson_assignment.py +++ b/lms/lms/doctype/lesson_assignment/lesson_assignment.py @@ -44,7 +44,7 @@ def get_assignment(lesson): assignment = frappe.db.get_value( "Lesson Assignment", {"lesson": lesson, "member": frappe.session.user}, - ["lesson", "member", "assignment"], + ["lesson", "member", "assignment", "comments", "status"], as_dict=True, ) assignment.file_name = frappe.db.get_value( diff --git a/lms/lms/doctype/lms_class/lms_class.json b/lms/lms/doctype/lms_class/lms_class.json index f90a0f30..4cbaaeb9 100644 --- a/lms/lms/doctype/lms_class/lms_class.json +++ b/lms/lms/doctype/lms_class/lms_class.json @@ -28,7 +28,8 @@ { "fieldname": "end_date", "fieldtype": "Date", - "label": "End Date" + "label": "End Date", + "reqd": 1 }, { "fieldname": "column_break_4", @@ -58,12 +59,13 @@ { "fieldname": "start_date", "fieldtype": "Date", - "label": "Start Date" + "label": "Start Date", + "reqd": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-11-14 17:08:03.206840", + "modified": "2022-11-21 10:55:50.067225", "modified_by": "Administrator", "module": "LMS", "name": "LMS Class", diff --git a/lms/lms/web_form/class/class.json b/lms/lms/web_form/class/class.json index c98783da..f46c2faa 100644 --- a/lms/lms/web_form/class/class.json +++ b/lms/lms/web_form/class/class.json @@ -20,7 +20,7 @@ "list_columns": [], "login_required": 0, "max_attachment_size": 0, - "modified": "2022-11-11 12:23:14.664297", + "modified": "2022-11-21 10:56:01.627821", "modified_by": "Administrator", "module": "LMS", "name": "class", @@ -56,7 +56,7 @@ "max_length": 0, "max_value": 0, "read_only": 0, - "reqd": 0, + "reqd": 1, "show_in_filter": 0 }, { @@ -68,7 +68,7 @@ "max_length": 0, "max_value": 0, "read_only": 0, - "reqd": 0, + "reqd": 1, "show_in_filter": 0 }, { diff --git a/lms/public/css/style.css b/lms/public/css/style.css index acd82e96..1a70cfc4 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -11,19 +11,19 @@ body { input[type=checkbox] { appearance: auto; position: relative; - width: var(--checkbox-size)!important; - height: var(--checkbox-size); - margin-right: var(--checkbox-right-margin)!important; - background-repeat: no-repeat; - background-position: center; - border: 1px solid var(--gray-400); - box-sizing: border-box; - box-shadow: 0 1px 2px #0000001a; - border-radius: 4px; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - -webkit-print-color-adjust: exact; + width: var(--checkbox-size)!important; + height: var(--checkbox-size); + margin-right: var(--checkbox-right-margin)!important; + background-repeat: no-repeat; + background-position: center; + border: 1px solid var(--gray-400); + box-sizing: border-box; + box-shadow: 0 1px 2px #0000001a; + border-radius: 4px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-print-color-adjust: exact; } .course-image { @@ -58,32 +58,32 @@ input[type=checkbox] { } .course-image .course-tags { - width: fit-content; + width: fit-content; } .course-card-pills { - background: #ffffff; - margin-left: 0; - margin-right: 0.5rem; - border-radius: var(--border-radius); - padding: 3.5px 8px; - font-size: 11px; - text-align: center; - letter-spacing: 0.011em; - text-transform: uppercase; - font-weight: 600; - color: var(--gray-900); - width: fit-content; - box-shadow: var(--shadow-sm); + background: #ffffff; + margin-left: 0; + margin-right: 0.5rem; + border-radius: var(--border-radius); + padding: 3.5px 8px; + font-size: 11px; + text-align: center; + letter-spacing: 0.011em; + text-transform: uppercase; + font-weight: 600; + color: var(--gray-900); + width: fit-content; + box-shadow: var(--shadow-sm); } .dark-pills { - background: rgba(25, 39, 52, 0.8); - color: #ffffff; + background: rgba(25, 39, 52, 0.8); + color: #ffffff; } .dark-pills img { - width: 0.75rem; - height: 0.75rem; + width: 0.75rem; + height: 0.75rem; } .common-page-style { @@ -97,7 +97,7 @@ input[type=checkbox] { background: #FFFFFF; border-radius: var(--border-radius-md); position: relative; - box-shadow: var(--shadow-sm); + box-shadow: var(--shadow-base); } .course-card { @@ -139,10 +139,10 @@ input[type=checkbox] { } .course-card-title { - font-weight: 600; - color: var(--gray-900); - margin-bottom: 1.25rem; - font-size: 1.125rem; + font-weight: 600; + color: var(--gray-900); + margin-bottom: 1.25rem; + font-size: 1.125rem; } .card-divider { @@ -162,7 +162,7 @@ input[type=checkbox] { @media (max-width: 400px) { .course-instructor { - margin-left: 0; + margin-left: 0; } } @@ -202,26 +202,26 @@ input[type=checkbox] { @media (max-width: 767px) { .cards-parent { - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - -moz-column-gap: 16px; - column-gap: 16px; - row-gap: 16px; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + -moz-column-gap: 16px; + column-gap: 16px; + row-gap: 16px; } } @media (max-width: 375px) { .cards-parent { - grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); - -moz-column-gap: 24px; - column-gap: 24px; - row-gap: 24px; + grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); + -moz-column-gap: 24px; + column-gap: 24px; + row-gap: 24px; } } @media (min-width: 576px) and (max-width: 992px) { .container { - padding-left: 1rem; - padding-right: 1rem; + padding-left: 1rem; + padding-right: 1rem; } } @@ -291,15 +291,15 @@ input[type=checkbox] { @media (max-width: 1000px) { .course-card-wide { - width: 75%; - margin: 0 auto; + width: 75%; + margin: 0 auto; } } @media (max-width: 768px) { .course-card-wide { - width: 100%; - margin: 0; + width: 100%; + margin: 0; } } @@ -344,7 +344,7 @@ input[type=checkbox] { @media (max-width: 768px) { .wide-button { - padding: 0.5rem 4rem; + padding: 0.5rem 4rem; } } @@ -378,7 +378,7 @@ input[type=checkbox] { } .course-home-page .course-home-outline { - padding-bottom: 4rem; + padding-bottom: 4rem; } .course-home-page { @@ -387,16 +387,16 @@ input[type=checkbox] { } .chapter-title { - cursor: pointer; - border-radius: var(--border-radius-lg); - color: var(--gray-900); - display: flex; - align-items: center; + cursor: pointer; + border-radius: var(--border-radius-lg); + color: var(--gray-900); + display: flex; + align-items: center; } .chapter-description { - color: var(--gray-900); - font-size: var(--text-sm); + color: var(--gray-900); + font-size: var(--text-sm); } .course-content-parent .chapter-description { @@ -419,10 +419,10 @@ input[type=checkbox] { } .lesson-links { - display: flex; - align-items: center; - padding: 0.5rem; - color: var(--gray-900); + display: flex; + align-items: center; + padding: 0.5rem; + color: var(--gray-900); } .lesson-links:hover { @@ -433,7 +433,7 @@ input[type=checkbox] { } .lessons { - margin-left: 1.5rem; + margin-left: 1.5rem; } .member-card { @@ -444,9 +444,9 @@ input[type=checkbox] { } .break { - flex-basis: 100%; - flex-grow: 1; - margin: 0.5rem 0; + flex-basis: 100%; + flex-grow: 1; + margin: 0.5rem 0; } .course-home-headings { @@ -487,8 +487,8 @@ input[type=checkbox] { @media (max-width: 500px) { .avatar-square { - width: 75px; - height: 75px; + width: 75px; + height: 75px; } } @@ -502,10 +502,10 @@ input[type=checkbox] { @media (max-width: 600px) { .member-parent { - grid-template-columns: repeat(auto-fill, minmax(125px, 1fr)); - -moz-column-gap: 2rem; - column-gap: 2rem; - row-gap: 2rem; + grid-template-columns: repeat(auto-fill, minmax(125px, 1fr)); + -moz-column-gap: 2rem; + column-gap: 2rem; + row-gap: 2rem; } } @@ -524,7 +524,7 @@ input[type=checkbox] { @media (max-width: 600px) { .review-modl .modal-dialog { - width: auto; + width: auto; } } @@ -573,12 +573,12 @@ input[type=checkbox] { } .lesson-content { - padding: 1.5rem; - flex-direction: column; + padding: 1.5rem; + flex-direction: column; } .lesson-content-card { - margin-top: 2rem; + margin-top: 2rem; } .lesson-content-card .alert-dismissible .close { @@ -593,21 +593,21 @@ input[type=checkbox] { @media (max-width: 1024px) { .course-content-parent { - display: flex; - flex-direction: column-reverse; + display: flex; + flex-direction: column-reverse; } } .course-content-parent .course-home-headings { - margin: 0 0 1rem; - width: 100%; + margin: 0 0 1rem; + width: 100%; } .lesson-pagination { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 2rem + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 2rem } .lesson-pagination-parent { @@ -616,7 +616,7 @@ input[type=checkbox] { @media (max-width: 768px) { .lesson-pagination-parent { - margin-left: 0px; + margin-left: 0px; } } @@ -647,7 +647,7 @@ input[type=checkbox] { @media (max-width: 500px) { .profile-banner { - height: 150px; + height: 150px; } } @@ -666,9 +666,9 @@ input[type=checkbox] { @media (max-width: 550px) { .profile-info { - align-items: flex-end; - padding-left: 0; - height: 150px; + align-items: flex-end; + padding-left: 0; + height: 150px; } } @@ -681,15 +681,15 @@ input[type=checkbox] { @media (max-width: 500px) { .profile-avatar { - top: 95px; - left: 10px; + top: 95px; + left: 10px; } } @media (max-width: 375px) { .profile-avatar { - top: 120px; - left: 10px; + top: 120px; + left: 10px; } } @@ -701,8 +701,8 @@ input[type=checkbox] { @media (max-width: 375px) { .profile-name { - font-size: var(--text-lg); - padding-top: 5px; + font-size: var(--text-lg); + padding-top: 5px; } } @@ -714,9 +714,9 @@ input[type=checkbox] { @media (max-width: 550px) { .profile-name-section { - flex-direction: column; - align-items: flex-end; - margin: 0 0 0.5rem; + flex-direction: column; + align-items: flex-end; + margin: 0 0 0.5rem; } } @@ -739,14 +739,14 @@ input[type=checkbox] { @media (max-width: 375px) { .creator-badge { - font-size: 8px; + font-size: 8px; } } @media (max-width: 550px) { .creator-badge { - margin-top: 0.25rem; - margin-left: 0; + margin-top: 0.25rem; + margin-left: 0; } } @@ -818,7 +818,7 @@ pre { } .markdown-source p:last-child { - margin-bottom: 0; + margin-bottom: 0; } .avatar img { @@ -826,34 +826,34 @@ pre { } .certificate-content { - background-color: #FFFFFF; - border-width: 10px; - border-style: solid; + background-color: #FFFFFF; + border-width: 10px; + border-style: solid; } @media (max-width: 500px) { - .certificate-content { - border-width: 50px; - } + .certificate-content { + border-width: 50px; + } } .certificate-footer { - display: flex; - justify-content: center; - margin: 4rem auto 0; - width: fit-content; + display: flex; + justify-content: center; + margin: 4rem auto 0; + width: fit-content; } .certificate-ribbon { - background-color: var(--primary-color); - padding: 0.5rem; - border-radius: var(--border-radius-md); + background-color: var(--primary-color); + padding: 0.5rem; + border-radius: var(--border-radius-md); } .certificate-heading { - font-size: 2rem; - font-weight: 500; - color: var(--text-color); + font-size: 2rem; + font-weight: 500; + color: var(--text-color); } .certificate-para { @@ -861,19 +861,19 @@ pre { } .certificate-card { - background: #FFFFFF; - border-radius: var(--border-radius-md); - position: relative; - box-shadow: var(--shadow-sm); - padding: 1rem; - text-align: center; + background: #FFFFFF; + border-radius: var(--border-radius-md); + position: relative; + box-shadow: var(--shadow-sm); + padding: 1rem; + text-align: center; } .certificate-footer-item { - color: var(--text-color); - font-weight: bold; - font-family: cursive; - font-size: 1.25rem; + color: var(--text-color); + font-weight: bold; + font-family: cursive; + font-size: 1.25rem; } .certificate-logo { @@ -881,20 +881,20 @@ pre { } @media (max-width: 768px) { - .certificate-card { - margin: 0; - } + .certificate-card { + margin: 0; + } } @media (max-width: 550px) { - .certificate-content { - padding: 1rem; - } + .certificate-content { + padding: 1rem; + } } .column-card { - flex-direction: column; - padding: 1.25rem; + flex-direction: column; + padding: 1.25rem; height: 100%; } @@ -908,7 +908,7 @@ pre { } .empty-state-text { - margin-left: 1rem; + margin-left: 1rem; } .empty-state-heading { @@ -937,42 +937,42 @@ pre { } .course-search-header { - float: right; - width: 80%; - display: flex; - justify-content: flex-end; - align-items: center; + float: right; + width: 80%; + display: flex; + justify-content: flex-end; + align-items: center; } @media (max-width: 1250px) { - .search { - width: 40%; - } + .search { + width: 40%; + } } @media (max-width: 1000px) { - .search { - width: 55%; - } + .search { + width: 55%; + } - .course-search-header { - width: 75%; - } + .course-search-header { + width: 75%; + } } @media (max-width: 650px) { - .course-search-header { - width: 60%; - } + .course-search-header { + width: 60%; + } } @media (max-width: 550px) { - .course-search-header { - float: none; - width: 100%; - justify-content: space-between; - margin-bottom: 1rem; - } + .course-search-header { + float: none; + width: 100%; + justify-content: space-between; + margin-bottom: 1rem; + } } .testimonial-card { @@ -993,11 +993,11 @@ pre { } .testimonial-footer { - display: flex; - align-items: center; - border-top: 1px solid var(--gray-200); - padding-top: 2rem; - margin-top: auto; + display: flex; + align-items: center; + border-top: 1px solid var(--gray-200); + padding-top: 2rem; + margin-top: auto; } .testimonial-profession { @@ -1055,7 +1055,7 @@ pre { @media (max-width: 500px) { .carousel { - padding: 0 0.5rem; + padding: 0 0.5rem; } } @@ -1105,22 +1105,22 @@ pre { @media (min-width: 768px) { .lesson-pagination .custom-checkbox .empty-checkbox { - width: 1rem; - height: 1rem; - border-radius: var(--border-radius-sm); + width: 1rem; + height: 1rem; + border-radius: var(--border-radius-sm); } } @media (max-width: 767px) { .lesson-pagination .custom-checkbox .empty-checkbox { - margin-bottom: 1rem; - border-radius: var(--border-radius-sm); + margin-bottom: 1rem; + border-radius: var(--border-radius-sm); } .lesson-pagination .custom-checkbox span { - display: inline-block; - width: 70%; - font-size: 10px; + display: inline-block; + width: 70%; + font-size: 10px; } } @@ -1133,23 +1133,24 @@ pre { } .preview-work { - width: 50%; + display: flex; + align-items: center; } .job-card { - position: relative; - padding: 1rem; + position: relative; + padding: 1rem; } .company-logo { - background-position: center; - background-size: contain; - background-position: center; - background-repeat: no-repeat; - border-radius: var(--border-radius-sm); - width: 50px; - height: 50px; - margin-right: 1rem; + background-position: center; + background-size: contain; + background-position: center; + background-repeat: no-repeat; + border-radius: var(--border-radius-sm); + width: 50px; + height: 50px; + margin-right: 1rem; } .job-card-parent { @@ -1158,9 +1159,9 @@ pre { } .job-card-logo-section { - display: flex; - align-items: center; - margin-top: 0.5rem; + display: flex; + align-items: center; + margin-top: 0.5rem; } .job-detail-card { @@ -1180,8 +1181,8 @@ pre { } .course-head-container { - color: var(--gray-900); - background-color: var(--gray-50); + color: var(--gray-900); + background-color: var(--gray-50); } .seperator { @@ -1203,12 +1204,12 @@ pre { @media (max-width: 1000px) { .course-overlay-card { - position: inherit; - margin: 1rem auto; + position: inherit; + margin: 1rem auto; } .seperator { - margin: 0 0.25rem; + margin: 0 0.25rem; } } @@ -1234,7 +1235,7 @@ pre { @media (max-width: 1000px) { .course-body-container { - width: 100%; + width: 100%; } } @@ -1277,25 +1278,25 @@ pre { @media (max-width: 1250px) { .reviews-header { - width: 85%; + width: 85%; } } @media (max-width: 768px) { .reviews-header { - width: 100%; + width: 100%; } } @media (max-width: 500px) { - .reviews-header { - flex-direction: column; - align-items: center; - } + .reviews-header { + flex-direction: column; + align-items: center; + } - .vertical-divider { - margin: 1rem; - } + .vertical-divider { + margin: 1rem; + } } .bold-heading { @@ -1314,8 +1315,8 @@ pre { } .vertical-divider { - border: 1px solid var(--gray-300); - margin: 0 1rem; + border: 1px solid var(--gray-300); + margin: 0 1rem; } .avg-rating-stars { @@ -1392,29 +1393,29 @@ pre { } .lms-nav .nav-link { - padding: var(--padding-sm) 0; - margin: 0 var(--margin-md); - font-size: var(--text-base); - color: var(--text-muted); + padding: var(--padding-sm) 0; + margin: 0 var(--margin-md); + font-size: var(--text-base); + color: var(--text-muted); } .lms-nav .nav-link.active { - font-weight: 500; - border-bottom: 1px solid var(--primary-color); - color: var(--primary-color); + font-weight: 500; + border-bottom: 1px solid var(--primary-color); + color: var(--primary-color); } @media (min-width: 500px) { - .lms-nav .nav-item:first-child .nav-link { - margin-left: 0; - } + .lms-nav .nav-item:first-child .nav-link { + margin-left: 0; + } } .dashboard-button { - position: relative; - top: -50px; - margin-left: auto; + position: relative; + top: -50px; + margin-left: auto; } .course-card-wide .breadcrumb { @@ -1426,300 +1427,300 @@ pre { } .btn-outline-primary { - border: 1px solid var(--primary-color); + border: 1px solid var(--primary-color); } .show-attachments { - padding-right: 0.5rem; - display: flex; - align-items: center; + padding-right: 0.5rem; + display: flex; + align-items: center; } .attachment-controls { - display: flex; - align-items: center; - width: fit-content; - cursor: pointer; + display: flex; + align-items: center; + width: fit-content; + cursor: pointer; } .attachments { - flex-direction: column; - padding: 0.5rem 0; - margin-top: 1rem; - position: absolute; - z-index: 1; - width: fit-content; - border-collapse: separate; - border-spacing: 1rem 0.5rem; + flex-direction: column; + padding: 0.5rem 0; + margin-top: 1rem; + position: absolute; + z-index: 1; + width: fit-content; + border-collapse: separate; + border-spacing: 1rem 0.5rem; } .attachments-parent { - color: var(--text-color); + color: var(--text-color); } li { - line-height: 1.7; + line-height: 1.7; } .course-overlay-title { - font-weight: 700; - font-size: var(--text-2xl); - line-height: 1rem; - color: var(--gray-900); - margin-bottom: 1.25rem; + font-weight: 700; + font-size: var(--text-2xl); + line-height: 1rem; + color: var(--gray-900); + margin-bottom: 1.25rem; } .course-card-wide .avatar .standard-image { - border: 1px solid var(--gray-400); + border: 1px solid var(--gray-400); } .lesson-progress-tick { - margin: 0 0.5rem + margin: 0 0.5rem } .no-preview { - color: var(--gray-600); + color: var(--gray-600); } .discussions-parent .empty-state { - background-color: var(--gray-200); + background-color: var(--gray-200); } .job-cards-parent { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(500px, 1fr)); - -moz-column-gap: 40px; - grid-gap: 1rem; - align-items: center; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(500px, 1fr)); + -moz-column-gap: 40px; + grid-gap: 1rem; + align-items: center; } .job-company { - display: flex; - align-items: center; + display: flex; + align-items: center; } .job-actions { - display: flex; - align-items: flex-start; - margin-left: auto; - margin-bottom: 1rem; + display: flex; + align-items: flex-start; + margin-left: auto; + margin-bottom: 1rem; } .job-detail-header { - display: flex; + display: flex; } @media (max-width: 600px) { - .job-company { - flex-direction: column; - align-items: inherit; - } + .job-company { + flex-direction: column; + align-items: inherit; + } } @media (max-width: 1200px) { - .job-cards-parent { - grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); - } + .job-cards-parent { + grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); + } } @media (max-width: 500px) { - .job-cards-parent { - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - } + .job-cards-parent { + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + } - .job-detail-header { - flex-wrap: wrap; - } + .job-detail-header { + flex-wrap: wrap; + } - .job-actions { - margin-top: 1rem; - } + .job-actions { + margin-top: 1rem; + } } [contenteditable="true"] { - outline: none; - background-color: var(--bg-light-gray); - border-radius: var(--border-radius); - border: 1px dashed var(--gray-600); - padding: 0.5rem 0.75rem; - color: var(--gray-900); + outline: none; + background-color: var(--bg-light-gray); + border-radius: var(--border-radius); + border: 1px dashed var(--gray-600); + padding: 0.5rem 0.75rem; + color: var(--gray-900); } [contenteditable="true"]:empty:before { - content: attr(data-placeholder); - color: var(--gray-600); + content: attr(data-placeholder); + color: var(--gray-600); } .course-image-attachment { - margin-top: 0.25rem; - background-color: var(--bg-light-gray); - border-radius: var(--border-radius); - border: 1px dashed var(--gray-600); - padding: 0.5rem 0.75rem; - width: fit-content; + margin-top: 0.25rem; + background-color: var(--bg-light-gray); + border-radius: var(--border-radius); + border: 1px dashed var(--gray-600); + padding: 0.5rem 0.75rem; + width: fit-content; } .btn-delete-tag { - cursor: pointer; + cursor: pointer; } .chapter-edit { - border: 1px solid var(--dark-border-color); - border-radius: var(--border-radius); - padding: 1rem; - margin-bottom: 1rem; + border: 1px solid var(--dark-border-color); + border-radius: var(--border-radius); + padding: 1rem; + margin-bottom: 1rem; } .chapter-edit .lessons { - margin-left: 0; - margin-top: 2rem; + margin-left: 0; + margin-top: 2rem; } .chapter-parent { - margin-bottom: 1rem; + margin-bottom: 1rem; } .chapter-edit .chapter-title { - padding: 0.5rem 0; + padding: 0.5rem 0; } .course-card-pills[contenteditable="true"] { - box-shadow: none; + box-shadow: none; } .preview { - display: flex; - align-items: center; - font-size: var(--text-md); + display: flex; + align-items: center; + font-size: var(--text-md); } .table { - margin-bottom: 0; + margin-bottom: 0; } .quiz-card { - border: 1px solid var(--dark-border-color); - border-radius: var(--border-radius); - padding: 1.25rem; - margin-top: 1.25rem; - font-size: var(--text-base); + border: 1px solid var(--dark-border-color); + border-radius: var(--border-radius); + padding: 1.25rem; + margin-top: 1.25rem; + font-size: var(--text-base); } .option-input { - width: 45%; - margin-right: 1rem; + width: 45%; + margin-right: 1rem; } .option-checkbox { - width: 15%; - display: flex; - align-items: center; + width: 15%; + display: flex; + align-items: center; } .preview-video-header { - position: relative; + position: relative; } .preview-info { - position: absolute; - top: 0; - right: -30px; + position: absolute; + top: 0; + right: -30px; } .tool-tip { - position: relative; - display: inline-block; + position: relative; + display: inline-block; } .tool-tip .tooltiptext { - visibility: hidden; - width: 30rem; - background-color: var(--gray-800); - color: var(--fg-color); - padding: 1rem; - border-radius: var(--border-radius-md); - position: absolute; - z-index: 1; - opacity: 0; - transition: opacity 0.3s; + visibility: hidden; + width: 30rem; + background-color: var(--gray-800); + color: var(--fg-color); + padding: 1rem; + border-radius: var(--border-radius-md); + position: absolute; + z-index: 1; + opacity: 0; + transition: opacity 0.3s; } .tool-tip:hover .tooltiptext { - visibility: visible; - opacity: 1; + visibility: visible; + opacity: 1; } .tooltiptext ul { - padding: 1rem; + padding: 1rem; } .medium { - font-size: var(--text-base); + font-size: var(--text-base); } .quiz-row { - position: relative; - color: var(--text-color); - cursor: pointer; + position: relative; + color: var(--text-color); + cursor: pointer; } .course-creation-link { - float: right; + float: right; } @media (max-width: 500px) { - .course-creation-link { - float: inherit; - margin-bottom: 1rem; - } + .course-creation-link { + float: inherit; + margin-bottom: 1rem; + } } .indicator-pill::before { - width: 0 !important; - height: 0 !important; - margin-right: 0 !important; + width: 0 !important; + height: 0 !important; + margin-right: 0 !important; } .role { - margin-bottom: 0; - cursor: pointer; + margin-bottom: 0; + cursor: pointer; } @media (min-width: 500px) { - .role:last-child { - margin-left: 5rem - } + .role:last-child { + margin-left: 5rem + } } .icon-xl { - width: 2.75rem; - height: 2.75rem; + width: 2.75rem; + height: 2.75rem; } .modal .comment-field { - height: 150px !important; - resize: auto !important; + height: 150px !important; + resize: auto !important; } .notification-card { - display: flex; - align-items: center; - margin-bottom: 1.5rem; - position: relative; + display: flex; + align-items: center; + margin-bottom: 1.5rem; + position: relative; } .notification-card:last-child { - margin-bottom: 0; + margin-bottom: 0; } .timestamp { - font-size: var(--text-xs); + font-size: var(--text-xs); } .stats-parent { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - grid-gap: 2rem; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + grid-gap: 2rem; } .statistics .stats-parent { @@ -1728,84 +1729,84 @@ li { } .stats-label { - color: var(--gray-900); - font-weight: 500; + color: var(--gray-900); + font-weight: 500; } .stats-value { - color: var(--gray-900); - font-weight: 500; - font-size: 1.5rem; - margin-top: 2rem; + color: var(--gray-900); + font-weight: 500; + font-size: 1.5rem; + margin-top: 2rem; } .indicator-pill.green::before { - height: 0; - width: 0; - border-radius: 0; - margin-right: 0; + height: 0; + width: 0; + border-radius: 0; + margin-right: 0; } .modal-header { - padding: 1.5rem 1.5rem 0 !important; + padding: 1.5rem 1.5rem 0 !important; } .modal-body { - padding: 0 1.5rem !important; + padding: 0 1.5rem !important; } .modal-content { - font-size: var(--text-base) !important; + font-size: var(--text-base) !important; } .modal-header, .modal-body { - margin-bottom: 1rem !important; + margin-bottom: 1rem !important; } .modal-header { - border-bottom: none !important; + border-bottom: none !important; } .modal-footer { - padding: 0.75rem 1.5rem !important; - border-top: none !important; - background-color: var(--gray-200) !important; + padding: 0.75rem 1.5rem !important; + border-top: none !important; + background-color: var(--gray-200) !important; } .modal-header .modal-title { - color: var(--gray-900); + color: var(--gray-900); } .frappe-chart .title { - font-size: 1rem; - font-weight: 500; - fill: var(--gray-900); + font-size: 1rem; + font-weight: 500; + fill: var(--gray-900); } .course-description-section { - padding-bottom: 4rem; + padding-bottom: 4rem; } input::file-selector-button { - border-radius: var(--border-radius); - font-size: var(--text-md); - padding: 0.25rem 1.25rem; - border: none; - color: var(--text-color); - cursor: pointer; + border-radius: var(--border-radius); + font-size: var(--text-md); + padding: 0.25rem 1.25rem; + border: none; + color: var(--text-color); + cursor: pointer; } input::file-selector-button:hover { - background-color: var(--gray-400); + background-color: var(--gray-400); } .btn { - font-weight: 400; + font-weight: 400; } select { - appearance: none; - -webkit-appearance: none; + appearance: none; + -webkit-appearance: none; } .course-list-cta { @@ -1861,17 +1862,17 @@ select { .lms-dropdown { border: 1px solid var(--gray-400); - border-radius: var(--border-radius-sm); - padding: 0.25rem 2rem; - cursor: pointer; + border-radius: var(--border-radius-sm); + padding: 0.25rem 2rem; + cursor: pointer; text-align: center; } .lms-menu { background-image: url(/assets/lms/icons/down-arrow.svg); - background-position: right 0.5rem center; - background-repeat: no-repeat; - background-size: 0.75rem; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 0.75rem; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; } diff --git a/lms/templates/assignment.html b/lms/templates/assignment.html index a0f04659..edee48ed 100644 --- a/lms/templates/assignment.html +++ b/lms/templates/assignment.html @@ -1,15 +1,22 @@
-

{{ _("Assignment") }}

+

{{ _("Assignment") }}

{{ _(question) }}
- {{ _("Only files of type {0} will be accepted").format(file_type) }} + {{ _("Only files of type {0} will be accepted.").format(file_type) }}
{{ _("Submit") }}
+
{{ _("Change") }}
+
+ + {{ _("Instructors Comments") }}: + + +
diff --git a/lms/templates/quiz.html b/lms/templates/quiz.html index babf9758..8629a2c9 100644 --- a/lms/templates/quiz.html +++ b/lms/templates/quiz.html @@ -1,114 +1,117 @@ {% if attempts_exceeded %}
-
{{ quiz.title }}
-
- {{ _("You have already exceeded the maximum number of attempts allowed for this quiz.") }} - {{ _("Your latest score is {0}.").format(last_attempt_score) }} -
+

+ {{ quiz.title }} +

+
+ {{ _("You have already exceeded the maximum number of attempts allowed for this quiz.") }} + {{ _("Your latest score is {0}.").format(last_attempt_score) }} +
{% else %} -
- {{ quiz.title }} -
-
- +
+ -
{{ quiz.title }}
+

+ {{ quiz.title }} +

-
- {{ _("This quiz consists of {0} questions.").format(quiz.questions | length) }} -
+
+ {{ _("This quiz consists of {0} questions.").format(quiz.questions | length) }} +
- {% if quiz.max_attempts %} - {% set suffix = "times" if quiz.max_attempts > 1 else "time" %} -
- {{ _("This quiz can only be taken {0} {1}. If you attempt the quiz but leave the page before submitting, - the quiz will be automatically submitted.").format(quiz.max_attempts, suffix) }} -
- {% endif %} + {% if quiz.max_attempts %} + {% set suffix = "times" if quiz.max_attempts > 1 else "time" %} +
+ {{ _("This quiz can only be taken {0} {1}. If you attempt the quiz but leave the page before submitting, + the quiz will be automatically submitted.").format(quiz.max_attempts, suffix) }} +
+ {% endif %} - {% if quiz.time %} -
- {{ _("The quiz has a time limit. For each question you will be given {0} seconds.").format(quiz.time) }} -
- {% endif %} + {% if quiz.time %} +
+ {{ _("The quiz has a time limit. For each question you will be given {0} seconds.").format(quiz.time) }} +
+ {% endif %} -
+
-
-
- {% for question in quiz.questions %} - {% set instruction = _("Choose all answers that apply") if question.multiple else _("Choose 1 answer") %} + +
+ {% for question in quiz.questions %} + {% set instruction = _("Choose all answers that apply") if question.multiple else _("Choose 1 answer") %} -
-
-
{{ loop.index }}.
-
- {{ frappe.utils.md_to_html(question.question) }} -
-
{{ instruction }}
-
+
+
+
{{ loop.index }}.
+
+ {{ frappe.utils.md_to_html(question.question) }} +
+
{{ instruction }}
+
- {% set options = [question.option_1, question.option_2, question.option_3, question.option_4] %} - {% for option in options %} - {% if option %} -
-
- -
+ {% set options = [question.option_1, question.option_2, question.option_3, question.option_4] %} + {% for option in options %} + {% if option %} +
+
+ +
- {% set explanation = question['explanation_' + loop.index | string] %} - {% if explanation %} - {{ explanation }} - {% endif %} -
- {% endif %} - {% endfor %} + {% set explanation = question['explanation_' + loop.index | string] %} + {% if explanation %} + {{ explanation }} + {% endif %} +
+ {% endif %} + {% endfor %} -
- {% endfor %} -
+
+ {% endfor %} +
-
+
{% endif %} diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 52a8621f..9e0ee674 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -412,10 +412,24 @@ const fetch_assignments = () => { callback: (data) => { if (data.message) { const assignment = data.message; + const status = assignment.status let target = $(".attach-file"); target.addClass("hide"); target.siblings(".submit-work").addClass("hide"); target.siblings(".preview-work").removeClass("hide"); + if(status != "Not Graded") { + let color = status == "Pass" ? "green": "red"; + $(".assignment-status") + .removeClass("hide") + .addClass(color) + .text(data.message.status) + target.siblings(".alert").addClass("hide"); + $(".clear-work").addClass("hide"); + if (assignment.comments) { + $(".comments").removeClass("hide"); + $(".comment").text(assignment.comments) + } + } target .siblings(".preview-work") .find("a") diff --git a/lms/www/classes/index.html b/lms/www/classes/index.html index e9aae9ab..065e1e1b 100644 --- a/lms/www/classes/index.html +++ b/lms/www/classes/index.html @@ -11,28 +11,7 @@
{{ _("All Classes") }}
{% if classes %} -
- {% for class in classes %} -
-
- {{ class.title }} -
-
- {% if class.start_date %} - - {{ frappe.utils.format_date(class.start_date, "medium") }} - - - {% endif %} - {% if class.end_date %} - - {{ frappe.utils.format_date(class.end_date, "medium") }} - - {% endif %} -
- -
- {% endfor %} -
+ {{ ClassCards(classes) }} {% else %}
@@ -45,3 +24,43 @@
{% endblock %} + + +{% macro ClassCards(classes) %} +
+ {% for class in classes %} + {% set course_count = frappe.db.count("Class Course", {"parent": class.name}) %} + {% set student_count = frappe.db.count("Class Student", {"parent": class.name}) %} + +
+
+ {% if course_count %} + + {{ course_count }} {{ _("Courses") }} + + {% endif %} + + {% if student_count %} + + {{ student_count }} {{ _("Students") }} + + {% endif %} +
+ +
+ {{ class.title }} +
+ +
+ + {{ frappe.utils.format_date(class.start_date, "medium") }} - + + + {{ frappe.utils.format_date(class.end_date, "medium") }} + +
+ +
+ {% endfor %} +
+{% endmacro %} From cfcc1b31621b9a01808334c2d840bfca3ba95dd3 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 21 Nov 2022 12:27:52 +0530 Subject: [PATCH 08/10] fix: formatting --- lms/www/assignments/assignment.js | 16 ++++++---------- lms/www/batch/learn.js | 10 +++++----- lms/www/classes/class.html | 2 +- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lms/www/assignments/assignment.js b/lms/www/assignments/assignment.js index 7995e672..aba82d71 100644 --- a/lms/www/assignments/assignment.js +++ b/lms/www/assignments/assignment.js @@ -1,5 +1,4 @@ frappe.ready(() => { - this.result; let self = this; @@ -14,10 +13,8 @@ frappe.ready(() => { self.result = $(this).val(); }); }); - }); - const set_result = () => { let self = this; let result = $("#result").data("type"); @@ -31,20 +28,19 @@ const set_result = () => { } }; - const save_assignment = (e) => { frappe.call({ method: "lms.lms.doctype.lesson_assignment.lesson_assignment.grade_assignment", args: { - "name": $(e.currentTarget).data("assignment"), - "result": self.result, - "comments": $("#comments").val(), + name: $(e.currentTarget).data("assignment"), + result: self.result, + comments: $("#comments").val(), }, callback: (data) => { frappe.show_alert({ message: __("Saved"), indicator: "green", }); - } - }) -} + }, + }); +}; diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 9e0ee674..dc79ee5b 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -412,22 +412,22 @@ const fetch_assignments = () => { callback: (data) => { if (data.message) { const assignment = data.message; - const status = assignment.status + const status = assignment.status; let target = $(".attach-file"); target.addClass("hide"); target.siblings(".submit-work").addClass("hide"); target.siblings(".preview-work").removeClass("hide"); - if(status != "Not Graded") { - let color = status == "Pass" ? "green": "red"; + if (status != "Not Graded") { + let color = status == "Pass" ? "green" : "red"; $(".assignment-status") .removeClass("hide") .addClass(color) - .text(data.message.status) + .text(data.message.status); target.siblings(".alert").addClass("hide"); $(".clear-work").addClass("hide"); if (assignment.comments) { $(".comments").removeClass("hide"); - $(".comment").text(assignment.comments) + $(".comment").text(assignment.comments); } } target diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index d2e1ccd2..b763d742 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -111,7 +111,7 @@
{% for student in class_students %}
- + {{ student.student_name }} From 88f9114dd6f41bd6f121465303f9a6080ac13321 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 21 Nov 2022 12:33:26 +0530 Subject: [PATCH 09/10] ci: updated flake8 url --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33ad3b85..1eca3075 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -46,8 +46,8 @@ repos: lms/public/js/lib/.* )$ - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 + - repo: https://github.com/PyCQA/flake8 + rev: 5.0.4 hooks: - id: flake8 additional_dependencies: ['flake8-bugbear',] From b5078c1f1f70d20f2829790d845409ad56db7815 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 21 Nov 2022 13:36:37 +0530 Subject: [PATCH 10/10] fix: removed unused file --- lms/www/courses/index.js | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 lms/www/courses/index.js diff --git a/lms/www/courses/index.js b/lms/www/courses/index.js deleted file mode 100644 index d6b84fca..00000000 --- a/lms/www/courses/index.js +++ /dev/null @@ -1,9 +0,0 @@ -frappe.ready(() => {}); - -const change_hash = (e) => { - window.location.hash = $(e.currentTarget).attr("href"); -}; - -const open_tab = () => { - $(`a[href="${window.location.hash}"]`).click(); -};