diff --git a/community/lms/doctype/chapter/chapter.js b/community/lms/doctype/chapter/chapter.js index 9380a622..9b895f9e 100644 --- a/community/lms/doctype/chapter/chapter.js +++ b/community/lms/doctype/chapter/chapter.js @@ -2,7 +2,15 @@ // For license information, please see license.txt frappe.ui.form.on('Chapter', { - // refresh: function(frm) { - // } + onload: function (frm) { + frm.set_query("lesson", "lessons", function () { + return { + filters: { + "chapter": frm.doc.name, + } + }; + }); + } + }); diff --git a/community/lms/doctype/chapter/chapter.json b/community/lms/doctype/chapter/chapter.json index 8b60641a..ca5b3fa5 100644 --- a/community/lms/doctype/chapter/chapter.json +++ b/community/lms/doctype/chapter/chapter.json @@ -9,7 +9,7 @@ "course", "title", "description", - "index_" + "lessons" ], "fields": [ { @@ -31,10 +31,10 @@ "options": "LMS Course" }, { - "default": "1", - "fieldname": "index_", - "fieldtype": "Int", - "label": "Index" + "fieldname": "lessons", + "fieldtype": "Table", + "label": "Lessons", + "options": "Lessons" } ], "index_web_pages_for_search": 1, @@ -45,7 +45,7 @@ "link_fieldname": "chapter" } ], - "modified": "2021-07-23 19:03:57.946831", + "modified": "2021-07-27 16:28:08.667964", "modified_by": "Administrator", "module": "LMS", "name": "Chapter", diff --git a/community/lms/doctype/chapter/chapter.py b/community/lms/doctype/chapter/chapter.py index a563c7e0..8e0f3f82 100644 --- a/community/lms/doctype/chapter/chapter.py +++ b/community/lms/doctype/chapter/chapter.py @@ -5,15 +5,6 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document -from ...utils import slugify class Chapter(Document): - def get_lessons(self): - rows = frappe.db.get_all("Lesson", - filters={"chapter": self.name}, - fields='name', - order_by="index_") - return [frappe.get_doc('Lesson', row['name']) for row in rows] - - def get_slugified_chapter_title(self): - return slugify(self.title) + pass diff --git a/community/lms/doctype/chapters/__init__.py b/community/lms/doctype/chapters/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/lms/doctype/chapters/chapters.json b/community/lms/doctype/chapters/chapters.json new file mode 100644 index 00000000..7ca73ed2 --- /dev/null +++ b/community/lms/doctype/chapters/chapters.json @@ -0,0 +1,32 @@ +{ + "actions": [], + "creation": "2021-07-27 16:25:02.903245", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "chapter" + ], + "fields": [ + { + "fieldname": "chapter", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Chapter", + "options": "Chapter", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-07-27 16:25:02.903245", + "modified_by": "Administrator", + "module": "LMS", + "name": "Chapters", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/community/lms/doctype/chapters/chapters.py b/community/lms/doctype/chapters/chapters.py new file mode 100644 index 00000000..5d07b66e --- /dev/null +++ b/community/lms/doctype/chapters/chapters.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, FOSS United and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class Chapters(Document): + pass diff --git a/community/lms/doctype/lesson/lesson.json b/community/lms/doctype/lesson/lesson.json index d2671804..5971085d 100644 --- a/community/lms/doctype/lesson/lesson.json +++ b/community/lms/doctype/lesson/lesson.json @@ -10,7 +10,6 @@ "include_in_preview", "column_break_4", "title", - "index_", "index_label", "section_break_6", "body", @@ -31,13 +30,6 @@ "in_list_view": 1, "label": "Title" }, - { - "default": "1", - "fieldname": "index_", - "fieldtype": "Int", - "in_list_view": 1, - "label": "Index" - }, { "fieldname": "body", "fieldtype": "Markdown Editor", @@ -75,7 +67,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-06-29 13:34:49.077363", + "modified": "2021-07-27 16:28:29.203624", "modified_by": "Administrator", "module": "LMS", "name": "Lesson", diff --git a/community/lms/doctype/lessons/__init__.py b/community/lms/doctype/lessons/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/lms/doctype/lessons/lessons.json b/community/lms/doctype/lessons/lessons.json new file mode 100644 index 00000000..d4dfddd2 --- /dev/null +++ b/community/lms/doctype/lessons/lessons.json @@ -0,0 +1,31 @@ +{ + "actions": [], + "creation": "2021-07-27 16:25:48.269536", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "lesson" + ], + "fields": [ + { + "fieldname": "lesson", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Lesson", + "options": "Lesson" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-07-27 16:53:52.732191", + "modified_by": "Administrator", + "module": "LMS", + "name": "Lessons", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/community/lms/doctype/lessons/lessons.py b/community/lms/doctype/lessons/lessons.py new file mode 100644 index 00000000..63370d40 --- /dev/null +++ b/community/lms/doctype/lessons/lessons.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, FOSS United and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class Lessons(Document): + pass diff --git a/community/lms/doctype/lms_course/lms_course.js b/community/lms/doctype/lms_course/lms_course.js index 195b896a..3bcaaaab 100644 --- a/community/lms/doctype/lms_course/lms_course.js +++ b/community/lms/doctype/lms_course/lms_course.js @@ -2,7 +2,15 @@ // For license information, please see license.txt frappe.ui.form.on('LMS Course', { - // refresh: function(frm) { - // } + onload: function (frm) { + frm.set_query("chapter", "chapters", function () { + return { + filters: { + "course": frm.doc.name, + } + }; + }); + } + }); diff --git a/community/lms/doctype/lms_course/lms_course.json b/community/lms/doctype/lms_course/lms_course.json index d6358fbf..cf2521b2 100644 --- a/community/lms/doctype/lms_course/lms_course.json +++ b/community/lms/doctype/lms_course/lms_course.json @@ -1,11 +1,5 @@ { "actions": [ - { - "action": "community.lms.doctype.lms_course.lms_course.reindex_lessons", - "action_type": "Server Action", - "group": "Reindex", - "label": "Reindex Lessons" - }, { "action": "community.lms.doctype.lms_course.lms_course.reindex_exercises", "action_type": "Server Action", @@ -30,7 +24,8 @@ "disable_self_learning", "section_break_5", "short_introduction", - "description" + "description", + "chapters" ], "fields": [ { @@ -93,6 +88,12 @@ "fieldname": "upcoming", "fieldtype": "Check", "label": "Is an Upcoming Course" + }, + { + "fieldname": "chapters", + "fieldtype": "Table", + "label": "Chapters", + "options": "Chapters" } ], "index_web_pages_for_search": 1, @@ -112,14 +113,9 @@ "group": "Mentors", "link_doctype": "LMS Course Mentor Mapping", "link_fieldname": "course" - }, - { - "group": "Mentors", - "link_doctype": "LMS Mentor Request", - "link_fieldname": "course" } ], - "modified": "2021-07-23 19:01:29.765570", + "modified": "2021-07-28 19:01:50.677445", "modified_by": "Administrator", "module": "LMS", "name": "LMS Course", diff --git a/community/lms/doctype/lms_course/lms_course.py b/community/lms/doctype/lms_course/lms_course.py index 73b1d5e3..5ec7a17f 100644 --- a/community/lms/doctype/lms_course/lms_course.py +++ b/community/lms/doctype/lms_course/lms_course.py @@ -9,8 +9,10 @@ import json from ...utils import slugify from community.query import find, find_all from frappe.utils import flt, cint +from ...utils import slugify class LMSCourse(Document): + @staticmethod def find(name): """Returns the course with specified name. @@ -112,17 +114,42 @@ class LMSCourse(Document): def get_chapters(self): """Returns all chapters of this course. """ - # TODO: chapters should have a way to specify the order - return find_all("Chapter", course=self.name, order_by="index_") + chapters = [] + for row in self.chapters: + chapter_details = frappe.db.get_value("Chapter", row.chapter, + ["name", "title", "description"], + as_dict=True) + chapter_details.idx = row.idx + chapters.append(chapter_details) + return chapters - def get_lessons(self): - """ Returns all lessons of this course """ + def get_lessons(self, chapter=None): + """ If chapter is passed, returns lessons of only that chapter. + Else returns lessons of all chapters of the course """ lessons = [] - chapters = self.get_chapters() - for chapter in chapters: - lessons.append(frappe.get_all("Lesson", {"chapter": chapter.name})) + + if chapter: + return self.get_lesson_details(chapter) + + for chapter in self.get_chapters(): + lesson = self.get_lesson_details(chapter) + lessons += lesson + return lessons + def get_lesson_details(self, chapter): + lessons = [] + lesson_list = frappe.get_all("Lessons", {"parent": chapter.name}, + ["lesson", "idx"], order_by="idx") + for row in lesson_list: + lesson_details = frappe.get_doc("Lesson", row.lesson) + lesson_details.number = flt("{}.{}".format(chapter.idx, row.idx)) + lessons.append(lesson_details) + return lessons + + def get_slugified_chapter_title(self, chapter): + return slugify(chapter) + def get_course_progress(self): """ Returns the course progress of the session user """ lesson_count = len(self.get_lessons()) @@ -160,38 +187,12 @@ class LMSCourse(Document): visibility="Public") return batches - def get_chapter(self, index): - return find("Chapter", course=self.name, index_=index) - - def get_lesson(self, chapter_index, lesson_index): - chapter_name = frappe.get_value( - "Chapter", - {"course": self.name, "index_": chapter_index}, - "name") - lesson_name = chapter_name and frappe.get_value( - "Lesson", - {"chapter": chapter_name, "index_": lesson_index}, - "name") - return lesson_name and frappe.get_doc("Lesson", lesson_name) - def get_lesson_index(self, lesson_name): """Returns the {chapter_index}.{lesson_index} for the lesson. """ - lesson = frappe.get_doc("Lesson", lesson_name) - chapter = frappe.get_doc("Chapter", lesson.chapter) - return f"{chapter.index_}.{lesson.index_}" - - def reindex_lessons(self): - for i, c in enumerate(self.get_chapters(), start=1): - c.index_ = i - c.save() - self._reindex_lessons_in_chapter(c) - - def _reindex_lessons_in_chapter(self, c): - for i, lesson in enumerate(c.get_lessons(), start=1): - lesson.index = i - lesson.index_label = f"{c.index_}.{i}" - lesson.save() + lesson = frappe.db.get_value("Lessons", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True) + chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True) + return f"{chapter.idx}.{lesson.idx}" def reindex_exercises(self): for i, c in enumerate(self.get_chapters(), start=1): @@ -202,7 +203,7 @@ class LMSCourse(Document): def _reindex_exercises_in_chapter(self, c): i = 1 - for lesson in c.get_lessons(): + for lesson in self.get_lessons(c): for exercise in lesson.get_exercises(): exercise.index_ = i exercise.index_label = f"{c.index_}.{i}" @@ -302,9 +303,6 @@ class LMSCourse(Document): return None return sum(ratings)/len(ratings) - def get_outline(self): - return CourseOutline(self) - def get_progress(self, lesson): return frappe.db.get_value("LMS Course Progress", { @@ -314,55 +312,14 @@ class LMSCourse(Document): }, ["status"]) -class CourseOutline: - def __init__(self, course): - self.course = course - self.chapters = self.get_chapters() - self.lessons = self.get_lessons() - - def get_next(self, current): + def get_neighbours(self, current, lessons): current = flt(current) - numbers = sorted(lesson['number'] for lesson in self.lessons) - try: - index = numbers.index(current) - return numbers[index+1] - except IndexError: - return None - - def get_prev(self, current): - current = flt(current) - numbers = sorted(lesson['number'] for lesson in self.lessons) - try: - index = numbers.index(current) - if index == 0: - return None - return numbers[index-1] - except IndexError: - return None - - def get_chapters(self): - return frappe.db.get_all("Chapter", - filters={"course": self.course.name}, - fields=["name", "title", "index_"], - order_by="index_") - - def get_lessons(self): - chapters = [c['name'] for c in self.chapters] - lessons = frappe.db.get_all("Lesson", - filters={"chapter": ["IN", chapters]}, - fields=["name", "title", "chapter", "index_"]) - - chapter_numbers = {c['name']: c['index_'] for c in self.chapters} - for lesson in lessons: - lesson['number'] = flt("{}.{}".format(chapter_numbers[lesson['chapter']], lesson['index_'])) - return lessons - -@frappe.whitelist() -def reindex_lessons(doc): - course_data = json.loads(doc) - course = frappe.get_doc("LMS Course", course_data['name']) - course.reindex_lessons() - frappe.msgprint("All lessons in this course have been re-indexed.") + numbers = sorted(lesson.number for lesson in lessons) + index = numbers.index(current) + return { + "prev": numbers[index-1] if index-1 >= 0 else None, + "next": numbers[index+1] if index+1 < len(numbers) else None + } @frappe.whitelist() def reindex_exercises(doc): diff --git a/community/lms/widgets/BatchTabs.html b/community/lms/widgets/BatchTabs.html deleted file mode 100644 index 07c4c71a..00000000 --- a/community/lms/widgets/BatchTabs.html +++ /dev/null @@ -1,67 +0,0 @@ -