Merge pull request #372 from pateljannat/course-moderator
This commit is contained in:
@@ -192,7 +192,9 @@ jinja = {
|
|||||||
"lms.lms.utils.get_popular_courses",
|
"lms.lms.utils.get_popular_courses",
|
||||||
"lms.lms.utils.format_amount",
|
"lms.lms.utils.format_amount",
|
||||||
"lms.lms.utils.first_lesson_exists",
|
"lms.lms.utils.first_lesson_exists",
|
||||||
"lms.lms.utils.has_course_instructor_role"
|
"lms.lms.utils.get_courses_under_review",
|
||||||
|
"lms.lms.utils.has_course_instructor_role",
|
||||||
|
"lms.lms.utils.has_course_moderator_role"
|
||||||
],
|
],
|
||||||
"filters": []
|
"filters": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ def submit_for_review(course):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@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:
|
if course:
|
||||||
doc = frappe.get_doc("LMS Course", course)
|
doc = frappe.get_doc("LMS Course", course)
|
||||||
else:
|
else:
|
||||||
@@ -208,7 +208,9 @@ def save_course(tags, title, short_introduction, video_link, description, course
|
|||||||
"video_link": video_link,
|
"video_link": video_link,
|
||||||
"image": image,
|
"image": image,
|
||||||
"description": description,
|
"description": description,
|
||||||
"tags": tags
|
"tags": tags,
|
||||||
|
"published": published,
|
||||||
|
"upcoming": upcoming
|
||||||
})
|
})
|
||||||
doc.save(ignore_permissions=True)
|
doc.save(ignore_permissions=True)
|
||||||
return doc.name
|
return doc.name
|
||||||
|
|||||||
@@ -435,8 +435,23 @@ def redirect_to_courses_list():
|
|||||||
raise frappe.Redirect
|
raise frappe.Redirect
|
||||||
|
|
||||||
|
|
||||||
def has_course_instructor_role():
|
def has_course_instructor_role(member=None):
|
||||||
return frappe.db.get_value("Has Role", {
|
return frappe.db.get_value("Has Role", {
|
||||||
"parent": frappe.session.user,
|
"parent": member or frappe.session.user,
|
||||||
"role": "Course Instructor"
|
"role": "Course Instructor"
|
||||||
}, "name")
|
}, "name")
|
||||||
|
|
||||||
|
|
||||||
|
def has_course_moderator_role(member=None):
|
||||||
|
return frappe.db.get_value("Has Role", {
|
||||||
|
"parent": member or frappe.session.user,
|
||||||
|
"role": "Course Moderator"
|
||||||
|
}, "name")
|
||||||
|
|
||||||
|
|
||||||
|
def get_courses_under_review():
|
||||||
|
return frappe.get_all("LMS Course", {
|
||||||
|
"status": "Under Review"
|
||||||
|
}, ["name", "upcoming", "title", "image", "enable_certification", "status", "published"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
{% set active = membership.current_lesson == lesson.name %}
|
{% set active = membership.current_lesson == lesson.name %}
|
||||||
<div class="lesson-info {% if active and not course.edit_mode %} active-lesson {% endif %}">
|
<div class="lesson-info {% if active and not course.edit_mode %} active-lesson {% endif %}">
|
||||||
|
|
||||||
{% 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() %}
|
||||||
<a class="lesson-links" data-course="{{ course.name }}"
|
<a class="lesson-links" data-course="{{ course.name }}"
|
||||||
{% if is_instructor and not lesson.include_in_preview %}
|
{% if is_instructor and not lesson.include_in_preview %}
|
||||||
title="{{ _('This lesson is not available for preview. As you are the Instructor of the course only you can see it.') }}"
|
title="{{ _('This lesson is not available for preview. As you are the Instructor of the course only you can see it.') }}"
|
||||||
@@ -185,3 +185,4 @@ const show_no_preview_dialog = (e) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
""".format(or_filters = or_filters, start=start, page_length=page_length), as_dict=1)
|
||||||
|
|
||||||
return users
|
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
|
||||||
|
|||||||
@@ -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_old_module_docs #08-07-2022
|
||||||
lms.patches.v0_0.delete_course_web_forms #21-08-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_instructor_role #29-08-2022
|
||||||
|
lms.patches.v0_0.create_course_moderator_role
|
||||||
|
|||||||
11
lms/patches/v0_0/create_course_moderator_role.py
Normal file
11
lms/patches/v0_0/create_course_moderator_role.py
Normal file
@@ -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)
|
||||||
@@ -74,7 +74,6 @@ input[type=checkbox] {
|
|||||||
|
|
||||||
.common-page-style {
|
.common-page-style {
|
||||||
padding: 2rem 0 5rem;
|
padding: 2rem 0 5rem;
|
||||||
min-height: 60vh;
|
|
||||||
padding-top: 3rem;
|
padding-top: 3rem;
|
||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
}
|
}
|
||||||
@@ -1687,3 +1686,8 @@ li {
|
|||||||
.review-link {
|
.review-link {
|
||||||
float: right
|
float: right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.role {
|
||||||
|
margin-bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|||||||
19
lms/templates/courses_under_review.html
Normal file
19
lms/templates/courses_under_review.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% set courses = get_courses_under_review() %}
|
||||||
|
|
||||||
|
{% if courses | length %}
|
||||||
|
<div class="cards-parent">
|
||||||
|
{% for course in courses %}
|
||||||
|
{{ widgets.CourseCard(course=course) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="empty-state">
|
||||||
|
<div>
|
||||||
|
<img class="icon icon-xl" src="/assets/lms/icons/comment.svg">
|
||||||
|
</div>
|
||||||
|
<div class="empty-state-text">
|
||||||
|
<div class="empty-state-heading">{{ _("No courses under review") }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
{% macro LessonContent(lesson) %}
|
{% macro LessonContent(lesson) %}
|
||||||
{% set instructors = get_instructors(course.name) %}
|
{% set instructors = get_instructors(course.name) %}
|
||||||
{% set is_instructor = is_instructor(course.name) %}
|
{% set is_instructor = is_instructor(course.name) %}
|
||||||
|
|
||||||
<div class="common-card-style lesson-content">
|
<div class="common-card-style lesson-content">
|
||||||
<div class="lesson-title">
|
<div class="lesson-title">
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@
|
|||||||
<span class="indicator-pill green {{ hide if get_progress(course.name, lesson.name) != 'Complete' else ''}}">{{ _("COMPLETED") }}</span>
|
<span class="indicator-pill green {{ hide if get_progress(course.name, lesson.name) != 'Complete' else ''}}">{{ _("COMPLETED") }}</span>
|
||||||
|
|
||||||
<!-- Edit Button -->
|
<!-- Edit Button -->
|
||||||
{% if is_instructor and not lesson.edit_mode %}
|
{% if (is_instructor or has_course_moderator_role()) and not lesson.edit_mode %}
|
||||||
<button class="button is-default button-links ml-auto btn-edit"> {{ _("Edit") }} </button>
|
<button class="button is-default button-links ml-auto btn-edit"> {{ _("Edit") }} </button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
|
|
||||||
<!-- Lesson Content -->
|
<!-- Lesson Content -->
|
||||||
<div class="markdown-source lesson-content-card {% if lesson.edit_mode %} mb-0 mt-2 {% endif %} ">
|
<div class="markdown-source lesson-content-card {% if lesson.edit_mode %} mb-0 mt-2 {% endif %} ">
|
||||||
{% 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 %}
|
{% if is_instructor and not lesson.include_in_preview and not lesson.edit_mode %}
|
||||||
<div class="small alert alert-secondary alert-dismissible mb-4">
|
<div class="small alert alert-secondary alert-dismissible mb-4">
|
||||||
@@ -190,9 +191,9 @@
|
|||||||
<div class="medium mb-4" contenteditable="true" data-placeholder="{{ _('Quiz ID') }}"
|
<div class="medium mb-4" contenteditable="true" data-placeholder="{{ _('Quiz ID') }}"
|
||||||
id="quiz-id">{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}</div>
|
id="quiz-id">{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}</div>
|
||||||
|
|
||||||
<label class="preview">
|
<label class="preview" for="preview">
|
||||||
<input {% if lesson.include_in_preview %} checked {% endif %} type="checkbox"
|
<input {% if lesson.include_in_preview %} checked {% endif %} type="checkbox" id="preview">
|
||||||
id="preview"> {{ _("Show preview of this lesson to Guest users.") }}
|
{{ _("Show preview of this lesson to Guest users.") }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
|
|||||||
@@ -542,10 +542,6 @@ const build_attachment_table = (file_doc) => {
|
|||||||
|
|
||||||
|
|
||||||
const make_editor = () => {
|
const make_editor = () => {
|
||||||
let comment = `<!--
|
|
||||||
{{ YouTubeVideo('Video Id') }}
|
|
||||||
{{ Quiz('Quiz Id') }}
|
|
||||||
-->`
|
|
||||||
|
|
||||||
this.code_field_group = new frappe.ui.FieldGroup({
|
this.code_field_group = new frappe.ui.FieldGroup({
|
||||||
fields: [
|
fields: [
|
||||||
@@ -556,7 +552,7 @@ const make_editor = () => {
|
|||||||
wrap: true,
|
wrap: true,
|
||||||
max_lines: Infinity,
|
max_lines: Infinity,
|
||||||
min_lines: 20,
|
min_lines: 20,
|
||||||
default: $("#body").data("body") || comment,
|
default: $("#body").data("body"),
|
||||||
depends_on: 'eval:doc.type=="Markdown"',
|
depends_on: 'eval:doc.type=="Markdown"',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from lms.www.utils import get_common_context, redirect_to_lesson
|
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
|
from frappe.utils import cstr, flt
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
@@ -23,11 +23,14 @@ def get_context(context):
|
|||||||
redirect_to_lesson(context.course, index_)
|
redirect_to_lesson(context.course, index_)
|
||||||
|
|
||||||
context.lesson = get_current_lesson_details(lesson_number, context)
|
context.lesson = get_current_lesson_details(lesson_number, context)
|
||||||
|
instructor = is_instructor(context.course.name)
|
||||||
|
context.show_lesson = context.membership or context.lesson.include_in_preview or instructor or has_course_moderator_role()
|
||||||
|
|
||||||
if not context.lesson:
|
if not context.lesson:
|
||||||
context.lesson = frappe._dict()
|
context.lesson = frappe._dict()
|
||||||
|
|
||||||
if frappe.form_dict.get("edit"):
|
if frappe.form_dict.get("edit"):
|
||||||
if not is_instructor(context.course.name):
|
if not instructor and not has_course_moderator_role():
|
||||||
redirect_to_courses_list()
|
redirect_to_courses_list()
|
||||||
context.lesson.edit_mode = True
|
context.lesson.edit_mode = True
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -55,8 +55,10 @@
|
|||||||
<div contenteditable="true" data-placeholder="{{ _('Explain the option') }}"
|
<div contenteditable="true" data-placeholder="{{ _('Explain the option') }}"
|
||||||
class="option-input">{% if explanation %}{{ explanation }}{% endif %}</div>
|
class="option-input">{% if explanation %}{{ explanation }}{% endif %}</div>
|
||||||
<div class="option-checkbox">
|
<div class="option-checkbox">
|
||||||
|
<label class="mb-0">
|
||||||
<input type="checkbox" {% if question['is_correct_' + num] %} checked {% endif %}>
|
<input type="checkbox" {% if question['is_correct_' + num] %} checked {% endif %}>
|
||||||
<label class="mb-0"> {{ _("Is Correct") }} </label>
|
{{ _("Is Correct") }}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="course-body-container">
|
<div class="course-body-container">
|
||||||
{{ CourseHeaderOverlay(course) }}
|
{{ CourseHeaderOverlay(course) }}
|
||||||
|
{{ CourseSettings(course) }}
|
||||||
{{ Description(course) }}
|
{{ Description(course) }}
|
||||||
{{ Save(course) }}
|
{{ Save(course) }}
|
||||||
{{ widgets.CourseOutline(course=course, membership=membership, is_user_interested=is_user_interested) }}
|
{{ widgets.CourseOutline(course=course, membership=membership, is_user_interested=is_user_interested) }}
|
||||||
@@ -210,6 +211,25 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Course Settings -->
|
||||||
|
{% macro CourseSettings(course) %}
|
||||||
|
|
||||||
|
{% if course.edit_mode and has_course_moderator_role() %}
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="published" class="mb-0">
|
||||||
|
<input type="checkbox" id="published" {% if course.published %} checked {% endif %}>
|
||||||
|
{{ _("Published") }}
|
||||||
|
</label>
|
||||||
|
<label for="upcoming" class="mb-0 ml-20">
|
||||||
|
<input type="checkbox" id="upcoming" {% if course.upcoming %} checked {% endif %}>
|
||||||
|
{{ _("Upcoming") }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
<!-- Save -->
|
<!-- Save -->
|
||||||
{% macro Save(course) %}
|
{% macro Save(course) %}
|
||||||
{% if course.edit_mode %}
|
{% if course.edit_mode %}
|
||||||
@@ -270,7 +290,7 @@
|
|||||||
membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %}
|
membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %}
|
||||||
|
|
||||||
{% if show_start_learing_cta %}
|
{% if show_start_learing_cta %}
|
||||||
<div class="btn btn-primary wide-button join-batch" data-course="{{ course.name | urlencode }}">
|
<div class="btn btn-primary wide-button join-batch mb-2" data-course="{{ course.name | urlencode }}">
|
||||||
{{ _("Start Learning") }}
|
{{ _("Start Learning") }}
|
||||||
<img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
<img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
||||||
</div>
|
</div>
|
||||||
@@ -286,7 +306,7 @@
|
|||||||
{{ _("Checkout Course") }} <img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
{{ _("Checkout Course") }} <img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% elif course.upcoming and not is_user_interested %}
|
{% elif course.upcoming and not is_user_interested and not is_instructor %}
|
||||||
<div class="btn btn-secondary wide-button notify-me" data-course="{{course.name | urlencode}}">
|
<div class="btn btn-secondary wide-button notify-me" data-course="{{course.name | urlencode}}">
|
||||||
{{ _("Notify me when available") }}
|
{{ _("Notify me when available") }}
|
||||||
</div>
|
</div>
|
||||||
@@ -323,7 +343,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if is_instructor(course.name) %}
|
{% if is_instructor(course.name) or has_course_moderator_role() %}
|
||||||
<a class="btn btn-secondary wide-button" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a>
|
<a class="btn btn-secondary wide-button" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
@@ -341,9 +361,9 @@
|
|||||||
frappe.utils.format_time(certificate_request.start_time, "short")) }} </p>
|
frappe.utils.format_time(certificate_request.start_time, "short")) }} </p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if course.status == "Under Review" %}
|
{% if course.status == "Under Review" and is_instructor(course.name) %}
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
{{ _("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.") }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ const submit_for_review = (e) => {
|
|||||||
}, 3);
|
}, 3);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 3000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -339,7 +339,9 @@ const save_course = (e) => {
|
|||||||
"video_link": $("#video-link").text(),
|
"video_link": $("#video-link").text(),
|
||||||
"image": $("#image").attr("href"),
|
"image": $("#image").attr("href"),
|
||||||
"description": $("#description").text(),
|
"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) => {
|
callback: (data) => {
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from lms.lms.doctype.lms_settings.lms_settings import check_profile_restriction
|
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):
|
def get_context(context):
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
@@ -28,7 +28,7 @@ def set_course_context(context, course_name):
|
|||||||
as_dict=True)
|
as_dict=True)
|
||||||
|
|
||||||
if frappe.form_dict.get("edit"):
|
if frappe.form_dict.get("edit"):
|
||||||
if not is_instructor(course.name):
|
if not is_instructor(course.name) and not has_course_moderator_role():
|
||||||
redirect_to_courses_list()
|
redirect_to_courses_list()
|
||||||
course.edit_mode = True
|
course.edit_mode = True
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,23 @@
|
|||||||
|
|
||||||
<ul class="nav" id="courses-tab">
|
<ul class="nav" id="courses-tab">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" data-toggle="tab" href="#courses-enrolled"> {{ _("Courses Enrolled") }} </a>
|
<a class="nav-link active" data-toggle="tab" href="#courses-enrolled">
|
||||||
|
{{ _("Courses Enrolled") }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if show_creators_section %}
|
{% if show_creators_section %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" data-toggle="tab" href="#courses-created">{{ _("Courses Created") }}
|
<a class="nav-link" data-toggle="tab" href="#courses-created">
|
||||||
|
{{ _("Courses Created") }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if show_review_section %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-toggle="tab" href="#courses-under-review">
|
||||||
|
{{ _("Courses Under Review") }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -39,8 +50,14 @@
|
|||||||
{% include "lms/templates/courses_created.html" %}
|
{% include "lms/templates/courses_created.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{% if show_review_section %}
|
||||||
|
<div class="tab-pane fade" id="courses-under-review" role="tabpanel" aria-labelledby="courses-under-review">
|
||||||
|
{% include "lms/templates/courses_under_review.html" %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import frappe
|
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):
|
def get_context(context):
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation")
|
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_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role()
|
||||||
|
context.show_review_section = has_course_moderator_role()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<div class="profile-page-body">
|
<div class="profile-page-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{% set read_only = member.name != frappe.session.user %}
|
{% set read_only = member.name != frappe.session.user %}
|
||||||
|
{{ RoleSettings(member) }}
|
||||||
{{ About(member) }}
|
{{ About(member) }}
|
||||||
{{ EducationDetails(member) }}
|
{{ EducationDetails(member) }}
|
||||||
{{ WorkDetails(member) }}
|
{{ WorkDetails(member) }}
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
|
|
||||||
<div class="profile-info">
|
<div class="profile-info">
|
||||||
<div class="profile-name-section">
|
<div class="profile-name-section">
|
||||||
<div class="profile-name"> {{ member.full_name }} </div>
|
<div class="profile-name" data-name="{{ member.name }}"> {{ member.full_name }} </div>
|
||||||
|
|
||||||
{% if get_authored_courses(member.name) | length %}
|
{% if get_authored_courses(member.name) | length %}
|
||||||
<div class="creator-badge"> {{ _("Creator") }} </div>
|
<div class="creator-badge"> {{ _("Creator") }} </div>
|
||||||
@@ -155,10 +156,34 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Role Settings -->
|
||||||
|
{% macro RoleSettings(member) %}
|
||||||
|
{% if has_course_moderator_role() %}
|
||||||
|
<div class="">
|
||||||
|
<div class="common-card-style profile-card">
|
||||||
|
<div class="course-home-headings"> {{ _("Role Settings") }} </div>
|
||||||
|
<div>
|
||||||
|
<label class="role">
|
||||||
|
<input type="checkbox" id="instructor" data-role="Course Instructor"
|
||||||
|
{% if has_course_instructor_role(member.name) %} checked {% endif %}>
|
||||||
|
{{ _("Course Instructor") }}
|
||||||
|
</label>
|
||||||
|
<label class="role ml-20">
|
||||||
|
<input type="checkbox" id="moderator" data-role="Course Moderator"
|
||||||
|
{% if has_course_moderator_role(member.name) %} checked {% endif %}>
|
||||||
|
{{ _("Course Moderator") }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
<!-- About Section -->
|
<!-- About Section -->
|
||||||
{% macro About(member) %}
|
{% macro About(member) %}
|
||||||
{% if member.bio %}
|
{% if member.bio %}
|
||||||
<div class="">
|
<div class="education-details">
|
||||||
<div class="common-card-style profile-card">
|
<div class="common-card-style profile-card">
|
||||||
<div class="course-home-headings"> {{ _("About") }} </div>
|
<div class="course-home-headings"> {{ _("About") }} </div>
|
||||||
<div class="description">{{ member.bio }}</div>
|
<div class="description">{{ member.bio }}</div>
|
||||||
@@ -386,21 +411,3 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
{% block script %}
|
|
||||||
<script>
|
|
||||||
frappe.ready(() => {
|
|
||||||
if ("{{ member.name }}" == frappe.session.user) {
|
|
||||||
setTimeout(() => {
|
|
||||||
var link_array = $('.nav-link').filter((i, elem) => $(elem).text().trim() === "My Profile");
|
|
||||||
link_array.length && $(link_array[0]).addClass("active");
|
|
||||||
}, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($(".profile-column-one").children().length == 0) {
|
|
||||||
$(".profile-column-one").hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
42
lms/www/profiles/profile.js
Normal file
42
lms/www/profiles/profile.js
Normal file
@@ -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",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from lms.page_renderers import get_profile_url_prefix
|
from lms.page_renderers import get_profile_url_prefix
|
||||||
from urllib.parse import urlencode
|
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
@@ -12,13 +12,16 @@ def get_context(context):
|
|||||||
if username:
|
if username:
|
||||||
frappe.local.flags.redirect_location = get_profile_url_prefix() + username
|
frappe.local.flags.redirect_location = get_profile_url_prefix() + username
|
||||||
raise frappe.Redirect
|
raise frappe.Redirect
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context.member = frappe.get_doc("User", {"username": username})
|
context.member = frappe.get_doc("User", {"username": username})
|
||||||
except:
|
except:
|
||||||
context.template = "www/404.html"
|
context.template = "www/404.html"
|
||||||
return
|
return
|
||||||
|
|
||||||
context.profile_tabs = get_profile_tabs(context.member)
|
context.profile_tabs = get_profile_tabs(context.member)
|
||||||
|
|
||||||
|
|
||||||
def get_profile_tabs(user):
|
def get_profile_tabs(user):
|
||||||
"""Returns the enabled ProfileTab objects.
|
"""Returns the enabled ProfileTab objects.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user