diff --git a/school/community/widgets/Avatar.html b/school/community/widgets/Avatar.html index 47cf60c9..f4b7194c 100644 --- a/school/community/widgets/Avatar.html +++ b/school/community/widgets/Avatar.html @@ -1,14 +1,14 @@ {% set color = get_palette(member.full_name) %} - - - {% if member.user_image %} - - - {% else %} - - {{ frappe.utils.get_abbr(member.full_name) }} - - {% endif %} + + + {% if member.user_image %} + + + {% else %} + + {{ frappe.utils.get_abbr(member.full_name) }} + {% endif %} + diff --git a/school/hooks.py b/school/hooks.py index 3af95593..7ad7ea2d 100644 --- a/school/hooks.py +++ b/school/hooks.py @@ -162,10 +162,26 @@ update_website_context = [ jinja = { "methods": [ "school.page_renderers.get_profile_url", + "school.overrides.user.get_authored_courses", "school.overrides.user.get_palette", "school.www.utils.get_membership", "school.www.utils.get_lessons", - "school.www.utils.get_tags" + "school.www.utils.get_tags", + "school.www.utils.get_instructors", + "school.www.utils.get_students", + "school.www.utils.get_average_rating", + "school.www.utils.is_certified", + "school.www.utils.get_lesson_index", + "school.www.utils.get_lesson_url", + "school.www.utils.get_chapters", + "school.www.utils.get_slugified_chapter_title", + "school.www.utils.get_progress", + "school.www.utils.render_html", + "school.www.utils.is_mentor", + "school.www.utils.is_cohort_staff", + "school.www.utils.get_mentors", + "school.www.utils.get_reviews", + "school.www.utils.is_eligible_to_review", ], "filters": [] } diff --git a/school/lms/doctype/course_lesson/course_lesson.py b/school/lms/doctype/course_lesson/course_lesson.py index 0be2e853..f03910f1 100644 --- a/school/lms/doctype/course_lesson/course_lesson.py +++ b/school/lms/doctype/course_lesson/course_lesson.py @@ -5,7 +5,8 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document -from ...md import markdown_to_html, find_macros +from ...md import find_macros +from school.www.utils import get_course_progress class CourseLesson(Document): def validate(self): @@ -57,9 +58,6 @@ class CourseLesson(Document): folder = frappe.get_doc(args) folder.save(ignore_permissions=True) - def render_html(self): - return markdown_to_html(self.body) - def get_exercises(self): if not self.body: return [] @@ -107,7 +105,6 @@ def save_progress(lesson, course, status): "status": status, }).save(ignore_permissions=True) - course_details = frappe.get_doc("LMS Course", course) - progress = course_details.get_course_progress() + progress = get_course_progress(course) frappe.db.set_value("LMS Batch Membership", membership, "progress", progress) return progress diff --git a/school/lms/doctype/lms_course/lms_course.py b/school/lms/doctype/lms_course/lms_course.py index 6ac61fe4..820c72bb 100644 --- a/school/lms/doctype/lms_course/lms_course.py +++ b/school/lms/doctype/lms_course/lms_course.py @@ -8,7 +8,7 @@ import json from ...utils import slugify from school.query import find, find_all from frappe.utils import flt, cint -from ...utils import slugify +from school.www.utils import get_chapters class LMSCourse(Document): @@ -98,31 +98,7 @@ class LMSCourse(Document): }) doc.insert() - def get_mentors(self): - """Returns the list of all mentors for this course. - """ - course_mentors = [] - mentors = frappe.get_all("LMS Course Mentor Mapping", {"course": self.name}, ["mentor"]) - for mentor in mentors: - member = frappe.get_doc("User", mentor.mentor) - member.batch_count = frappe.db.count("LMS Batch Membership", - { - "member": member.name, - "member_type": "Mentor" - }) - course_mentors.append(member) - return course_mentors - def is_mentor(self, email): - """Checks if given user is a mentor for this course. - """ - if not email: - return False - return frappe.db.count("LMS Course Mentor Mapping", - { - "course": self.name, - "mentor": email - }) def get_student_batch(self, email): """Returns the batch the given student is part of. @@ -142,12 +118,6 @@ class LMSCourse(Document): fieldname="batch") return batch_name and frappe.get_doc("LMS Batch", batch_name) - def get_slugified_chapter_title(self, chapter): - return slugify(chapter) - - def get_batch(self, batch_name): - return find("LMS Batch", name=batch_name, course=self.name) - def get_batches(self, mentor=None): batches = find_all("LMS Batch", course=self.name) if mentor: @@ -166,36 +136,8 @@ class LMSCourse(Document): name = frappe.get_value("Cohort", {"course": self.name, "slug": cohort_slug}) return name and frappe.get_doc("Cohort", name) - def is_cohort_staff(self, user_email): - """Returns True if the user is either a mentor or a staff for one or more active cohorts of this course. - """ - q1 = { - "doctype": "Cohort Staff", - "course": self.name, - "email": user_email - } - q2 = { - "doctype": "Cohort Mentor", - "course": self.name, - "email": user_email - } - return frappe.db.exists(q1) or frappe.db.exists(q2) - - def get_lesson_index(self, lesson_name): - """Returns the {chapter_index}.{lesson_index} for the lesson. - """ - lesson = frappe.db.get_value("Lesson Reference", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True) - if not lesson: - return None - - chapter = frappe.db.get_value("Chapter Reference", {"chapter": lesson.parent}, ["idx"], as_dict=True) - if not chapter: - return None - - return f"{chapter.idx}.{lesson.idx}" - def reindex_exercises(self): - for i, c in enumerate(self.get_chapters(), start=1): + for i, c in enumerate(get_chapters(self.name), start=1): self._reindex_exercises_in_chapter(c, i) def _reindex_exercises_in_chapter(self, c, index): @@ -207,117 +149,12 @@ class LMSCourse(Document): exercise.save() i += 1 - def get_learn_url(self, lesson_number): - if not lesson_number: - return - return f"/courses/{self.name}/learn/{lesson_number}" - - - def get_all_memberships(self, member): all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": self.name}, ["batch"]) for membership in all_memberships: membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title") return all_memberships - def get_students(self, batch=None): - """Returns (email, full_name, username) of all the students of this batch as a list of dict. - """ - filters = { - "course": self.name, - "member_type": "Student" - } - if batch: - filters["batch"] = batch - memberships = frappe.get_all( - "LMS Batch Membership", - filters, - ["member"]) - member_names = [m['member'] for m in memberships] - return find_all("User", name=["IN", member_names]) - - - - def get_reviews(self): - reviews = frappe.get_all("LMS Course Review", - { - "course": self.name - }, - ["review", "rating", "owner"], - order_by= "creation desc") - out_of_ratings = frappe.db.get_all("DocField", - { - "parent": "LMS Course Review", - "fieldtype": "Rating" - }, - ["options"]) - out_of_ratings = (len(out_of_ratings) and out_of_ratings[0].options) or 5 - for review in reviews: - review.rating = review.rating * out_of_ratings - review.owner_details = frappe.get_doc("User", review.owner) - - return reviews - - def is_eligible_to_review(self, membership): - """ Checks if user is eligible to review the course """ - if not membership: - return False - if frappe.db.count("LMS Course Review", - { - "course": self.name, - "owner": frappe.session.user - }): - return False - return True - - def get_average_rating(self): - ratings = [review.rating for review in self.get_reviews()] - if not len(ratings): - return None - return sum(ratings)/len(ratings) - - def get_progress(self, lesson): - return frappe.db.get_value("LMS Course Progress", - { - "course": self.name, - "owner": frappe.session.user, - "lesson": lesson - }, - ["status"]) - - def get_course_progress(self, member=None): - """ Returns the course progress of the session user """ - lesson_count = len(self.get_lessons()) - if not lesson_count: - return 0 - completed_lessons = frappe.db.count("LMS Course Progress", - { - "course": self.name, - "owner": member or frappe.session.user, - "status": "Complete" - }) - precision = cint(frappe.db.get_default("float_precision")) or 3 - return flt(((completed_lessons/lesson_count) * 100), precision) - - def get_neighbours(self, current, lessons): - current = flt(current) - 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 - } - - def is_certified(self): - certificate = frappe.get_all("LMS Certification", - { - "student": frappe.session.user, - "course": self.name - }) - if len(certificate): - return certificate[0].name - return - @frappe.whitelist() def reindex_exercises(doc): course_data = json.loads(doc) diff --git a/school/lms/md.py b/school/lms/md.py index b072af2a..5acb6322 100644 --- a/school/lms/md.py +++ b/school/lms/md.py @@ -105,7 +105,7 @@ def sanitize_html(html, macro): any broken tags. This makes sures that all those things are fixed before passing to the etree parser. """ - soup = BeautifulSoup(html, features="html5lib") + soup = BeautifulSoup(html, features="lxml") nodes = soup.body.children classname = "" if macro == "YouTubeVideo": diff --git a/school/lms/web_template/course_cards/course_cards.html b/school/lms/web_template/course_cards/course_cards.html index e65a8efb..cbf9563a 100644 --- a/school/lms/web_template/course_cards/course_cards.html +++ b/school/lms/web_template/course_cards/course_cards.html @@ -2,7 +2,8 @@

{{ title }}

{% for course_row in courses %} - {% set course = frappe.get_doc("LMS Course", course_row.course) %} + {% set course = frappe.db.get_value("LMS Course", course_row.course, + ["name", "upcoming", "title", "image", "enable_certification"], as_dict=True) %} {{ widgets.CourseCard(course=course, read_only=False) }} {% endfor %}
diff --git a/school/lms/widgets/ChapterTeaser.html b/school/lms/widgets/ChapterTeaser.html index 6bdcc5e3..7376acfd 100644 --- a/school/lms/widgets/ChapterTeaser.html +++ b/school/lms/widgets/ChapterTeaser.html @@ -1,12 +1,12 @@
- -