From 7a7bc3e0db3e77690809b37650e97b41059180ed Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 29 Aug 2022 09:21:45 +0530 Subject: [PATCH 01/41] fix: removed desk access from course instructor role --- lms/patches.txt | 2 +- lms/patches/v0_0/create_course_instructor_role.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lms/patches.txt b/lms/patches.txt index 6fe8bbf7..f8a1d28a 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -30,4 +30,4 @@ lms.patches.v0_0.move_certification_to_certificate lms.patches.v0_0.quiz_submission_member lms.patches.v0_0.delete_old_module_docs #08-07-2022 lms.patches.v0_0.delete_course_web_forms #21-08-2022 -lms.patches.v0_0.create_course_instructor_role +lms.patches.v0_0.create_course_instructor_role #29-08-2022 diff --git a/lms/patches/v0_0/create_course_instructor_role.py b/lms/patches/v0_0/create_course_instructor_role.py index 25f5bd91..3653fbdd 100644 --- a/lms/patches/v0_0/create_course_instructor_role.py +++ b/lms/patches/v0_0/create_course_instructor_role.py @@ -6,5 +6,6 @@ def execute(): "doctype": "Role", "role_name": "Course Instructor", "home_page": "/dashboard", + "desk_access": 0 }) role.save(ignore_permissions=True) From b3a9274cd3e5533c17725fe8ec026848fe2e5b6e Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 30 Aug 2022 12:50:26 +0530 Subject: [PATCH 02/41] fix: minor UI --- .../courses_enrolled/courses_enrolled.html | 4 +- lms/public/js/common_functions.js | 2 +- lms/www/batch/join.html | 40 +++++++++---------- lms/www/batch/learn.html | 35 +++++++++------- lms/www/dashboard/index.html | 5 ++- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/lms/lms/web_template/courses_enrolled/courses_enrolled.html b/lms/lms/web_template/courses_enrolled/courses_enrolled.html index f254a3ef..b165aa70 100644 --- a/lms/lms/web_template/courses_enrolled/courses_enrolled.html +++ b/lms/lms/web_template/courses_enrolled/courses_enrolled.html @@ -1,14 +1,16 @@ {% set enrolled = get_enrolled_courses().in_progress + get_enrolled_courses().completed %} + {% if enrolled | length %}
{% for course in enrolled %} {{ widgets.CourseCard(course=course) }} {% endfor %}
+ {% else %} {% set site_name = frappe.db.get_single_value("System Settings", "app_name") %}
-
+
{{ _("You haven't enrolled for any courses") }}
{{ _("Here are a few courses we recommend for you to get started with {0}").format(site_name) }}
diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index d09baca3..17ace20d 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -67,7 +67,7 @@ const join_course = (e) => { }, 3); setTimeout(function () { window.location.href = `/courses/${course}/learn/1.1`; - }, 3000); + }, 1000); } } }) diff --git a/lms/www/batch/join.html b/lms/www/batch/join.html index ce46d291..824cf13d 100644 --- a/lms/www/batch/join.html +++ b/lms/www/batch/join.html @@ -48,25 +48,25 @@ {% endblock %} diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index b364ca79..c3fb460a 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -67,7 +67,7 @@ data-index="{{ lesson_index }}" data-course="{{ course.name }}" data-chapter="{{ chapter }}" {% if lesson.name %} data-lesson="{{ lesson.name }}" {% endif %} >{% if lesson.title %}{{ lesson.title }}{% endif %}
- {{ _("COMPLETED") }} + {{ _("COMPLETED") }} {% if is_instructor and not lesson.edit_mode %} @@ -119,9 +119,13 @@ {% endif %} {% else %} + {% set course_link = "" + _('here') + "" %}
-
{{ _("Start Learning") }}
-
{{ _("This lesson is not available for preview. Please join the course to access it.") }}
+
+ {{ _("This lesson is not available for preview. + Please join the course to access it. + Click {0} to join the course.").format(course_link) }} +
{% endif %}
@@ -140,14 +144,14 @@
{% if prev_url %} {% endif %}
- {% if not is_mentor(course.name, frappe.session.user) and membership %} {% set progress = get_progress(course.name, lesson.name) %} + + {% if not is_mentor(course.name, frappe.session.user) and membership %}
- -
- {{ _("Mark as Incomplete") }} -
{% endif %}
-
diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index 1f6e5855..a24a2977 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -1,5 +1,6 @@ {% extends "templates/base.html" %} -{% block title %}{{ _("Dashboard")}} +{% block title %} +{{ _("Dashboard")}} {% endblock %} @@ -20,6 +21,7 @@ + {% if show_creators_section %} + + +
{% endmacro %} {% macro Discussions() %} -{% set topics_count = frappe.db.count("Discussion Topic", { - "reference_doctype": "Course Lesson", - "reference_docname": lesson.name -}) %} -{% set is_instructor = frappe.session.user == course.instructor %} -{% set condition = is_instructor if is_instructor else membership %} -{% set doctype, docname = _("Course Lesson"), lesson.name %} -{% set title = "Questions" if topics_count else "" %} -{% set cta_title = "Ask a Question" %} -{% set button_name = _("Start Learning") %} -{% set redirect_to = "/courses/" + course.name %} -{% set empty_state_title = _("Have a doubt?") %} -{% set empty_state_subtitle = _("Post it here, our mentors will help you out.") %} -{% include "frappe/templates/discussions/discussions_section.html" %} + {% set topics_count = frappe.db.count("Discussion Topic", { + "reference_doctype": "Course Lesson", + "reference_docname": lesson.name + }) %} + {% set is_instructor = frappe.session.user == course.instructor %} + {% set condition = is_instructor if is_instructor else membership %} + {% set doctype, docname = _("Course Lesson"), lesson.name %} + {% set title = "Questions" if topics_count else "" %} + {% set cta_title = "Ask a Question" %} + {% set button_name = _("Start Learning") %} + {% set redirect_to = "/courses/" + course.name %} + {% set empty_state_title = _("Have a doubt?") %} + {% set empty_state_subtitle = _("Post it here, our mentors will help you out.") %} + {% include "frappe/templates/discussions/discussions_section.html" %} {% endmacro %} {%- block script %} -{{ super() }} - -{{ include_script('controls.bundle.js') }} -{% for ext in page_extensions %} -{{ ext.render_footer() }} -{% endfor %} + {{ super() }} + + {{ include_script('controls.bundle.js') }} + {% for ext in page_extensions %} + {{ ext.render_footer() }} + {% endfor %} {%- endblock %} diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 0fe52cd6..197ca8a7 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -490,7 +490,9 @@ const save_lesson = (e) => { method: "lms.lms.doctype.lms_course.lms_course.save_lesson", args: { "title": $("#title").text(), - "body": this.code_field_group.fields_dict["code_md"].last_value, + "body": this.code_field_group.fields_dict["code_md"].value, + "youtube": $("#youtube").text(), + "quiz_id": $("#quiz-id").text(), "chapter": $("#title").data("chapter"), "preview": $("#preview").prop("checked") ? 1 : 0, "idx": $("#title").data("index"), From c37cdbdc5fc95c26ae955cd13c9bfa3c08f61924 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 2 Sep 2022 17:18:57 +0530 Subject: [PATCH 06/41] chore: added logs --- lms/lms/web_template/courses_enrolled/courses_enrolled.html | 2 +- lms/templates/courses_created.html | 2 +- lms/www/dashboard/index.html | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lms/lms/web_template/courses_enrolled/courses_enrolled.html b/lms/lms/web_template/courses_enrolled/courses_enrolled.html index b165aa70..236e8dec 100644 --- a/lms/lms/web_template/courses_enrolled/courses_enrolled.html +++ b/lms/lms/web_template/courses_enrolled/courses_enrolled.html @@ -1,5 +1,5 @@ {% set enrolled = get_enrolled_courses().in_progress + get_enrolled_courses().completed %} - +{{ enrolled }} {% if enrolled | length %}
{% for course in enrolled %} diff --git a/lms/templates/courses_created.html b/lms/templates/courses_created.html index a219ebe1..083317d1 100644 --- a/lms/templates/courses_created.html +++ b/lms/templates/courses_created.html @@ -1,5 +1,5 @@ {% set courses = get_authored_courses(frappe.session.user, only_published=False) %} - +{{ courses }} {% if courses | length %}
{% for course in courses %} diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index 083cb524..93f303a1 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -8,6 +8,8 @@ {% set portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") %} {% set show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() %} +{{ show_creators_section }} +{{ frappe.session.user }}
From eabbe3e3ed71cfd7758759102d1e16ad61f53c6d Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:50:29 +0530 Subject: [PATCH 07/41] fix: readme --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b46849e7..edb0f99e 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,68 @@

+ + GitHub last commit + + GitHub issues + + GitHub pull requests + + GitHub pull requests +

-
+ + Frappe LMS +

Frappe LMS

+ Easy to Use, Open Source Learning Management System +
+ Visit the website » +
+
+ Explore the docs. + Report Bug +

+
- + ## About The Project ![Frappe LMS](/lms/public/images/course-home.png) - -Frappe LMS is an easy to use, open source learning management system. It has a clear UI that helps students focus only on whats important and assists in a distraction-free learning. +Frappe LMS is an easy-to-use, open-source learning management system. It has a clear UI that helps students focus only on what's important and assists in distraction-free learning. You can create courses and lessons through simple forms in the backend that you can analyze with the help of reports. Course Instructors and students can reach out to each other through the discussions section available for each lesson and get queries resolved. @@ -48,21 +71,29 @@ Lessons can be in the form of text, videos, quizzes or a combination of all thes

(back to top)

+ ## Getting Started -Frappe LMS app is build using [Frappe Framework](https://frappeframework.com). +Frappe LMS app is built1 using [Frappe Framework](https://frappeframework.com). ### Direct installation through bench -To setup the repository locally follow the steps mentioned below: +To setup the repository locally, follow the steps mentioned below: + +1. Install bench and set up a frappe-bench directory by following the [Installation Steps](https://frappeframework.com/docs/user/en/installation). -1. Install bench and setup a frappe-bench directory by following the [Installation Steps](https://frappeframework.com/docs/user/en/installation). 2. Start the server by running ```bench start```. + 3. In a separate terminal window, create a new site by running ```bench new-site lms.test```. + 4. Fork the Frappe LMS app and clone it. -5. Run ```bench get-app lms``` to get the app on your bench . + +5. Run ```bench get-app lms``` to get the app on your bench. + 6. Run ```bench --site lms.test install-app lms```. + 7. Map your site to localhost with the command ```bench --site lms.test add-to-hosts```. + 8. Now open the URL [http://lms.test:8000/](http://lms.test:8000/) in your browser, you should see the app running.

(back to top)

@@ -72,6 +103,7 @@ To setup the repository locally follow the steps mentioned below: 1. Clone the repo. ``` + $ git clone https://github.com/frappe/lms.git $ cd lms @@ -81,55 +113,63 @@ $ cd lms 2. Run docker-compose ``` + $ docker-compose up ``` 3. Visit the website at [http://localhost:8000/](http://localhost:8000/) -You'll have to go through the setup wizard to setup the website for the first time you access it. Login using the following credentiasl to complete the setup wizard. +You'll have to go through the setup wizard to set up the website the first time you access it. Log in using the following credentials to complete the setup wizard. ``` + Username: Administrator + password: admin ``` ## [](https://github.com/frappe/lms/blob/main/docker-installation.md#stopping-the-server)Stopping the server -Press `ctrl+c` in the terminal to stop the server. You can also run `docker-compose down` in another terminal to stop it. +Press ctrl+c in the terminal to stop the server. You can also run docker-compose down in another terminal to stop it. To completely reset the instance, do the following: ``` + $ docker-compose down --volumes + $ docker-compose up + ``` - + ## Contributing -Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. +Contributions are what makes the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated. -Thank you for your interest in contributing to an open-source project! Our world works on people taking initiative to contribute to the "commons" and contributing to open source means you are contributing to make things better for not only yourself but everyone else too! So thank you for taking this initiative. +Thank you for your interest in contributing to an open-source project! Our world works on people taking initiative to contribute to the "commons" and contributing to open source means you are contributing to making things better for not only yourself but everyone else too! So thank you for taking this initiative. -Great projects also work because of great quality. Open source or not, the user really cares that things should work as they are advertised, and consistently. New features should follow the same pattern and so that users don't have to learn things again and again. +Great projects also work because of great quality. Open source or not, the user really cares that things should work as they are advertised, and consistently. New features should follow the same pattern so that users don't have to learn things again and again. Developers who maintain open source also expect that you follow certain guidelines. These guidelines ensure that developers are able to quickly give feedback on your contribution and how to make it better. Most probably you might have to go back and change a few things, but it will be in the interest of making this process better for everyone. So be prepared for some back and forth. + Don't forget to give the project a star! Thanks again! +1. Go to the apps/lms directory of your installation and execute git pull --unshallow to ensure that you have the full git repository. Also, fork the frappe/lms repository on GitHub. -1. Go to the apps/lms directory of your installation and execute git pull --unshallow to ensure that you have the full git repository. Also fork the frappe/lms repository on GitHub. 2. Check out a working branch in git (e.g. ```git checkout -b my-new-branch```). + 3. Run your local version (e.g. bench start in your bench installation). Make sure that your changes work the way you want them to. + 4. Commit your changes to your branch. Make sure to use a semantic commit message. + 6. Push your branch to your fork on Github, and create a pull request.

(back to top)

## License - - Distributed under [GNU AFFERO GENERAL PUBLIC LICENSE](license.txt) From 2d5b8430bdb836013f62618c1affe0e4bea02d14 Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:55:00 +0530 Subject: [PATCH 08/41] fix: images and links in readme --- README.md | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index edb0f99e..28655dd6 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,26 @@

- - - GitHub last commit - + GitHub last commit - - GitHub issues - + GitHub issues - - GitHub pull requests - + GitHub pull requests - - GitHub pull requests - + GitHub pull requests

- - Frappe LMS - -

Frappe LMS

-

- Easy to Use, Open Source Learning Management System - -
- +
Visit the website » - -
- -
- +
+
Explore the docs. - Report Bug

From e41c83a68cdc2c56690b5b41ab89cd514305c0da Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:58:52 +0530 Subject: [PATCH 09/41] fix: spelling in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28655dd6..60b632a6 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Lessons can be in the form of text, videos, quizzes or a combination of all thes ## Getting Started -Frappe LMS app is built1 using [Frappe Framework](https://frappeframework.com). +Frappe LMS app is built using [Frappe Framework](https://frappeframework.com). ### Direct installation through bench From 8088a464ad12fb7aa41ab2a78df9def2c5236888 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 09:16:57 +0530 Subject: [PATCH 10/41] fix: dashboard creators section issue --- lms/lms/doctype/lms_course/lms_course.py | 9 ++++----- lms/lms/utils.py | 2 +- lms/overrides/user.py | 18 ++++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lms/lms/doctype/lms_course/lms_course.py b/lms/lms/doctype/lms_course/lms_course.py index 1d8096a4..0f497eb3 100644 --- a/lms/lms/doctype/lms_course/lms_course.py +++ b/lms/lms/doctype/lms_course/lms_course.py @@ -34,11 +34,10 @@ class LMSCourse(Document): self.send_email_to_interested_users() def send_email_to_interested_users(self): - interested_users = frappe.get_all("LMS Course Interest", - { - "course": self.name - }, - ["name", "user"]) + interested_users = frappe.get_all("LMS Course Interest", { + "course": self.name + }, + ["name", "user"]) subject = self.title + " is available!" args = { "title": self.title, diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 30b201a0..5fd64ca3 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -239,7 +239,7 @@ def get_progress(course, lesson): def render_html(body, youtube, quiz_id): - if "/" in youtube: + if youtube and "/" in youtube: youtube = youtube.split("/")[-1] quiz_id = "{{ Quiz('" + quiz_id + "') }}" if quiz_id else "" diff --git a/lms/overrides/user.py b/lms/overrides/user.py index 324cf83c..00805c7a 100644 --- a/lms/overrides/user.py +++ b/lms/overrides/user.py @@ -128,6 +128,7 @@ def get_enrolled_courses(): in_progress = [] completed = [] memberships = get_course_membership(frappe.session.user, member_type="Student") + for membership in memberships: course = frappe.db.get_value("LMS Course", membership.course, ["name", "upcoming", "title", "image", "enable_certification", "paid_certificate", "price_certificate", "currency", "published"], as_dict=True) @@ -146,6 +147,7 @@ def get_enrolled_courses(): def get_course_membership(member, member_type=None): """ Returns all memberships of the user. """ + filters = { "member": member } @@ -158,20 +160,20 @@ def get_course_membership(member, member_type=None): def get_authored_courses(member, only_published=True): """ Returns the number of courses authored by this user. """ course_details = [] - - filters = { + courses = frappe.get_all("Course Instructor", { "instructor": member - } - if only_published: - filters["published"] = True - courses = frappe.get_all('LMS Course', filters) + }, ["parent"]) for course in courses: - course_details.append(frappe.db.get_value("LMS Course", course, - ["name", "upcoming", "title", "image", "enable_certification", "status"], as_dict=True)) + detail = frappe.db.get_value("LMS Course", course.parent, + ["name", "upcoming", "title", "image", "enable_certification", "status", "published"], as_dict=True) + if only_published and not detail.published: + continue + course_details.append(detail) return course_details + def get_palette(full_name): """ Returns a color unique to each member for Avatar """ From 6a760c3019598d5bfb02a943774ceefbec42e269 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 09:25:00 +0530 Subject: [PATCH 11/41] chore: removed logs --- lms/lms/web_template/courses_enrolled/courses_enrolled.html | 2 +- lms/templates/courses_created.html | 2 +- lms/www/dashboard/index.html | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lms/lms/web_template/courses_enrolled/courses_enrolled.html b/lms/lms/web_template/courses_enrolled/courses_enrolled.html index 236e8dec..b165aa70 100644 --- a/lms/lms/web_template/courses_enrolled/courses_enrolled.html +++ b/lms/lms/web_template/courses_enrolled/courses_enrolled.html @@ -1,5 +1,5 @@ {% set enrolled = get_enrolled_courses().in_progress + get_enrolled_courses().completed %} -{{ enrolled }} + {% if enrolled | length %}
{% for course in enrolled %} diff --git a/lms/templates/courses_created.html b/lms/templates/courses_created.html index 083317d1..a219ebe1 100644 --- a/lms/templates/courses_created.html +++ b/lms/templates/courses_created.html @@ -1,5 +1,5 @@ {% set courses = get_authored_courses(frappe.session.user, only_published=False) %} -{{ courses }} + {% if courses | length %}
{% for course in courses %} diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index 93f303a1..083cb524 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -8,8 +8,6 @@ {% set portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") %} {% set show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() %} -{{ show_creators_section }} -{{ frappe.session.user }}
From 2819e55a61b1cf15c773295f0887ef33a50c5213 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 10:34:40 +0530 Subject: [PATCH 12/41] fix: dashboard function parameters --- lms/overrides/user.py | 10 +++++----- lms/templates/courses_created.html | 2 +- lms/www/courses/course.html | 17 ----------------- lms/www/profiles/profile.html | 2 +- 4 files changed, 7 insertions(+), 24 deletions(-) diff --git a/lms/overrides/user.py b/lms/overrides/user.py index 00805c7a..617f72bd 100644 --- a/lms/overrides/user.py +++ b/lms/overrides/user.py @@ -127,7 +127,7 @@ class CustomUser(User): def get_enrolled_courses(): in_progress = [] completed = [] - memberships = get_course_membership(frappe.session.user, member_type="Student") + memberships = get_course_membership(None, member_type="Student") for membership in memberships: course = frappe.db.get_value("LMS Course", membership.course, ["name", "upcoming", "title", "image", @@ -145,11 +145,11 @@ def get_enrolled_courses(): "completed": completed } -def get_course_membership(member, member_type=None): +def get_course_membership(member=None, member_type=None): """ Returns all memberships of the user. """ filters = { - "member": member + "member": member or frappe.session.user } if member_type: filters["member_type"] = member_type @@ -157,11 +157,11 @@ def get_course_membership(member, member_type=None): return frappe.get_all("LMS Batch Membership", filters, ["name", "course", "progress"]) -def get_authored_courses(member, only_published=True): +def get_authored_courses(member=None, only_published=True): """ Returns the number of courses authored by this user. """ course_details = [] courses = frappe.get_all("Course Instructor", { - "instructor": member + "instructor": member or frappe.session.user }, ["parent"]) for course in courses: diff --git a/lms/templates/courses_created.html b/lms/templates/courses_created.html index a219ebe1..f51d9d13 100644 --- a/lms/templates/courses_created.html +++ b/lms/templates/courses_created.html @@ -1,4 +1,4 @@ -{% set courses = get_authored_courses(frappe.session.user, only_published=False) %} +{% set courses = get_authored_courses(None, only_published=False) %} {% if courses | length %}
diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index d049ad31..c8f04de8 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -227,23 +227,6 @@ {% endmacro %} -{% macro CourseCreator(course) %} -
{{ _("Course Creators") }}
-
- {% set instructors = get_instructors(course.name) %} - {% for instructor in instructors %} -
- {{ widgets.Avatar(member=instructor, avatar_class="avatar-medium") }} -
-
{{ instructor.full_name }}
-
{{ get_authored_courses(instructor.name) | length }} {{ _("Courses Created") }}
-
-
- {% endfor %} -
-{% endmacro %} - - {% macro RelatedCourses(course) %} {% if course.related_courses | length %} diff --git a/lms/www/profiles/profile.html b/lms/www/profiles/profile.html index bbf242c7..0878c6a4 100644 --- a/lms/www/profiles/profile.html +++ b/lms/www/profiles/profile.html @@ -33,7 +33,7 @@ {% macro ProfileBanner(member) %} {% set cover_image = member.cover_image if member.cover_image else "/assets/lms/images/profile-banner.png" %} -{% set enrollment = get_course_membership(frappe.session.user, member_type="Student") | length %} +{% set enrollment = get_course_membership(None, member_type="Student") | length %} {% set enrollment_suffix = _("Courses") if enrollment > 1 else _("Course") %}
From 7ef625c59800b1a4a6f7ef258e89f2aefb542acf Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 11:35:21 +0530 Subject: [PATCH 13/41] chore: logging user --- lms/lms/doctype/lms_course/lms_course.js | 46 ++++++++++++------------ lms/www/dashboard/index.html | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lms/lms/doctype/lms_course/lms_course.js b/lms/lms/doctype/lms_course/lms_course.js index 2fc82620..c08e1683 100644 --- a/lms/lms/doctype/lms_course/lms_course.js +++ b/lms/lms/doctype/lms_course/lms_course.js @@ -3,31 +3,31 @@ frappe.ui.form.on('LMS Course', { - onload: function (frm) { + onload: function (frm) { - frm.set_query("chapter", "chapters", function () { - return { - filters: { - "course": frm.doc.name, - } - }; - }); + frm.set_query("chapter", "chapters", function () { + return { + filters: { + "course": frm.doc.name, + } + }; + }); - frm.set_query("instructor", function (doc) { - return { - filters: { - "ignore_user_type": 1, - } - }; - }); + frm.set_query("instructor", "instructors", function () { + return { + filters: { + "ignore_user_type": 1, + } + }; + }); - frm.set_query("course", "related_courses", function () { - return { - filters: { - "published": true, - } - }; - }); - } + frm.set_query("course", "related_courses", function () { + return { + filters: { + "published": true, + } + }; + }); + } }); diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index 083cb524..d4897187 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -7,7 +7,7 @@ {% block content %} {% set portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") %} {% set show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() %} - +{{ frappe.session.user }}
From e84e02ff07dbb933e14b8c5ebb84dcedd6fb4941 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 13:32:51 +0530 Subject: [PATCH 14/41] fix: profile, dashboard and tests --- lms/lms/doctype/exercise/test_exercise.py | 9 ++-- lms/lms/doctype/lms_course/test_lms_course.py | 18 +++++++ lms/lms/web_form/profile/profile.json | 20 ++------ lms/overrides/user.py | 3 +- lms/public/css/style.css | 50 +++++++++++-------- lms/www/dashboard/index.html | 4 +- lms/www/dashboard/index.py | 8 +++ lms/www/profiles/profile.html | 2 +- 8 files changed, 68 insertions(+), 46 deletions(-) create mode 100644 lms/www/dashboard/index.py diff --git a/lms/lms/doctype/exercise/test_exercise.py b/lms/lms/doctype/exercise/test_exercise.py index 139b6f7a..9deaa690 100644 --- a/lms/lms/doctype/exercise/test_exercise.py +++ b/lms/lms/doctype/exercise/test_exercise.py @@ -6,10 +6,6 @@ import unittest from lms.lms.doctype.lms_course.test_lms_course import new_course class TestExercise(unittest.TestCase): - def setUp(self): - frappe.db.sql('delete from `tabLMS Batch Membership`') - frappe.db.sql('delete from `tabExercise Submission`') - frappe.db.sql('delete from `tabExercise`') def new_exercise(self): course = new_course("Test Course") @@ -47,3 +43,8 @@ class TestExercise(unittest.TestCase): user_submission = e.get_user_submission() assert user_submission is not None assert user_submission.name == submission.name + + def tearDown(self): + frappe.db.sql('delete from `tabLMS Batch Membership`') + frappe.db.sql('delete from `tabExercise Submission`') + frappe.db.sql('delete from `tabExercise`') diff --git a/lms/lms/doctype/lms_course/test_lms_course.py b/lms/lms/doctype/lms_course/test_lms_course.py index 542db568..ef133bda 100644 --- a/lms/lms/doctype/lms_course/test_lms_course.py +++ b/lms/lms/doctype/lms_course/test_lms_course.py @@ -7,13 +7,16 @@ import frappe from .lms_course import LMSCourse import unittest + class TestLMSCourse(unittest.TestCase): + def test_new_course(self): course = new_course("Test Course") assert course.title == "Test Course" assert course.name == "test-course" + # disabled this test as it is failing def _test_add_mentors(self): course = new_course("Test Course") @@ -26,10 +29,23 @@ class TestLMSCourse(unittest.TestCase): mentors_data = [dict(email=mentor.email, batch_count=mentor.batch_count) for mentor in mentors] assert mentors_data == [{"email": "tester@example.com", "batch_count": 0}] + def tearDown(self): if frappe.db.exists("User", "tester@example.com"): frappe.delete_doc("User", "tester@example.com") + if frappe.db.exists("LMS Course", "test-course"): + frappe.db.delete("Exercise Submission", {"course": "test-course"}) + frappe.db.delete("Exercise Latest Submission", {"course": "test-course"}) + frappe.db.delete("Exercise", {"course": "test-course"}) + frappe.db.delete("LMS Batch Membership", {"course": "test-course"}) + frappe.db.delete("LMS Batch", {"course": "test-course"}) + frappe.db.delete("LMS Course Mentor Mapping", {"course": "test-course"}) + frappe.db.delete("Course Instructor", {"parent": "test-course"}) + frappe.db.sql('delete from `tabCourse Instructor`') + frappe.delete_doc("LMS Course", "test-course") + + def new_user(name, email): user = frappe.db.exists("User", email) if user: @@ -46,6 +62,7 @@ def new_user(name, email): doc.insert() return doc + def new_course(title, additional_filters=None): course = frappe.db.exists("LMS Course", { "title": title }) if course: @@ -66,6 +83,7 @@ def new_course(title, additional_filters=None): doc.insert(ignore_permissions=True) return doc + def create_evaluator(): if not frappe.db.exists("Course Evaluator", "evaluator@example.com"): new_user("Evaluator", "evaluator@example.com") diff --git a/lms/lms/web_form/profile/profile.json b/lms/lms/web_form/profile/profile.json index 705b1e0d..f0e5ab81 100644 --- a/lms/lms/web_form/profile/profile.json +++ b/lms/lms/web_form/profile/profile.json @@ -18,11 +18,11 @@ "docstatus": 0, "doctype": "Web Form", "idx": 0, - "is_multi_step_form": 0, "is_standard": 1, + "list_columns": [], "login_required": 1, "max_attachment_size": 0, - "modified": "2022-06-24 19:08:29.197279", + "modified": "2022-09-05 13:08:40.071348", "modified_by": "Administrator", "module": "LMS", "name": "profile", @@ -30,11 +30,9 @@ "payment_button_label": "Buy Now", "published": 1, "route": "edit-profile", - "route_to_success_link": 0, "show_attachments": 0, - "show_in_grid": 0, + "show_list": 0, "show_sidebar": 0, - "sidebar_items": [], "success_url": "/profile", "title": "Profile", "web_form_fields": [ @@ -50,18 +48,6 @@ "reqd": 1, "show_in_filter": 0 }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "middle_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Middle Name (Optional)", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, { "allow_read_on_all_link_options": 0, "fieldname": "last_name", diff --git a/lms/overrides/user.py b/lms/overrides/user.py index 617f72bd..52db13c7 100644 --- a/lms/overrides/user.py +++ b/lms/overrides/user.py @@ -167,7 +167,8 @@ def get_authored_courses(member=None, only_published=True): for course in courses: detail = frappe.db.get_value("LMS Course", course.parent, ["name", "upcoming", "title", "image", "enable_certification", "status", "published"], as_dict=True) - if only_published and not detail.published: + + if only_published and detail and not detail.published: continue course_details.append(detail) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 6cdfe14b..5a4c85ed 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -44,32 +44,32 @@ input[type=checkbox] { } .course-image .course-tags { - width: 95%; + width: fit-content; } .course-card-pills { - background: #ffffff; - margin-left: 0; - margin-right: 1rem; - 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: 1rem; + 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 { @@ -903,7 +903,7 @@ pre { .empty-state { background: var(--gray-200); border-radius: var(--border-radius-lg); - padding: 2rem; + padding: 1.25rem; display: flex; justify-content: space-between; align-items: center; @@ -911,7 +911,6 @@ pre { .empty-state-text { flex: 1; - margin-left: 1.25rem; text-align: center; } @@ -1667,3 +1666,14 @@ li { color: var(--text-color); cursor: pointer; } + +.course-creation-link { + float: right; +} + +@media (max-width: 500px) { + .course-creation-link { + float: inherit; + margin-bottom: 1rem; + } +} diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index d4897187..03025f98 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -5,14 +5,12 @@ {% block content %} -{% set portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") %} -{% set show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() %} {{ frappe.session.user }}
{% if show_creators_section %} - + {{ _("Create a Course") }} {% endif %} diff --git a/lms/www/dashboard/index.py b/lms/www/dashboard/index.py new file mode 100644 index 00000000..23616076 --- /dev/null +++ b/lms/www/dashboard/index.py @@ -0,0 +1,8 @@ +import frappe +from lms.lms.utils import has_course_instructor_role + + +def get_content(context): + context.no_cache = 1 + portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") + context.show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() diff --git a/lms/www/profiles/profile.html b/lms/www/profiles/profile.html index 0878c6a4..962f4cea 100644 --- a/lms/www/profiles/profile.html +++ b/lms/www/profiles/profile.html @@ -58,7 +58,7 @@ {% if frappe.session.user == member.email %} {% endif %}
From 8f86a8aba63db5bc4ba995f4d0928abddae12717 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 14:46:40 +0530 Subject: [PATCH 15/41] chore: removed log --- lms/www/dashboard/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index 03025f98..fb93273d 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -5,7 +5,6 @@ {% block content %} -{{ frappe.session.user }}
From 3a08f57fb1aa163e0dc5463758c1f16748fb1b96 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 14:53:13 +0530 Subject: [PATCH 16/41] fix: context for dashboard --- lms/www/dashboard/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/www/dashboard/index.py b/lms/www/dashboard/index.py index 23616076..487ebdd1 100644 --- a/lms/www/dashboard/index.py +++ b/lms/www/dashboard/index.py @@ -2,7 +2,7 @@ import frappe from lms.lms.utils import has_course_instructor_role -def get_content(context): +def get_context(context): context.no_cache = 1 portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") context.show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() From 36aca1e664d6f76f0f0e6f7e215894276bfd3635 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 5 Sep 2022 18:05:16 +0530 Subject: [PATCH 17/41] fix: ui for review, instructors and profile --- lms/lms/widgets/CourseCard.html | 8 +++++--- lms/lms/widgets/Reviews.html | 2 +- lms/public/css/style.css | 10 ++++++++++ lms/www/batch/learn.html | 14 ++++++++------ lms/www/profiles/profile.html | 2 +- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lms/lms/widgets/CourseCard.html b/lms/lms/widgets/CourseCard.html index e601811a..6c3b4599 100644 --- a/lms/lms/widgets/CourseCard.html +++ b/lms/lms/widgets/CourseCard.html @@ -90,10 +90,12 @@ {% if ins_len == 1 %} - {{ instructors[0].full_name }} + {{ instructors[0].full_name }} + {% elif ins_len == 2 %} + {{ instructors[0].full_name.split(" ")[0] }} and {{ instructors[1].full_name.split(" ")[0] }} {% else %} - {% set suffix = "other" if ins_len - 1 == 1 else "others" %} - {{ instructors[0].full_name.split(" ")[0] }} and {{ ins_len - 1 }} {{ suffix }} + {% set suffix = "other" if ins_len - 2 == 1 else "others" %} + {{ instructors[0].full_name.split(" ")[0] }}, {{ instructors[1].full_name.split(" ")[0] }} and {{ ins_len - 2 }} {{ suffix }} {% endif %} diff --git a/lms/lms/widgets/Reviews.html b/lms/lms/widgets/Reviews.html index b91ce99f..29015da1 100644 --- a/lms/lms/widgets/Reviews.html +++ b/lms/lms/widgets/Reviews.html @@ -4,7 +4,7 @@
{{ _("Reviews") }} {% if is_eligible_to_review(course.name, membership) and reviews | length %} - + {{ _("Write a review") }} {% endif %} diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 5a4c85ed..2fe71a33 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1677,3 +1677,13 @@ li { margin-bottom: 1rem; } } + +.indicator-pill::before { + width: 0; + height: 0; + margin-right: 0; +} + +.review-link { + float: right +} diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index b8cfc684..5929946a 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -90,12 +90,14 @@ {% endfor %} - {% if ins_len == 1 %} - {{ instructors[0].full_name }} - {% else %} - {% set suffix = _("other") if ins_len - 1 == 1 else _("others") %} - {{ instructors[0].full_name.split(" ")[0] }} and {{ ins_len - 1 }} {{ suffix }} - {% endif %} + {% if ins_len == 1 %} + {{ instructors[0].full_name }} + {% elif ins_len == 2 %} + {{ instructors[0].full_name.split(" ")[0] }} and {{ instructors[1].full_name.split(" ")[0] }} + {% else %} + {% set suffix = "other" if ins_len - 2 == 1 else "others" %} + {{ instructors[0].full_name.split(" ")[0] }}, {{ instructors[1].full_name.split(" ")[0] }} and {{ ins_len - 2 }} {{ suffix }} + {% endif %}
{{ frappe.utils.format_date(lesson.creation, "medium") }}
diff --git a/lms/www/profiles/profile.html b/lms/www/profiles/profile.html index 962f4cea..3a4a6560 100644 --- a/lms/www/profiles/profile.html +++ b/lms/www/profiles/profile.html @@ -58,7 +58,7 @@ {% if frappe.session.user == member.email %} {% endif %}
From 4c969420f3fae60fdef579c8ddd733150cae716e Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 6 Sep 2022 11:19:11 +0530 Subject: [PATCH 18/41] feat: course moderator --- lms/hooks.py | 1 + lms/lms/utils.py | 12 ++++++++++ lms/patches.txt | 1 + .../v0_0/create_course_moderator_role.py | 11 +++++++++ lms/templates/courses_under_review.html | 20 ++++++++++++++++ lms/www/batch/learn.py | 4 ++-- lms/www/courses/course.py | 4 ++-- lms/www/dashboard/index.html | 23 ++++++++++++++++--- lms/www/dashboard/index.py | 3 ++- 9 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 lms/patches/v0_0/create_course_moderator_role.py create mode 100644 lms/templates/courses_under_review.html diff --git a/lms/hooks.py b/lms/hooks.py index 3e1e92d2..e45b76d4 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -192,6 +192,7 @@ jinja = { "lms.lms.utils.get_popular_courses", "lms.lms.utils.format_amount", "lms.lms.utils.first_lesson_exists", + "lms.lms.utils.get_courses_under_review", "lms.lms.utils.has_course_instructor_role" ], "filters": [] diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 5fd64ca3..1eaf9ca3 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -440,3 +440,15 @@ def has_course_instructor_role(): "parent": frappe.session.user, "role": "Course Instructor" }, "name") + + +def has_course_moderator_role(): + return frappe.db.get_value("Has Role", { + "parent": frappe.session.user, + "role": "Course Moderator" + }, "name") + + +def get_courses_under_review(): + return "jan" + diff --git a/lms/patches.txt b/lms/patches.txt index f8a1d28a..8ea2108a 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -31,3 +31,4 @@ lms.patches.v0_0.quiz_submission_member lms.patches.v0_0.delete_old_module_docs #08-07-2022 lms.patches.v0_0.delete_course_web_forms #21-08-2022 lms.patches.v0_0.create_course_instructor_role #29-08-2022 +lms.patches.v0_0.create_course_moderator_role diff --git a/lms/patches/v0_0/create_course_moderator_role.py b/lms/patches/v0_0/create_course_moderator_role.py new file mode 100644 index 00000000..f7127c81 --- /dev/null +++ b/lms/patches/v0_0/create_course_moderator_role.py @@ -0,0 +1,11 @@ +import frappe + +def execute(): + if not frappe.db.exists("Role", "Course Moderator"): + role = frappe.get_doc({ + "doctype": "Role", + "role_name": "Course Moderator", + "home_page": "/dashboard", + "desk_access": 0 + }) + role.save(ignore_permissions=True) diff --git a/lms/templates/courses_under_review.html b/lms/templates/courses_under_review.html new file mode 100644 index 00000000..7b0fa109 --- /dev/null +++ b/lms/templates/courses_under_review.html @@ -0,0 +1,20 @@ +{% set courses = get_courses_under_review() %} + +{% if courses | length %} +
+ {% for course in courses %} + {{ widgets.CourseCard(course=course) }} + {% endfor %} +
+ +{% else %} +
+
+ +
+
+
{{ _("No courses created") }}
+
{{ _("Help others learn something new.") }}
+
+
+{% endif %} diff --git a/lms/www/batch/learn.py b/lms/www/batch/learn.py index b3f59b76..659654dc 100644 --- a/lms/www/batch/learn.py +++ b/lms/www/batch/learn.py @@ -1,6 +1,6 @@ import frappe from lms.www.utils import get_common_context, redirect_to_lesson -from lms.lms.utils import get_lesson_url, is_instructor, redirect_to_courses_list +from lms.lms.utils import get_lesson_url, has_course_moderator_role, is_instructor, redirect_to_courses_list from frappe.utils import cstr, flt def get_context(context): @@ -27,7 +27,7 @@ def get_context(context): context.lesson = frappe._dict() if frappe.form_dict.get("edit"): - if not is_instructor(context.course.name): + if not is_instructor(context.course.name) or has_course_moderator_role(): redirect_to_courses_list() context.lesson.edit_mode = True else: diff --git a/lms/www/courses/course.py b/lms/www/courses/course.py index fb83fd9b..4bf95a8e 100644 --- a/lms/www/courses/course.py +++ b/lms/www/courses/course.py @@ -1,6 +1,6 @@ import frappe from lms.lms.doctype.lms_settings.lms_settings import check_profile_restriction -from lms.lms.utils import get_membership, is_instructor, is_certified, get_evaluation_details, redirect_to_courses_list +from lms.lms.utils import get_membership, has_course_moderator_role, is_instructor, is_certified, get_evaluation_details, redirect_to_courses_list def get_context(context): context.no_cache = 1 @@ -28,7 +28,7 @@ def set_course_context(context, course_name): as_dict=True) if frappe.form_dict.get("edit"): - if not is_instructor(course.name): + if not is_instructor(course.name) or not has_course_moderator_role(): redirect_to_courses_list() course.edit_mode = True diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index fb93273d..c7d76e57 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -16,12 +16,23 @@
{% endif %} -
+ {% if show_review_section %} +
+ {% include "lms/templates/courses_under_review.html" %} +
+ {% endif %} + +
diff --git a/lms/www/dashboard/index.py b/lms/www/dashboard/index.py index 487ebdd1..68951425 100644 --- a/lms/www/dashboard/index.py +++ b/lms/www/dashboard/index.py @@ -1,8 +1,9 @@ import frappe -from lms.lms.utils import has_course_instructor_role +from lms.lms.utils import has_course_instructor_role, has_course_moderator_role def get_context(context): context.no_cache = 1 portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") context.show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role() + context.show_review_section = has_course_moderator_role() From ce7f3ffca9da5f729f21a25644ed6da8452c707e Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 6 Sep 2022 11:38:40 +0530 Subject: [PATCH 19/41] fix: no preview message --- lms/lms/widgets/CourseCard.html | 4 ++-- lms/www/batch/learn.html | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lms/lms/widgets/CourseCard.html b/lms/lms/widgets/CourseCard.html index 6c3b4599..a7555a65 100644 --- a/lms/lms/widgets/CourseCard.html +++ b/lms/lms/widgets/CourseCard.html @@ -94,8 +94,8 @@ {% elif ins_len == 2 %} {{ instructors[0].full_name.split(" ")[0] }} and {{ instructors[1].full_name.split(" ")[0] }} {% else %} - {% set suffix = "other" if ins_len - 2 == 1 else "others" %} - {{ instructors[0].full_name.split(" ")[0] }}, {{ instructors[1].full_name.split(" ")[0] }} and {{ ins_len - 2 }} {{ suffix }} + {% set suffix = "other" if ins_len - 1 == 1 else "others" %} + {{ instructors[0].full_name.split(" ")[0] }} and {{ ins_len - 1 }} {{ suffix }} {% endif %} diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index 5929946a..78896567 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -95,8 +95,8 @@ {% elif ins_len == 2 %} {{ instructors[0].full_name.split(" ")[0] }} and {{ instructors[1].full_name.split(" ")[0] }} {% else %} - {% set suffix = "other" if ins_len - 2 == 1 else "others" %} - {{ instructors[0].full_name.split(" ")[0] }}, {{ instructors[1].full_name.split(" ")[0] }} and {{ ins_len - 2 }} {{ suffix }} + {% set suffix = "other" if ins_len - 1 == 1 else "others" %} + {{ instructors[0].full_name.split(" ")[0] }} and {{ ins_len - 1 }} {{ suffix }} {% endif %} @@ -124,9 +124,9 @@ {% set course_link = "" + _('here') + "" %}
- {{ _("This lesson is not available for preview. + {{ _("There is no preview available for this lesson. Please join the course to access it. - Click {0} to join the course.").format(course_link) }} + Click {0} to enroll.").format(course_link) }}
{% endif %} From 9dc10c3756443749b8ac4494862de157e00ff268 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 9 Sep 2022 15:37:35 +0530 Subject: [PATCH 20/41] feat: allow moderators to edit course --- lms/hooks.py | 3 ++- lms/lms/utils.py | 5 ++++- lms/lms/widgets/CourseCard.html | 2 +- lms/lms/widgets/CourseOutline.html | 3 +++ lms/www/batch/learn.js | 6 +----- lms/www/batch/learn.py | 2 +- lms/www/courses/course.html | 8 ++++---- lms/www/courses/course.js | 2 +- lms/www/courses/course.py | 2 +- 9 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lms/hooks.py b/lms/hooks.py index e45b76d4..188a9e45 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -193,7 +193,8 @@ jinja = { "lms.lms.utils.format_amount", "lms.lms.utils.first_lesson_exists", "lms.lms.utils.get_courses_under_review", - "lms.lms.utils.has_course_instructor_role" + "lms.lms.utils.has_course_instructor_role", + "lms.lms.utils.has_course_moderator_role" ], "filters": [] } diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 1eaf9ca3..047b43f7 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -450,5 +450,8 @@ def has_course_moderator_role(): def get_courses_under_review(): - return "jan" + return frappe.get_all("LMS Course", { + "status": "Under Review" + }, ["name", "upcoming", "title", "image", "enable_certification", "status", "published"] + ) diff --git a/lms/lms/widgets/CourseCard.html b/lms/lms/widgets/CourseCard.html index a7555a65..c84ab45d 100644 --- a/lms/lms/widgets/CourseCard.html +++ b/lms/lms/widgets/CourseCard.html @@ -3,7 +3,7 @@
+ style="background-image: url( {{ course.image | urlencode }} );" {% endif %}>
{% for tag in get_tags(course.name) %}
{{ tag }}
diff --git a/lms/lms/widgets/CourseOutline.html b/lms/lms/widgets/CourseOutline.html index b146c3fd..d2f47904 100644 --- a/lms/lms/widgets/CourseOutline.html +++ b/lms/lms/widgets/CourseOutline.html @@ -185,3 +185,6 @@ const show_no_preview_dialog = (e) => { }; +dahanukar +sandesh +chetna diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 197ca8a7..50178845 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -542,10 +542,6 @@ const build_attachment_table = (file_doc) => { const make_editor = () => { - let comment = `` this.code_field_group = new frappe.ui.FieldGroup({ fields: [ @@ -556,7 +552,7 @@ const make_editor = () => { wrap: true, max_lines: Infinity, min_lines: 20, - default: $("#body").data("body") || comment, + default: $("#body").data("body"), depends_on: 'eval:doc.type=="Markdown"', } ], diff --git a/lms/www/batch/learn.py b/lms/www/batch/learn.py index 659654dc..9519c776 100644 --- a/lms/www/batch/learn.py +++ b/lms/www/batch/learn.py @@ -27,7 +27,7 @@ def get_context(context): context.lesson = frappe._dict() if frappe.form_dict.get("edit"): - if not is_instructor(context.course.name) or has_course_moderator_role(): + if not is_instructor(context.course.name) and not has_course_moderator_role(): redirect_to_courses_list() context.lesson.edit_mode = True else: diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index c8f04de8..75d26a28 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -270,7 +270,7 @@ membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %} {% if show_start_learing_cta %} -
+
{{ _("Start Learning") }}
@@ -323,7 +323,7 @@ {% endif %} {% endif %} - {% if is_instructor(course.name) %} + {% if is_instructor(course.name) or has_course_moderator_role() %} {{ _("Edit Course") }} {% endif %} {% endmacro %} @@ -341,9 +341,9 @@ frappe.utils.format_time(certificate_request.start_time, "short")) }}

{% endif %} - {% if course.status == "Under Review" %} + {% if course.status == "Under Review" and is_instructor(course.name) %}
- {{ _("Your course is currently under review. Once the review is complete, the System Admins will publish it on the website.") }} + {{ _("This course is currently under review. Once the review is complete, the System Admins will publish it on the website.") }}
{% endif %} diff --git a/lms/www/courses/course.js b/lms/www/courses/course.js index 9e9f086b..083391f7 100644 --- a/lms/www/courses/course.js +++ b/lms/www/courses/course.js @@ -206,7 +206,7 @@ const submit_for_review = (e) => { }, 3); setTimeout(() => { window.location.reload(); - }, 3000); + }, 1000); } } }); diff --git a/lms/www/courses/course.py b/lms/www/courses/course.py index 4bf95a8e..f56f1ad2 100644 --- a/lms/www/courses/course.py +++ b/lms/www/courses/course.py @@ -28,7 +28,7 @@ def set_course_context(context, course_name): as_dict=True) if frappe.form_dict.get("edit"): - if not is_instructor(course.name) or not has_course_moderator_role(): + if not is_instructor(course.name) and not has_course_moderator_role(): redirect_to_courses_list() course.edit_mode = True From 6d14bc2f54d8fa0061aed29c40a3074b5205b816 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 9 Sep 2022 16:04:53 +0530 Subject: [PATCH 21/41] fix: encode course image --- lms/lms/widgets/CourseCard.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/lms/widgets/CourseCard.html b/lms/lms/widgets/CourseCard.html index a7555a65..c84ab45d 100644 --- a/lms/lms/widgets/CourseCard.html +++ b/lms/lms/widgets/CourseCard.html @@ -3,7 +3,7 @@
+ style="background-image: url( {{ course.image | urlencode }} );" {% endif %}>
{% for tag in get_tags(course.name) %}
{{ tag }}
From 212ed8e428bc17eb288c42e1b8f9192a7d3e87d0 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 9 Sep 2022 18:16:02 +0530 Subject: [PATCH 22/41] feat: course settings from website --- lms/lms/doctype/lms_course/lms_course.py | 6 ++++-- lms/lms/widgets/CourseOutline.html | 6 ++---- lms/public/css/style.css | 1 - lms/www/batch/learn.html | 11 ++++++----- lms/www/batch/learn.py | 5 ++++- lms/www/batch/quiz.html | 6 ++++-- lms/www/courses/course.html | 20 ++++++++++++++++++++ lms/www/courses/course.js | 4 +++- 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/lms/lms/doctype/lms_course/lms_course.py b/lms/lms/doctype/lms_course/lms_course.py index 0f497eb3..f6008f3d 100644 --- a/lms/lms/doctype/lms_course/lms_course.py +++ b/lms/lms/doctype/lms_course/lms_course.py @@ -194,7 +194,7 @@ def submit_for_review(course): @frappe.whitelist() -def save_course(tags, title, short_introduction, video_link, description, course, image=None): +def save_course(tags, title, short_introduction, video_link, description, course, published, upcoming, image=None): if course: doc = frappe.get_doc("LMS Course", course) else: @@ -208,7 +208,9 @@ def save_course(tags, title, short_introduction, video_link, description, course "video_link": video_link, "image": image, "description": description, - "tags": tags + "tags": tags, + "published": published, + "upcoming": upcoming }) doc.save(ignore_permissions=True) return doc.name diff --git a/lms/lms/widgets/CourseOutline.html b/lms/lms/widgets/CourseOutline.html index d2f47904..2aec5324 100644 --- a/lms/lms/widgets/CourseOutline.html +++ b/lms/lms/widgets/CourseOutline.html @@ -55,7 +55,7 @@ {% set active = membership.current_lesson == lesson.name %}
- {% if membership or lesson.include_in_preview or is_instructor %} + {% if membership or lesson.include_in_preview or is_instructor or has_course_moderator_role() %} { }; -dahanukar -sandesh -chetna + diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 2fe71a33..b8b2b9f7 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -74,7 +74,6 @@ input[type=checkbox] { .common-page-style { padding: 2rem 0 5rem; - min-height: 60vh; padding-top: 3rem; background-color: var(--bg-color); } diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index 78896567..629e4ca0 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -57,6 +57,7 @@ {% macro LessonContent(lesson) %} {% set instructors = get_instructors(course.name) %} {% set is_instructor = is_instructor(course.name) %} +
@@ -70,7 +71,7 @@ {{ _("COMPLETED") }} - {% if is_instructor and not lesson.edit_mode %} + {% if (is_instructor or has_course_moderator_role()) and not lesson.edit_mode %} {% endif %}
@@ -105,7 +106,7 @@
- {% if membership or lesson.include_in_preview or is_instructor %} + {% if show_lesson %} {% if is_instructor and not lesson.include_in_preview and not lesson.edit_mode %}
@@ -190,9 +191,9 @@
{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}
-
diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index 75d26a28..7472880a 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -18,6 +18,7 @@
{{ CourseHeaderOverlay(course) }} + {{ CourseSettings(course) }} {{ Description(course) }} {{ Save(course) }} {{ widgets.CourseOutline(course=course, membership=membership, is_user_interested=is_user_interested) }} @@ -210,6 +211,25 @@ {% endmacro %} + +{% macro CourseSettings(course) %} + + {% if has_course_moderator_role() %} +
+ + +
+ {% endif %} + +{% endmacro %} + + {% macro Save(course) %} {% if course.edit_mode %} diff --git a/lms/www/courses/course.js b/lms/www/courses/course.js index 083391f7..0669f119 100644 --- a/lms/www/courses/course.js +++ b/lms/www/courses/course.js @@ -339,7 +339,9 @@ const save_course = (e) => { "video_link": $("#video-link").text(), "image": $("#image").attr("href"), "description": $("#description").text(), - "course": $("#title").data("course") ? $("#title").data("course") : "" + "course": $("#title").data("course") ? $("#title").data("course") : "", + "published": $("#published").prop("checked") ? 1 : 0, + "upcoming": $("#upcoming").prop("checked") ? 1 : 0 }, callback: (data) => { frappe.show_alert({ From b94a4ef9d6e4752d2e8d769375582011b819d5ac Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 12 Sep 2022 12:06:36 +0530 Subject: [PATCH 23/41] feat: role settings from profile --- lms/lms/utils.py | 10 ++++---- lms/overrides/user.py | 19 ++++++++++++++ lms/public/css/style.css | 5 ++++ lms/www/courses/course.html | 4 +-- lms/www/profiles/profile.html | 47 ++++++++++++++++++++--------------- lms/www/profiles/profile.js | 42 +++++++++++++++++++++++++++++++ lms/www/profiles/profile.py | 5 +++- 7 files changed, 104 insertions(+), 28 deletions(-) create mode 100644 lms/www/profiles/profile.js diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 047b43f7..22f78197 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -435,16 +435,16 @@ def redirect_to_courses_list(): raise frappe.Redirect -def has_course_instructor_role(): +def has_course_instructor_role(member=None): return frappe.db.get_value("Has Role", { - "parent": frappe.session.user, + "parent": member or frappe.session.user, "role": "Course Instructor" }, "name") -def has_course_moderator_role(): +def has_course_moderator_role(member=None): return frappe.db.get_value("Has Role", { - "parent": frappe.session.user, + "parent": member or frappe.session.user, "role": "Course Moderator" }, "name") @@ -453,5 +453,5 @@ def get_courses_under_review(): return frappe.get_all("LMS Course", { "status": "Under Review" }, ["name", "upcoming", "title", "image", "enable_certification", "status", "published"] - ) +) diff --git a/lms/overrides/user.py b/lms/overrides/user.py index 52db13c7..820a4be5 100644 --- a/lms/overrides/user.py +++ b/lms/overrides/user.py @@ -330,3 +330,22 @@ def get_users(or_filters, start, page_length, text): """.format(or_filters = or_filters, start=start, page_length=page_length), as_dict=1) return users + + +@frappe.whitelist() +def save_role(user, role, value): + if cint(value): + doc = frappe.get_doc({ + "doctype": "Has Role", + "parent": user, + "role": role, + "parenttype": "User", + "parentfield": "roles" + }) + doc.save(ignore_permissions=True) + else: + frappe.db.delete("Has Role", { + "parent": user, + "role": role + }) + return True diff --git a/lms/public/css/style.css b/lms/public/css/style.css index b8b2b9f7..d24d8ff8 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1686,3 +1686,8 @@ li { .review-link { float: right } + +.role { + margin-bottom: 0; + cursor: pointer; +} diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index 7472880a..4fdaf48e 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -214,7 +214,7 @@ {% macro CourseSettings(course) %} - {% if has_course_moderator_role() %} + {% if course.edit_mode and has_course_moderator_role() %}
- {% elif course.upcoming and not is_user_interested %} + {% elif course.upcoming and not is_user_interested and not is_instructor %}
{{ _("Notify me when available") }}
diff --git a/lms/www/profiles/profile.html b/lms/www/profiles/profile.html index 3a4a6560..ad3ff2bc 100644 --- a/lms/www/profiles/profile.html +++ b/lms/www/profiles/profile.html @@ -11,6 +11,7 @@
{% set read_only = member.name != frappe.session.user %} + {{ RoleSettings(member) }} {{ About(member) }} {{ EducationDetails(member) }} {{ WorkDetails(member) }} @@ -45,7 +46,7 @@
-
{{ member.full_name }}
+
{{ member.full_name }}
{% if get_authored_courses(member.name) | length %}
{{ _("Creator") }}
@@ -155,10 +156,34 @@ {% endmacro %} + +{% macro RoleSettings(member) %} + {% if has_course_moderator_role() %} +
+
+
{{ _("Role Settings") }}
+
+ + +
+
+
+ {% endif %} +{% endmacro %} + + {% macro About(member) %} {% if member.bio %} -
+
{{ _("About") }}
{{ member.bio }}
@@ -386,21 +411,3 @@
{% endif %} {% endmacro %} - - -{% block script %} - -{% endblock %} diff --git a/lms/www/profiles/profile.js b/lms/www/profiles/profile.js new file mode 100644 index 00000000..da344e2a --- /dev/null +++ b/lms/www/profiles/profile.js @@ -0,0 +1,42 @@ +frappe.ready(() => { + + make_profile_active_in_navbar(); + + $(".role").change((e) => { + save_role(e); + }); + +}); + + +const make_profile_active_in_navbar = () => { + let member_name = $(".profile-name").data("name"); + if (member_name == frappe.session.user) { + setTimeout(() => { + let link_array = $('.nav-link').filter((i, elem) => $(elem).text().trim() === "My Profile"); + link_array.length && $(link_array[0]).addClass("active"); + }, 0) + } +} + + +const save_role = (e) => { + let member_name = $(".profile-name").data("name"); + let role = $(e.currentTarget).children("input"); + frappe.call({ + method: "lms.overrides.user.save_role", + args: { + "user": member_name, + "role": role.data("role"), + "value": role.prop("checked") ? 1 : 0 + }, + callback: (data) => { + if (data.message) { + frappe.show_alert({ + message: __("Saved"), + indicator: "green", + }); + } + } + }) +} diff --git a/lms/www/profiles/profile.py b/lms/www/profiles/profile.py index 93ac9136..ddbdf481 100644 --- a/lms/www/profiles/profile.py +++ b/lms/www/profiles/profile.py @@ -1,6 +1,6 @@ import frappe from lms.page_renderers import get_profile_url_prefix -from urllib.parse import urlencode + def get_context(context): context.no_cache = 1 @@ -12,13 +12,16 @@ def get_context(context): if username: frappe.local.flags.redirect_location = get_profile_url_prefix() + username raise frappe.Redirect + try: context.member = frappe.get_doc("User", {"username": username}) except: context.template = "www/404.html" return + context.profile_tabs = get_profile_tabs(context.member) + def get_profile_tabs(user): """Returns the enabled ProfileTab objects. From d8d0ce5b451fbf344b45337af56e5c79118e47a0 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 12 Sep 2022 12:15:30 +0530 Subject: [PATCH 24/41] fix: empty state for review section --- lms/templates/courses_under_review.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lms/templates/courses_under_review.html b/lms/templates/courses_under_review.html index 7b0fa109..394ec66e 100644 --- a/lms/templates/courses_under_review.html +++ b/lms/templates/courses_under_review.html @@ -13,8 +13,7 @@
-
{{ _("No courses created") }}
-
{{ _("Help others learn something new.") }}
+
{{ _("No courses under review") }}
{% endif %} From 46861486c9011c2c718185c914b13dd6b57efa15 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 12 Sep 2022 13:00:51 +0530 Subject: [PATCH 25/41] fix: text editor for description field --- lms/www/batch/learn.js | 1 - lms/www/courses/course.html | 16 +++++++++++++--- lms/www/courses/course.js | 29 ++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 50178845..620c2b53 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -542,7 +542,6 @@ const build_attachment_table = (file_doc) => { const make_editor = () => { - this.code_field_group = new frappe.ui.FieldGroup({ fields: [ { diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index 4fdaf48e..e4c24cc4 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -205,9 +205,13 @@ {% macro Description(course) %} -
{% if course.description %}{{ frappe.utils.md_to_html(course.description) }}{% endif %}
+ {% if course.edit_mode %} +
+ {% else %} +
+ {{ frappe.utils.md_to_html(course.description) }} +
+ {% endif %} {% endmacro %} @@ -419,3 +423,9 @@
{% endmacro %} + + +{% block base_scripts %} + {{ include_script("frappe-web.bundle.js") }} + {{ include_script('controls.bundle.js') }} +{% endblock %} diff --git a/lms/www/courses/course.js b/lms/www/courses/course.js index 0669f119..06fbec3e 100644 --- a/lms/www/courses/course.js +++ b/lms/www/courses/course.js @@ -70,6 +70,10 @@ frappe.ready(() => { remove_tag(e); }); + if ($("#description").length) { + make_editor(); + } + }); @@ -338,7 +342,7 @@ const save_course = (e) => { "short_introduction": $("#intro").text(), "video_link": $("#video-link").text(), "image": $("#image").attr("href"), - "description": $("#description").text(), + "description": this.code_field_group.fields_dict["code_md"].value, "course": $("#title").data("course") ? $("#title").data("course") : "", "published": $("#published").prop("checked") ? 1 : 0, "upcoming": $("#upcoming").prop("checked") ? 1 : 0 @@ -359,3 +363,26 @@ const save_course = (e) => { const remove_tag = (e) => { $(e.currentTarget).closest(".course-card-pills").remove(); }; + + +const make_editor = () => { + this.code_field_group = new frappe.ui.FieldGroup({ + fields: [ + { + fieldname: "code_md", + fieldtype: "Code", + options: "Markdown", + wrap: true, + max_lines: Infinity, + min_lines: 20, + default: $("#description").data("description"), + depends_on: 'eval:doc.type=="Markdown"', + } + ], + body: $("#description").get(0), + }); + this.code_field_group.make(); + $("#description .form-section:last").removeClass("empty-section"); + $("#description .frappe-control").removeClass("hide-control"); + $("#description .form-column").addClass("p-0"); +}; From 7d7f674d9eba78b18fe938315f8a05cd5d2a485e Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 12 Sep 2022 18:17:06 +0530 Subject: [PATCH 26/41] fix: empty states --- .../courses_enrolled/courses_enrolled.html | 38 ++- lms/lms/widgets/Reviews.html | 309 +++++++++--------- lms/public/css/style.css | 12 +- lms/templates/courses_created.html | 4 +- lms/templates/courses_under_review.html | 5 +- lms/www/batch/quiz_list.html | 24 +- lms/www/community/index.html | 2 +- lms/www/courses/index.html | 50 +-- lms/www/jobs/index.html | 11 +- 9 files changed, 232 insertions(+), 223 deletions(-) diff --git a/lms/lms/web_template/courses_enrolled/courses_enrolled.html b/lms/lms/web_template/courses_enrolled/courses_enrolled.html index b165aa70..298a2363 100644 --- a/lms/lms/web_template/courses_enrolled/courses_enrolled.html +++ b/lms/lms/web_template/courses_enrolled/courses_enrolled.html @@ -1,29 +1,31 @@ {% set enrolled = get_enrolled_courses().in_progress + get_enrolled_courses().completed %} + {% if enrolled | length %}
- {% for course in enrolled %} - {{ widgets.CourseCard(course=course) }} - {% endfor %} + {% for course in enrolled %} + {{ widgets.CourseCard(course=course) }} + {% endfor %}
+ {% else %} {% set site_name = frappe.db.get_single_value("System Settings", "app_name") %} -
-
-
-
{{ _("You haven't enrolled for any courses") }}
-
{{ _("Here are a few courses we recommend for you to get started with {0}").format(site_name) }}
+
+
+
+
{{ _("You haven't enrolled for any courses") }}
+
{{ _("Here are a few courses we recommend for you to get started with {0}").format(site_name) }}
+
+ {% set recommended_courses = get_popular_courses() %} +
+ {% for course in recommended_courses %} + {% if course %} + {% set course_details = frappe.get_doc("LMS Course", course.course) %} + {{ widgets.CourseCard(course=course_details) }} + {% endif %} + {% endfor %} +
- {% set recommended_courses = get_popular_courses() %} -
- {% for course in recommended_courses %} - {% if course %} - {% set course_details = frappe.get_doc("LMS Course", course.course) %} - {{ widgets.CourseCard(course=course_details) }} - {% endif %} - {% endfor %} -
-
{% endif %} diff --git a/lms/lms/widgets/Reviews.html b/lms/lms/widgets/Reviews.html index 29015da1..89904e55 100644 --- a/lms/lms/widgets/Reviews.html +++ b/lms/lms/widgets/Reviews.html @@ -1,166 +1,169 @@ {% if not course.upcoming %}
- {% set reviews = get_reviews(course.name) %} -
- {{ _("Reviews") }} - {% if is_eligible_to_review(course.name, membership) and reviews | length %} - - {{ _("Write a review") }} - - {% endif %} -
- - {% set avg_rating = get_average_rating(course.name) %} - {% if avg_rating %} -
-
-
{{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }}
-
{{ reviews | length }} {{ _("ratings") }}
-
-
- {% for i in [1, 2, 3, 4, 5] %} - - - - {% endfor %} -
-
-
- {{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }} {{ _("out of 5 ") }} -
-
-
- {% set sorted_reviews = get_sorted_reviews(course.name) %} -
- {% for review in sorted_reviews %} -
-
{{ frappe.utils.cint(review) }} {{ _("stars") }}
-
-
- {{ sorted_reviews[review] }} Complete -
-
-
{{ frappe.utils.cint(sorted_reviews[review]) }}%
-
- {% endfor %} -
-
- {% endif %} - - {% if reviews | length %} -
- {% for review in reviews %} -
-
- -
- {{ widgets.Avatar(member=review.owner_details, avatar_class="avatar-medium") }} -
- -
-
- - - {{ review.owner_details.full_name }} - - -
frappe.utils.pretty_date(review.creation)
-
- -
- {% for i in [1, 2, 3, 4, 5] %} - - - - {% endfor %} -
-
-
- -
{{ review.review }}
-
- {% if loop.index != reviews | length %} -
- {% endif %} - {% endfor %} -
- - {% else %} -
-
- -
-
-
{{ _("Review the course") }}
-
{{ _("Help us improve our course material.") }}
-
-
- {% if not is_instructor(course.name) %} + {% set reviews = get_reviews(course.name) %} +
+ {{ _("Reviews") }} {% if is_eligible_to_review(course.name, membership) %} - - {{ _("Write a review") }} - - {% elif frappe.session.user == "Guest" %} - {{ _("Login") }} - {% elif not membership %} -
{{ _("Start Learning") }}
+ + {{ _("Write a review") }} + + {% elif not is_instructor(course.name) and frappe.session.user == "Guest" %} + {{ _("Login") }} + {% elif not is_instructor(course.name) and not membership %} +
{{ _("Start Learning") }}
{% endif %} - {% endif %}
-
- {% endif %} + + + {% set avg_rating = get_average_rating(course.name) %} + {% if avg_rating %} +
+
+
+ {{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }} +
+
{{ reviews | length }} {{ _("ratings") }}
+
+
+ {% for i in [1, 2, 3, 4, 5] %} + + + + {% endfor %} +
+
+
+ {{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }} {{ _("out of 5 ") }} +
+
+ + +
+ {% set sorted_reviews = get_sorted_reviews(course.name) %} +
+ {% for review in sorted_reviews %} +
+
+ {{ frappe.utils.cint(review) }} {{ _("stars") }} +
+
+
+ {{ sorted_reviews[review] }} Complete +
+
+
{{ frappe.utils.cint(sorted_reviews[review]) }}%
+
+ {% endfor %} +
+
+ {% endif %} + + + {% if reviews | length %} +
+ {% for review in reviews %} +
+
+
+ {{ widgets.Avatar(member=review.owner_details, avatar_class="avatar-medium") }} +
+
+
+ + + {{ review.owner_details.full_name }} + + +
+ {{ frappe.utils.pretty_date(review.creation) }} +
+
+
+ {% for i in [1, 2, 3, 4, 5] %} + + + + {% endfor %} +
+
+
+
{{ review.review }}
+
+ {% if loop.index != reviews | length %} +
+ {% endif %} + {% endfor %} +
+ + + {% else %} +
+ +
+
{{ _("Review the course") }}
+
{{ _("Help us improve our course material.") }}
+
+
+ {% endif %}
-