diff --git a/lms/lms/doctype/lms_assignment/lms_assignment.json b/lms/lms/doctype/lms_assignment/lms_assignment.json
index 0dde9649..6cb778a1 100644
--- a/lms/lms/doctype/lms_assignment/lms_assignment.json
+++ b/lms/lms/doctype/lms_assignment/lms_assignment.json
@@ -46,7 +46,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2023-06-23 12:34:21.314971",
+ "modified": "2023-06-26 18:09:29.809564",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Assignment",
@@ -78,6 +78,7 @@
"write": 1
}
],
+ "show_title_field_in_link": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py
index 5c7a3cae..9001066f 100644
--- a/lms/lms/doctype/lms_class/lms_class.py
+++ b/lms/lms/doctype/lms_class/lms_class.py
@@ -15,7 +15,9 @@ class LMSClass(Document):
def validate(self):
if self.seat_count:
self.validate_seats_left()
+ self.validate_duplicate_courses()
self.validate_duplicate_students()
+ self.validate_duplicate_assessments()
self.validate_membership()
def validate_duplicate_students(self):
@@ -28,6 +30,28 @@ class LMSClass(Document):
)
)
+ def validate_duplicate_courses(self):
+ courses = [row.course for row in self.courses]
+ duplicates = {course for course in courses if courses.count(course) > 1}
+ if len(duplicates):
+ title = frappe.db.get_value("LMS Course", next(iter(duplicates)), "title")
+ frappe.throw(
+ _("Course {0} has already been added to this class.").format(frappe.bold(title))
+ )
+
+ def validate_duplicate_assessments(self):
+ assessments = [row.assessment_name for row in self.assessment]
+ duplicates = {
+ assessment for assessment in assessments if assessments.count(assessment) > 1
+ }
+ if len(duplicates):
+ title = frappe.db.get_value("LMS Assessment", next(iter(duplicates)), "title")
+ frappe.throw(
+ _("Assessment {0} has already been added to this class.").format(
+ frappe.bold(next(iter(duplicates)))
+ )
+ )
+
def validate_membership(self):
for course in self.courses:
for student in self.students:
@@ -44,51 +68,30 @@ class LMSClass(Document):
frappe.throw(_("There are no seats available in this class."))
-@frappe.whitelist()
-def add_student(email, class_name):
- if not frappe.db.exists("User", email):
- frappe.throw(_("There is no such user. Please create a user with this Email ID."))
-
- filters = {
- "student": email,
- "parent": class_name,
- "parenttype": "LMS Class",
- "parentfield": "students",
- }
- if frappe.db.exists("Class Student", filters):
- frappe.throw(
- _("Student {0} has already been added to this class.").format(frappe.bold(email))
- )
-
- frappe.get_doc(
- {
- "doctype": "Class Student",
- "student": email,
- "student_name": frappe.db.get_value("User", email, "full_name"),
- "parent": class_name,
- "parenttype": "LMS Class",
- "parentfield": "students",
- }
- ).save()
- return True
-
-
@frappe.whitelist()
def remove_student(student, class_name):
+ frappe.only_for("Moderator")
frappe.db.delete("Class Student", {"student": student, "parent": class_name})
@frappe.whitelist()
def remove_course(course, parent):
+ frappe.only_for("Moderator")
frappe.db.delete("Class Course", {"course": course, "parent": parent})
+@frappe.whitelist()
+def remove_assessment(assessment, parent):
+ frappe.only_for("Moderator")
+ frappe.db.delete("LMS Assessment", {"assessment_name": assessment, "parent": parent})
+
+
@frappe.whitelist()
def create_live_class(
class_name, title, duration, date, time, timezone, auto_recording, description=None
):
date = format_date(date, "yyyy-mm-dd", True)
-
+ frappe.only_for("Moderator")
payload = {
"topic": title,
"start_time": format_datetime(f"{date} {time}", "yyyy-MM-ddTHH:mm:ssZ"),
@@ -165,6 +168,7 @@ def create_class(
category=None,
name=None,
):
+ frappe.only_for("Moderator")
if name:
class_details = frappe.get_doc("LMS Class", name)
else:
@@ -185,26 +189,3 @@ def create_class(
)
class_details.save()
return class_details
-
-
-@frappe.whitelist()
-def update_assessment(type, name, value, class_name):
- if not has_course_moderator_role():
- return
-
- value = cint(value)
- filters = {
- "assessment_type": type,
- "assessment_name": name,
- "parent": class_name,
- "parenttype": "LMS Class",
- "parentfield": "assessment",
- }
- exists = frappe.db.exists("LMS Assessment", filters)
-
- if exists and not value:
- frappe.db.delete("LMS Assessment", exists)
- elif not exists and value:
- doc = frappe.new_doc("LMS Assessment")
- doc.update(filters)
- doc.insert()
diff --git a/lms/patches.txt b/lms/patches.txt
index eb99f28e..22e92dab 100644
--- a/lms/patches.txt
+++ b/lms/patches.txt
@@ -53,4 +53,6 @@ lms.patches.v0_0.share_certificates
execute:frappe.delete_doc("Web Form", "class", ignore_missing=True, force=True)
lms.patches.v0_0.amend_course_and_lesson_editor_fields
lms.patches.v0_0.convert_course_description_to_html #11-05-2023
-lms.patches.v1_0.rename_assignment_doctype
\ No newline at end of file
+lms.patches.v1_0.rename_assignment_doctype
+execute:frappe.permissions.reset_perms("LMS Assignment")
+execute:frappe.permissions.reset_perms("LMS Quiz")
diff --git a/lms/public/css/style.css b/lms/public/css/style.css
index d8afb208..7c6510be 100644
--- a/lms/public/css/style.css
+++ b/lms/public/css/style.css
@@ -2195,4 +2195,13 @@ select {
display: grid;
grid-template-columns: repeat(auto-fill, 150px);
grid-gap: 1rem;
+}
+
+.btn-remove-course {
+ opacity: 0;
+ margin-top: 0.25rem;
+}
+
+.btn-remove-course:hover {
+ opacity: 1;
}
\ No newline at end of file
diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html
index 2b415517..3193e05a 100644
--- a/lms/www/classes/class.html
+++ b/lms/www/classes/class.html
@@ -180,7 +180,15 @@
{% if class_courses | length %}
{% for course in class_courses %}
- {{ widgets.CourseCard(course=course, read_only=False) }}
+
+ {{ widgets.CourseCard(course=course, read_only=False) }}
+
+
+
+
+
+
+
{% endfor %}
{% else %}
@@ -230,7 +238,7 @@
{% if is_moderator %}
-
+
@@ -255,7 +263,7 @@
{{ student.assessments_graded }}
- {{ frappe.utils.format_datetime(student.last_active, "medium") }}
+ {{ frappe.utils.pretty_date(student.last_active) }}
{% if is_moderator %}
@@ -265,17 +273,7 @@
{% endif %}
-
-
-
-
-
{% endfor %}
{% else %}
@@ -297,107 +295,10 @@
{% endif %}
-
{{ AssessmentList(assessments) }}
{% endmacro %}
-
-{% macro ManageAssessments() %}
-{% if is_moderator %}
-
-
-
-
-
-
-
-
- {{ _("Create New") }}
-
-
- {{ _("To create a new assignment or quiz for this class, click on the buttons below. Once you have created the new assignment or quiz you can come back and add it from here.") }}
-
-
-
-
-
-
-
-
-
-
-
-
-{% endif %}
-{% endmacro %}
-
{% macro AssessmentList(assessments) %}
{% if assessments | length %}
@@ -425,6 +331,11 @@
{{ assessment.assessment_type.split("LMS ")[1] }}
+
+
+
+
+
{% endfor %}
diff --git a/lms/www/classes/class.js b/lms/www/classes/class.js
index 5f361a81..d51442da 100644
--- a/lms/www/classes/class.js
+++ b/lms/www/classes/class.js
@@ -30,14 +30,13 @@ frappe.ready(() => {
remove_course(e);
});
+ $(".btn-remove-assessment").click((e) => {
+ remove_assessment(e);
+ });
+
$("#open-assessment-modal").click((e) => {
e.preventDefault();
show_assessment_modal();
- /* $("#assessment-modal").modal("show"); */
- });
-
- $(".assessment-item").click((e) => {
- update_assessment(e);
});
$(".btn-close").click((e) => {
@@ -45,54 +44,6 @@ frappe.ready(() => {
});
});
-const submit_student = (e) => {
- e.preventDefault();
- if ($('input[data-fieldname="student_input"]').val()) {
- frappe.call({
- method: "lms.lms.doctype.lms_class.lms_class.add_student",
- args: {
- email: $('input[data-fieldname="student_input"]').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 create_live_class = (e) => {
let class_name = $(".class-details").data("class");
frappe.call({
@@ -353,34 +304,38 @@ const show_course_modal = () => {
],
primary_action_label: __("Add"),
primary_action(values) {
- frappe.call({
- method: "frappe.client.insert",
- args: {
- doc: {
- doctype: "Class Course",
- course: values.course,
- parenttype: "LMS Class",
- parentfield: "courses",
- parent: $(".class-details").data("class"),
- },
- },
- callback(r) {
- frappe.show_alert(
- {
- message: __("Course Added"),
- indicator: "green",
- },
- 3
- );
- window.location.reload();
- },
- });
+ add_course(values);
course_modal.hide();
},
});
course_modal.show();
};
+const add_course = (values) => {
+ frappe.call({
+ method: "frappe.client.insert",
+ args: {
+ doc: {
+ doctype: "Class Course",
+ course: values.course,
+ parenttype: "LMS Class",
+ parentfield: "courses",
+ parent: $(".class-details").data("class"),
+ },
+ },
+ callback(r) {
+ frappe.show_alert(
+ {
+ message: __("Course Added"),
+ indicator: "green",
+ },
+ 2000
+ );
+ window.location.reload();
+ },
+ });
+};
+
const remove_course = (e) => {
frappe.confirm("Are you sure you want to remove this course?", () => {
frappe.call({
@@ -395,7 +350,7 @@ const remove_course = (e) => {
message: __("Course Removed"),
indicator: "green",
},
- 3
+ 2000
);
window.location.reload();
},
@@ -420,34 +375,63 @@ const show_student_modal = () => {
],
primary_action_label: __("Add"),
primary_action(values) {
- frappe.call({
- method: "frappe.client.insert",
- args: {
- doc: {
- doctype: "Class Student",
- student: values.student,
- parenttype: "LMS Class",
- parentfield: "students",
- parent: $(".class-details").data("class"),
- },
- },
- callback(r) {
- frappe.show_alert(
- {
- message: __("Student Added"),
- indicator: "green",
- },
- 3
- );
- window.location.reload();
- },
- });
+ add_student(values);
student_modal.hide();
},
});
student_modal.show();
};
+const add_student = (values) => {
+ frappe.call({
+ method: "frappe.client.insert",
+ args: {
+ doc: {
+ doctype: "Class Student",
+ student: values.student,
+ parenttype: "LMS Class",
+ parentfield: "students",
+ parent: $(".class-details").data("class"),
+ },
+ },
+ callback(r) {
+ frappe.show_alert(
+ {
+ message: __("Student Added"),
+ indicator: "green",
+ },
+ 2000
+ );
+ 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",
+ },
+ 2000
+ );
+ window.location.reload();
+ },
+ });
+ }
+ );
+};
+
const show_assessment_modal = (e) => {
let assessment_modal = new frappe.ui.Dialog({
title: "Manage Assessments",
@@ -476,31 +460,57 @@ const show_assessment_modal = (e) => {
],
primary_action_label: __("Add"),
primary_action(values) {
- frappe.call({
- method: "frappe.client.insert",
- args: {
- doc: {
- doctype: "LMS Assessment",
- assessment_type: values.assessment_type,
- assessment_name: values.assessment_name,
- parenttype: "LMS Class",
- parentfield: "assessments",
- parent: $(".class-details").data("class"),
- },
- },
- callback(r) {
- frappe.show_alert(
- {
- message: __("Assessment Added"),
- indicator: "green",
- },
- 3
- );
- window.location.reload();
- },
- });
+ add_addessment(values);
assessment_modal.hide();
},
});
assessment_modal.show();
};
+
+const add_addessment = (values) => {
+ frappe.call({
+ method: "frappe.client.insert",
+ args: {
+ doc: {
+ doctype: "LMS Assessment",
+ assessment_type: values.assessment_type,
+ assessment_name: values.assessment_name,
+ parenttype: "LMS Class",
+ parentfield: "assessment",
+ parent: $(".class-details").data("class"),
+ },
+ },
+ callback(r) {
+ frappe.show_alert(
+ {
+ message: __("Assessment Added"),
+ indicator: "green",
+ },
+ 2000
+ );
+ window.location.reload();
+ },
+ });
+};
+
+const remove_assessment = (e) => {
+ frappe.confirm("Are you sure you want to remove this assessment?", () => {
+ frappe.call({
+ method: "lms.lms.doctype.lms_class.lms_class.remove_assessment",
+ args: {
+ assessment: $(e.currentTarget).data("assessment"),
+ parent: $(".class-details").data("class"),
+ },
+ callback(r) {
+ frappe.show_alert(
+ {
+ message: __("Assessment Removed"),
+ indicator: "green",
+ },
+ 2000
+ );
+ window.location.reload();
+ },
+ });
+ });
+};
diff --git a/lms/www/classes/class.py b/lms/www/classes/class.py
index 99f0f572..59932854 100644
--- a/lms/www/classes/class.py
+++ b/lms/www/classes/class.py
@@ -48,7 +48,7 @@ def get_context(context):
class_students = frappe.get_all(
"Class Student",
{"parent": class_name},
- ["student", "student_name", "username"],
+ ["name", "student", "student_name", "username"],
order_by="creation desc",
)
diff --git a/lms/www/quiz_submission/__init__.py b/lms/www/quiz_submission/__init__.py
new file mode 100644
index 00000000..e69de29b