From 668130d4433cc4e8f3e5c2808dad1c794c5cb6ae Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 22 Aug 2022 12:58:54 +0530 Subject: [PATCH] feat: access for course creation --- lms/hooks.py | 3 +- lms/lms/doctype/lms_quiz/test_lms_quiz.py | 8 +-- .../doctype/lms_settings/lms_settings.json | 11 +-- lms/lms/utils.py | 7 ++ lms/patches.txt | 1 + .../v0_0/create_course_instructor_role.py | 10 +++ lms/public/css/style.css | 2 +- lms/public/js/common_functions.js | 2 +- lms/templates/courses_created.html | 27 ++++--- lms/templates/quiz.html | 3 +- .../search_course/search_course.html | 27 +++---- lms/www/batch/learn.html | 2 + lms/www/batch/learn.js | 13 ++-- lms/www/batch/learn.py | 16 +++-- lms/www/courses/course.html | 5 +- lms/www/courses/index.html | 6 +- lms/www/dashboard/index.html | 72 +++++++++---------- 17 files changed, 123 insertions(+), 92 deletions(-) create mode 100644 lms/patches/v0_0/create_course_instructor_role.py diff --git a/lms/hooks.py b/lms/hooks.py index 4f2589f8..3e1e92d2 100644 --- a/lms/hooks.py +++ b/lms/hooks.py @@ -191,7 +191,8 @@ jinja = { "lms.lms.utils.get_signup_optin_checks", "lms.lms.utils.get_popular_courses", "lms.lms.utils.format_amount", - "lms.lms.utils.first_lesson_exists" + "lms.lms.utils.first_lesson_exists", + "lms.lms.utils.has_course_instructor_role" ], "filters": [] } diff --git a/lms/lms/doctype/lms_quiz/test_lms_quiz.py b/lms/lms/doctype/lms_quiz/test_lms_quiz.py index e778aab8..ef004896 100644 --- a/lms/lms/doctype/lms_quiz/test_lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/test_lms_quiz.py @@ -15,7 +15,7 @@ class TestLMSQuiz(unittest.TestCase): }).save(ignore_permissions=True) def test_with_multiple_options(self): - quiz = frappe.get_doc("LMS Quiz", "Test Quiz") + quiz = frappe.get_doc("LMS Quiz", "test-quiz") quiz.append("questions", { "question": "Question multiple", "option_1": "Option 1", @@ -27,7 +27,7 @@ class TestLMSQuiz(unittest.TestCase): self.assertTrue(quiz.questions[0].multiple) def test_with_no_correct_option(self): - quiz = frappe.get_doc("LMS Quiz", "Test Quiz") + quiz = frappe.get_doc("LMS Quiz", "test-quiz") quiz.append("questions", { "question": "Question no correct option", "option_1": "Option 1", @@ -37,5 +37,5 @@ class TestLMSQuiz(unittest.TestCase): @classmethod def tearDownClass(cls) -> None: - frappe.db.delete("LMS Quiz", "Test Quiz") - frappe.db.delete("LMS Quiz Question", {"parent": "Test Quiz"}) + frappe.db.delete("LMS Quiz", "test-quiz") + frappe.db.delete("LMS Quiz Question", {"parent": "test-quiz"}) diff --git a/lms/lms/doctype/lms_settings/lms_settings.json b/lms/lms/doctype/lms_settings/lms_settings.json index afbbbc1a..5e0fbbe9 100644 --- a/lms/lms/doctype/lms_settings/lms_settings.json +++ b/lms/lms/doctype/lms_settings/lms_settings.json @@ -6,8 +6,8 @@ "engine": "InnoDB", "field_order": [ "show_search", - "portal_course_creation", "force_profile_completion", + "portal_course_creation", "column_break_2", "search_placeholder", "custom_certificate_template", @@ -110,10 +110,11 @@ "fieldtype": "Column Break" }, { - "default": "0", + "default": "Course Instructor Role", "fieldname": "portal_course_creation", - "fieldtype": "Check", - "label": "Enable Course Creation from Portal" + "fieldtype": "Select", + "label": "Course Creation Access Through Website To", + "options": "Course Instructor Role\nAnyone" }, { "fieldname": "column_break_9", @@ -149,7 +150,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2022-05-09 09:55:24.519269", + "modified": "2022-08-22 10:02:59.988499", "modified_by": "Administrator", "module": "LMS", "name": "LMS Settings", diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 88f617c1..c8c8e28a 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -400,3 +400,10 @@ def first_lesson_exists(course): def redirect_to_courses_list(): frappe.local.flags.redirect_location = "/courses" raise frappe.Redirect + + +def has_course_instructor_role(): + return frappe.db.get_value("Has Role", { + "parent": frappe.session.user, + "role": "Course Instructor" + }, "name") diff --git a/lms/patches.txt b/lms/patches.txt index b8c513c6..8014a7a6 100644 --- a/lms/patches.txt +++ b/lms/patches.txt @@ -30,3 +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 +lms.patches.v0_0.create_course_instructor_role diff --git a/lms/patches/v0_0/create_course_instructor_role.py b/lms/patches/v0_0/create_course_instructor_role.py new file mode 100644 index 00000000..25f5bd91 --- /dev/null +++ b/lms/patches/v0_0/create_course_instructor_role.py @@ -0,0 +1,10 @@ +import frappe + +def execute(): + if not frappe.db.exists("Role", "Course Instructor"): + role = frappe.get_doc({ + "doctype": "Role", + "role_name": "Course Instructor", + "home_page": "/dashboard", + }) + role.save(ignore_permissions=True) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index c0c223a4..4060b8d6 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -944,7 +944,7 @@ pre { float: right; width: 80%; display: flex; - justify-content: end; + justify-content: flex-end; align-items: center; } diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index c44dcb9e..abfd3fcb 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -109,7 +109,7 @@ const add_chapter = (e) => { return; } - let next_index = $("[data-index]").last().data("index") || 1; + let next_index = $("[data-index]").last().data("index") + 1 || 1; let add_after = $(`.chapter-parent:last`).length ? $(`.chapter-parent:last`) : $("#outline-heading"); console.log(add_after) $(`
diff --git a/lms/templates/courses_created.html b/lms/templates/courses_created.html index 5b18e173..a219ebe1 100644 --- a/lms/templates/courses_created.html +++ b/lms/templates/courses_created.html @@ -1,23 +1,20 @@ {% set courses = get_authored_courses(frappe.session.user, only_published=False) %} + {% if courses | length %}
- {% for course in courses %} - {{ widgets.CourseCard(course=course) }} - {% endfor %} + {% for course in courses %} + {{ widgets.CourseCard(course=course) }} + {% endfor %}
+ {% else %}
-
- -
-
-
{{ _("No courses created") }}
-
{{ _("Help others learn something new.") }}
-
-
- - {{ _("Create a Course") }} - -
+
+ +
+
+
{{ _("No courses created") }}
+
{{ _("Help others learn something new.") }}
+
{% endif %} diff --git a/lms/templates/quiz.html b/lms/templates/quiz.html index a2e885e6..83b67185 100644 --- a/lms/templates/quiz.html +++ b/lms/templates/quiz.html @@ -5,7 +5,8 @@
{{ _("Your latest score is {0}.").format(last_attempt_score) }}
{% else %} -
{{ quiz.title }}
+
{{ quiz.title }}
diff --git a/lms/templates/search_course/search_course.html b/lms/templates/search_course/search_course.html index b9fb5900..43dd100d 100644 --- a/lms/templates/search_course/search_course.html +++ b/lms/templates/search_course/search_course.html @@ -1,19 +1,22 @@ -{% set show_search = frappe.db.get_single_value("LMS Settings", "show_search") %} {% set search_placeholder = frappe.db.get_single_value("LMS Settings", "search_placeholder") %} +{% set portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation") %} -{% if show_search %} - +
+ + {% if portal_course_creation == "Anyone" or has_course_instructor_role() %} + {{ _("Create a Course") }} + {% endif %} +
- × -
- -
-
-
{{ _("No results found") }}
-
{{ _("Try some other keyword or explore our list of courses.") }}
-
+ × +
+ +
+
+
{{ _("No results found") }}
+
{{ _("Try some other keyword or explore our list of courses.") }}
+
-{% endif %} diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index fdb5d9a7..b7de690b 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -185,7 +185,9 @@
+ {% if lesson.name %} + {% endif %} {{ _("Create a Quiz") }}
diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index a6227e2f..1fb8facf 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -1,6 +1,6 @@ frappe.ready(() => { - localStorage.removeItem($("#quiz-title").text()); + localStorage.removeItem($("#quiz-title").data("name")); fetch_assignments(); @@ -200,8 +200,9 @@ const move_to_next_lesson = (status, e) => { const quiz_summary = (e=undefined) => { e && e.preventDefault(); - let quiz_name = $("#quiz-title").text(); + let quiz_name = $("#quiz-title").data("name"); let total_questions = $(".question").length; + frappe.call({ method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary", args: { @@ -230,7 +231,6 @@ const check_answer = (e=undefined) => { e && e.preventDefault(); clearInterval(self.timer); $(".timer").addClass("hide"); - let quiz_name = $("#quiz-title").text(); let total_questions = $(".question").length; let current_index = $(".active-question").attr("data-qt-index"); @@ -249,7 +249,7 @@ const check_answer = (e=undefined) => { $("#next").removeClass("hide"); } let [answer, is_correct] = parse_options(); - add_to_local_storage(quiz_name, current_index, answer, is_correct); + add_to_local_storage(current_index, answer, is_correct); }; @@ -285,13 +285,16 @@ const add_icon = (element, icon) => { }; -const add_to_local_storage = (quiz_name, current_index, answer, is_correct) => { +const add_to_local_storage = (current_index, answer, is_correct) => { + let quiz_name = $("#quiz-title").data("name") let quiz_stored = JSON.parse(localStorage.getItem(quiz_name)); + let quiz_obj = { "question_index": current_index, "answer": answer.join(), "is_correct": is_correct } + quiz_stored ? quiz_stored.push(quiz_obj) : quiz_stored = [quiz_obj] localStorage.setItem(quiz_name, JSON.stringify(quiz_stored)) }; diff --git a/lms/www/batch/learn.py b/lms/www/batch/learn.py index 4e705d17..b3f59b76 100644 --- a/lms/www/batch/learn.py +++ b/lms/www/batch/learn.py @@ -24,16 +24,17 @@ def get_context(context): context.lesson = get_current_lesson_details(lesson_number, context) if not context.lesson: - context.lessom = frappe._dict() + context.lesson = frappe._dict() if frappe.form_dict.get("edit"): if not is_instructor(context.course.name): redirect_to_courses_list() context.lesson.edit_mode = True + else: + neighbours = get_neighbours(lesson_number, context.lessons) + context.next_url = get_url(neighbours["next"], context.course) + context.prev_url = get_url(neighbours["prev"], context.course) - neighbours = get_neighbours(lesson_number, context.lessons) - context.next_url = get_url(neighbours["next"], context.course) - context.prev_url = get_url(neighbours["prev"], context.course) meta_info = context.lesson.title + " - " + context.course.title if context.lesson.title else "New Lesson" context.metatags = { "title": meta_info, @@ -52,8 +53,13 @@ def get_context(context): def get_current_lesson_details(lesson_number, context): details_list = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons)) + if not len(details_list): - redirect_to_lesson(context.course) + if frappe.form_dict.get("edit"): + return None + else: + redirect_to_lesson(context.course) + lesson_info = details_list[0] lesson_info.body = lesson_info.body.replace("\"", "'") return lesson_info diff --git a/lms/www/courses/course.html b/lms/www/courses/course.html index 1e5f9e2a..252eb8ba 100644 --- a/lms/www/courses/course.html +++ b/lms/www/courses/course.html @@ -188,10 +188,13 @@ data-placeholder="Description">{% if course.description %}{{ frappe.utils.md_to_ {% if course.edit_mode %}
+ {{ _("Save Course Details") }} + + {% if course.name %} {{ _("Back to Course") }} + {% endif %}
{% endif %} {% endmacro %} diff --git a/lms/www/courses/index.html b/lms/www/courses/index.html index 03c49fec..10dc5dd7 100644 --- a/lms/www/courses/index.html +++ b/lms/www/courses/index.html @@ -15,11 +15,7 @@
{% else %} - -
- {% include "lms/templates/search_course/search_course.html" %} - {{ _("Create a Course") }} -
+ {% include "lms/templates/search_course/search_course.html" %}
{% set courses = live_courses %} diff --git a/lms/www/dashboard/index.html b/lms/www/dashboard/index.html index bd37483e..1f6e5855 100644 --- a/lms/www/dashboard/index.html +++ b/lms/www/dashboard/index.html @@ -2,48 +2,48 @@ {% block title %}{{ _("Dashboard")}} {% endblock %} + {% 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() %} +
-
- {% if portal_course_creation %} - - - {{ _("New Course")}} - - {% endif %} - -
-
-
- {% include "lms/lms/web_template/courses_enrolled/courses_enrolled.html" %} -
- {% if portal_course_creation %} -
- {% include "lms/templates/courses_created.html" %} -
- {% endif %} + {% endif %} + + + +
+ +
+
+ {% include "lms/lms/web_template/courses_enrolled/courses_enrolled.html" %} +
+ {% if show_creators_section %} +
+ {% include "lms/templates/courses_created.html" %} +
+ {% endif %} +
+
-
+ - {% endblock %}