diff --git a/lms/lms/doctype/course_lesson/course_lesson.json b/lms/lms/doctype/course_lesson/course_lesson.json index d74a463d..ac1ef99c 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.json +++ b/lms/lms/doctype/course_lesson/course_lesson.json @@ -18,6 +18,10 @@ "youtube", "column_break_9", "quiz_id", + "section_break_16", + "question", + "column_break_15", + "file_type", "section_break_11", "body", "help_section", @@ -105,11 +109,33 @@ "fieldname": "youtube", "fieldtype": "Data", "label": "YouTube Video URL" + }, + { + "fieldname": "section_break_16", + "fieldtype": "Section Break", + "label": "Assignment" + }, + { + "description": "Assignment will appear at the bottom of the lesson.", + "fieldname": "question", + "fieldtype": "Small Text", + "label": "Question" + }, + { + "fieldname": "file_type", + "fieldtype": "Select", + "label": "File Type", + "mandatory_depends_on": "question", + "options": "Image\nDocument\nPDF" + }, + { + "fieldname": "column_break_15", + "fieldtype": "Column Break" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2022-09-02 11:30:15.450624", + "modified": "2022-10-28 12:36:01.978641", "modified_by": "Administrator", "module": "LMS", "name": "Course Lesson", @@ -147,4 +173,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index f5d03573..66bdde72 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -9,20 +9,24 @@ from frappe.model.document import Document from ...md import find_macros from lms.lms.utils import get_course_progress, get_lesson_url + class CourseLesson(Document): def validate(self): - self.check_and_create_folder() + #self.check_and_create_folder() self.validate_quiz_id() + def validate_quiz_id(self): if self.quiz_id and not frappe.db.exists("LMS Quiz", self.quiz_id): frappe.throw(_("Invalid Quiz ID")) + def on_update(self): dynamic_documents = ["Exercise", "Quiz"] for section in dynamic_documents: self.update_lesson_name_in_document(section) + def update_lesson_name_in_document(self, section): doctype_map= { "Exercise": "Exercise", @@ -39,6 +43,7 @@ class CourseLesson(Document): index += 1 self.update_orphan_documents(doctype_map[section], documents) + def update_orphan_documents(self, doctype, documents): """Updates the documents that were previously part of this lesson, but not any more. @@ -53,6 +58,7 @@ class CourseLesson(Document): ex.index_label = "" ex.save() + def check_and_create_folder(self): args = { "doctype": "File", @@ -63,6 +69,7 @@ class CourseLesson(Document): folder = frappe.get_doc(args) folder.save(ignore_permissions=True) + def get_exercises(self): if not self.body: return [] @@ -79,28 +86,26 @@ class CourseLesson(Document): return ("").join([ s for s in self.get_progress().lower().split() ]) return + @frappe.whitelist() def save_progress(lesson, course, status): - membership = frappe.db.exists("LMS Batch Membership", - { - "member": frappe.session.user, - "course": course - }) + membership = frappe.db.exists("LMS Batch Membership", { + "member": frappe.session.user, + "course": course + }) if not membership: return - if frappe.db.exists("LMS Course Progress", - { - "lesson": lesson, - "owner": frappe.session.user, - "course": course - }): - doc = frappe.get_doc("LMS Course Progress", - { - "lesson": lesson, - "owner": frappe.session.user, - "course": course - }) + if frappe.db.exists("LMS Course Progress", { + "lesson": lesson, + "owner": frappe.session.user, + "course": course + }): + doc = frappe.get_doc("LMS Course Progress", { + "lesson": lesson, + "owner": frappe.session.user, + "course": course + }) doc.status = status doc.save(ignore_permissions=True) else: @@ -114,6 +119,7 @@ def save_progress(lesson, course, status): frappe.db.set_value("LMS Batch Membership", membership, "progress", progress) return progress + @frappe.whitelist() def get_lesson_info(chapter): return frappe.db.get_value("Course Chapter", chapter, "course") diff --git a/lms/lms/doctype/lesson_assignment/lesson_assignment.json b/lms/lms/doctype/lesson_assignment/lesson_assignment.json index 4c0ba546..18e41b8a 100644 --- a/lms/lms/doctype/lesson_assignment/lesson_assignment.json +++ b/lms/lms/doctype/lesson_assignment/lesson_assignment.json @@ -6,11 +6,12 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "lesson", - "user", - "column_break_3", "assignment", - "id" + "lesson", + "course", + "column_break_3", + "member", + "member_name" ], "fields": [ { @@ -19,34 +20,51 @@ "in_list_view": 1, "in_standard_filter": 1, "label": "Lesson", - "options": "Course Lesson" - }, - { - "fieldname": "user", - "fieldtype": "Link", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "User", - "options": "User" + "options": "Course Lesson", + "reqd": 1 }, { "fieldname": "column_break_3", "fieldtype": "Column Break" }, - { - "fieldname": "id", - "fieldtype": "Data", - "label": "ID" - }, { "fieldname": "assignment", "fieldtype": "Attach", - "label": "Assignment" + "label": "Assignment", + "reqd": 1 + }, + { + "fieldname": "member", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Member", + "options": "User", + "reqd": 1 + }, + { + "fetch_from": "member.full_name", + "fieldname": "member_name", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Member Name", + "read_only": 1 + }, + { + "fetch_from": "lesson.course", + "fieldname": "course", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Course", + "read_only": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-12-22 11:17:08.390615", + "make_attachments_public": 1, + "modified": "2022-10-31 13:18:09.609729", "modified_by": "Administrator", "module": "LMS", "name": "Lesson Assignment", @@ -66,5 +84,7 @@ } ], "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [], + "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 eb2fd5e8..81d550b2 100644 --- a/lms/lms/doctype/lesson_assignment/lesson_assignment.py +++ b/lms/lms/doctype/lesson_assignment/lesson_assignment.py @@ -3,18 +3,26 @@ import frappe from frappe.model.document import Document -from frappe.handler import upload_file +from frappe import _ + class LessonAssignment(Document): - pass + def validate(self): + self.validate_duplicates() + + + def validate_duplicates(self): + if frappe.db.exists("Lesson Assignment", {"lesson": self.lesson, "member": self.member}): + lesson_title = frappe.db.get_value("Course Lesson", self.lesson, "title") + frappe.throw(_("Assignment for Lesson {0} by {1} already exists.").format(lesson_title, self.member_name)) + @frappe.whitelist() -def upload_assignment(assignment, lesson, identifier): +def upload_assignment(assignment, lesson): args = { "doctype": "Lesson Assignment", "lesson": lesson, - "user": frappe.session.user, - "id": identifier + "member": frappe.session.user } if frappe.db.exists(args): del args["doctype"] @@ -24,18 +32,16 @@ def upload_assignment(assignment, lesson, identifier): lesson_work = frappe.get_doc(args) lesson_work.save(ignore_permissions=True) + @frappe.whitelist() def get_assignment(lesson): - assignments = frappe.get_all("Lesson Assignment", - { + assignment = frappe.db.get_value("Lesson Assignment", { "lesson": lesson, - "user": frappe.session.user - }, - ["lesson", "user", "id", "assignment"]) - if len(assignments): - for assignment in assignments: - assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name") - return assignments + "member": frappe.session.user + }, ["lesson", "member", "assignment"], + as_dict=True) + assignment.file_name = frappe.db.get_value("File", {"file_url": assignment.assignment}, "file_name") + return assignment diff --git a/lms/lms/doctype/lms_course/lms_course.py b/lms/lms/doctype/lms_course/lms_course.py index 3b4e7e41..62ab9300 100644 --- a/lms/lms/doctype/lms_course/lms_course.py +++ b/lms/lms/doctype/lms_course/lms_course.py @@ -270,7 +270,7 @@ def save_chapter(course, title, chapter_description, idx, chapter): @frappe.whitelist() -def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_id=None): +def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_id=None, question=None, file_type=None): if lesson: doc = frappe.get_doc("Course Lesson", lesson) else: @@ -284,7 +284,9 @@ def save_lesson(title, body, chapter, preview, idx, lesson, youtube=None, quiz_i "body": body, "include_in_preview": preview, "youtube": youtube, - "quiz_id": quiz_id + "quiz_id": quiz_id, + "question": question, + "file_type": file_type }) doc.save(ignore_permissions=True) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 04939d1b..127ad33d 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -100,8 +100,10 @@ def get_lesson_details(chapter): order_by="idx") for row in lesson_list: - lesson_details = frappe.db.get_value("Course Lesson", row.lesson, - ["name", "title", "include_in_preview", "body", "creation", "youtube", "quiz_id"], as_dict=True) + lesson_details = frappe.db.get_value("Course Lesson", + row.lesson, + ["name", "title", "include_in_preview", "body", "creation", "youtube", "quiz_id", "question", "unique_id", "file_type"], + as_dict=True) lesson_details.number = flt("{}.{}".format(chapter.idx, row.idx)) lesson_details.icon = "icon-list" macros = find_macros(lesson_details.body) @@ -244,13 +246,22 @@ def get_progress(course, lesson): ["status"]) -def render_html(body, youtube, quiz_id): +def render_html(lesson): + youtube = lesson.youtube + quiz_id = lesson.quiz_id + body = lesson.body + if youtube and "/" in youtube: youtube = youtube.split("/")[-1] quiz_id = "{{ Quiz('" + quiz_id + "') }}" if quiz_id else "" youtube = "{{ YouTubeVideo('" + youtube + "') }}" if youtube else "" text = youtube + body + quiz_id + + if lesson.question: + assignment = "{{ Assignment('" + lesson.question + "-" + lesson.file_type + "') }}" + text = text + assignment + return markdown_to_html(text) diff --git a/lms/plugins.py b/lms/plugins.py index 354fe281..7d9972be 100644 --- a/lms/plugins.py +++ b/lms/plugins.py @@ -151,9 +151,10 @@ def assignment_renderer(detail): "Image": ".png, .jpg, .jpeg", "Video": "video/*" } + question = detail.split("-")[0] file_type = detail.split("-")[1] accept = supported_types[file_type] if file_type else "" - return frappe.render_template("templates/assignment.html", {"id": detail.split("-")[0], "accept": accept}) + return frappe.render_template("templates/assignment.html", {"question": question, "accept": accept}) def show_custom_signup(): if (frappe.db.get_single_value("LMS Settings", "terms_of_use") diff --git a/lms/public/css/style.css b/lms/public/css/style.css index de73ca1c..54203126 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1126,8 +1126,7 @@ pre { } .preview-work { - width: 50%; - justify-content: space-between; + width: 50%; } .job-card { @@ -1778,3 +1777,25 @@ li { .course-description-section { 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; +} + +input::file-selector-button:hover { + background-color: var(--gray-400); +} + +.btn { + font-weight: 400; +} + +select { + appearance: none; + -webkit-appearance: none; +} diff --git a/lms/templates/assignment.html b/lms/templates/assignment.html index 2bf14e41..c8577887 100644 --- a/lms/templates/assignment.html +++ b/lms/templates/assignment.html @@ -1,10 +1,12 @@
-
- -
{{ _("Submit Work") }}
-
- -
{{ _("Change") }}
+
+

{{ _("Assignment") }}

+
{{ _(question) }}
+ +
{{ _("Submit") }}
+
+ +
{{ _("Change") }}
+
-
diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index c3249a85..4987bbca 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -123,7 +123,7 @@ {% if lesson.edit_mode %} {{ EditLesson(lesson) }} {% else %} - {{ render_html(lesson.body, lesson.youtube, lesson.quiz_id) }} + {{ render_html(lesson) }} {% endif %} {% else %} @@ -171,11 +171,30 @@ {% macro EditLesson(lesson) %} -
{% if lesson.youtube %}{{ lesson.youtube }}{% endif %}
+
+
{% if lesson.youtube %}{{ lesson.youtube }}{% endif %}
+ +
{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}
+
+
-
{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}
+ +
+
{% if lesson.question %}{{ lesson.question }}{% endif %}
+ + +
+ + +