feat: publish batches
This commit is contained in:
@@ -66,13 +66,8 @@
|
||||
{% macro CreateLesson() %}
|
||||
<article class="field-parent">
|
||||
<div class="field-group">
|
||||
<div>
|
||||
<div class="field-label">
|
||||
{{ _("Title") }}
|
||||
</div>
|
||||
<div class="field-description">
|
||||
{{ _("Something Short and Concise") }}
|
||||
</div>
|
||||
<div class="field-label">
|
||||
{{ _("Title") }}
|
||||
</div>
|
||||
<div class="">
|
||||
<input id="lesson-title" type="text" class="field-input" data-index="{{ lesson_index }}" data-chapter="{{ chapter }}" data-course="{{ course.name }}" {% if lesson.name %} data-lesson="{{ lesson.name }}" value="{{ lesson.title }}" {% endif %}>
|
||||
@@ -86,6 +81,19 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="field-group">
|
||||
<div class="field-label">
|
||||
{{ _("Instructor Notes") }}
|
||||
</div>
|
||||
<div class="field-description">
|
||||
{{ _("These notes will only be visible to the Course Creator, Course Evaluaor and Moderator.") }}
|
||||
</div>
|
||||
<div id="instructor-notes"></div>
|
||||
{% if lesson.instructor_notes %}
|
||||
<div id="current-instructor-notes" class="hide">{{ lesson.instructor_notes }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="field-group">
|
||||
<div>
|
||||
<div class="field-label">
|
||||
@@ -117,9 +125,9 @@
|
||||
};
|
||||
</script>
|
||||
{% endif %}
|
||||
{{ include_script('controls.bundle.js') }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph@latest"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed@latest"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
frappe.ready(() => {
|
||||
frappe.telemetry.capture("on_lesson_creation_page", "lms");
|
||||
let self = this;
|
||||
this.quiz_in_lesson = [];
|
||||
|
||||
frappe.telemetry.capture("on_lesson_creation_page", "lms");
|
||||
|
||||
if ($("#instructor-notes").length) {
|
||||
frappe.require("controls.bundle.js", () => {
|
||||
make_instructor_notes_component();
|
||||
});
|
||||
}
|
||||
|
||||
if ($("#current-lesson-content").length) {
|
||||
parse_string_to_lesson();
|
||||
}
|
||||
@@ -18,6 +26,27 @@ const setup_editor = () => {
|
||||
self.editor = new EditorJS({
|
||||
holder: "lesson-content",
|
||||
tools: {
|
||||
embed: {
|
||||
class: Embed,
|
||||
config: {
|
||||
services: {
|
||||
youtube: true,
|
||||
vimeo: true,
|
||||
codepen: true,
|
||||
slides: {
|
||||
regex: /https:\/\/docs\.google\.com\/presentation\/d\/e\/([A-Za-z0-9_-]+)\/pub/,
|
||||
embedUrl:
|
||||
"https://docs.google.com/presentation/d/e/<%= remote_id %>/embed",
|
||||
html: "<iframe width='100%' height='300' frameborder='0' allowfullscreen='true'></iframe>",
|
||||
},
|
||||
pdf: {
|
||||
regex: /(https?:\/\/.*\.pdf)/,
|
||||
embedUrl: "<%= remote_id %>",
|
||||
html: "<iframe width='100%' height='600px' frameborder='0'></iframe>",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: ["bold", "italic", "link"],
|
||||
@@ -76,6 +105,15 @@ const parse_string_to_lesson = () => {
|
||||
file_url: video,
|
||||
},
|
||||
});
|
||||
} else if (block.includes("{{ Embed")) {
|
||||
let embed = block.match(/'([^']+)'/)[1];
|
||||
lesson_blocks.push({
|
||||
type: "embed",
|
||||
data: {
|
||||
service: embed.split("|||")[0],
|
||||
embed: embed.split("|||")[1],
|
||||
},
|
||||
});
|
||||
} else if (block.includes("![]")) {
|
||||
let image = block.match(/\((.*?)\)/)[1];
|
||||
lesson_blocks.push({
|
||||
@@ -131,6 +169,15 @@ const parse_lesson_to_string = (data) => {
|
||||
"#".repeat(block.data.level) + ` ${block.data.text}\n`;
|
||||
} else if (block.type == "paragraph") {
|
||||
lesson_content += `${block.data.text}\n`;
|
||||
} else if (block.type == "embed") {
|
||||
if (block.data.service == "pdf") {
|
||||
if (!block.data.embed.startsWith(window.location.origin)) {
|
||||
frappe.throw(__("Invalid PDF URL"));
|
||||
}
|
||||
}
|
||||
lesson_content += `{{ Embed("${
|
||||
block.data.service
|
||||
}|||${block.data.embed.replace(/&/g, "&")}") }}\n`;
|
||||
}
|
||||
});
|
||||
save(lesson_content);
|
||||
@@ -149,6 +196,8 @@ const save = (lesson_content) => {
|
||||
preview: $("#preview").prop("checked") ? 1 : 0,
|
||||
idx: $("#lesson-title").data("index"),
|
||||
lesson: lesson ? lesson : "",
|
||||
instructor_notes:
|
||||
this.instructor_notes.get_values().instructor_notes,
|
||||
},
|
||||
callback: (data) => {
|
||||
frappe.show_alert({
|
||||
@@ -466,3 +515,20 @@ class Upload {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const make_instructor_notes_component = () => {
|
||||
this.instructor_notes = new frappe.ui.FieldGroup({
|
||||
fields: [
|
||||
{
|
||||
fieldname: "instructor_notes",
|
||||
fieldtype: "Text Editor",
|
||||
default: $("#current-instructor-notes").html(),
|
||||
},
|
||||
],
|
||||
body: $("#instructor-notes").get(0),
|
||||
});
|
||||
this.instructor_notes.make();
|
||||
$("#instructor-notes .form-section:last").removeClass("empty-section");
|
||||
$("#instructor-notes .frappe-control").removeClass("hide-control");
|
||||
$("#instructor-notes .form-column").addClass("p-0");
|
||||
};
|
||||
|
||||
@@ -149,17 +149,28 @@
|
||||
{% if show_lesson %}
|
||||
|
||||
{% if is_instructor and not lesson.include_in_preview %}
|
||||
<div class="medium alert alert-info alert-dismissible mb-4">
|
||||
<div class="alert alert-info alert-dismissible mb-4">
|
||||
{{ _("This lesson is not available for preview. As you are the Instructor of the course only you can see it.") }}
|
||||
<a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if lesson.instructor_notes and (is_moderator or instructor or is_evaluator) %}
|
||||
<div class="alert alert-info mb-4">
|
||||
<div class="bold-heading mb-2">
|
||||
{{ _("Instructor Notes") }}
|
||||
</div>
|
||||
<div>
|
||||
{{ lesson.instructor_notes }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ render_html(lesson) }}
|
||||
|
||||
{% else %}
|
||||
{% set course_link = "<a class='enroll-in-course' data-course=" + course.name | urlencode + " href=''>" + _('here') + "</a>" %}
|
||||
<div class="alert alert-info medium mb-0">
|
||||
<div class="alert alert-info mb-0">
|
||||
{{ _("There is no preview available for this lesson.
|
||||
Please join the course to access it.
|
||||
Click {0} to enroll.").format(course_link) }}
|
||||
|
||||
@@ -2,7 +2,12 @@ import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cstr, flt
|
||||
|
||||
from lms.lms.utils import get_lesson_url, has_course_moderator_role, is_instructor
|
||||
from lms.lms.utils import (
|
||||
get_lesson_url,
|
||||
has_course_moderator_role,
|
||||
is_instructor,
|
||||
has_course_evaluator_role,
|
||||
)
|
||||
from lms.www.utils import (
|
||||
get_common_context,
|
||||
redirect_to_lesson,
|
||||
@@ -37,20 +42,23 @@ def get_context(context):
|
||||
redirect_to_lesson(context.course, index_)
|
||||
|
||||
context.lesson = get_current_lesson_details(lesson_number, context)
|
||||
instructor = is_instructor(context.course.name)
|
||||
context.instructor = is_instructor(context.course.name)
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
context.is_evaluator = has_course_evaluator_role()
|
||||
|
||||
context.show_lesson = (
|
||||
context.membership
|
||||
or (context.lesson and context.lesson.include_in_preview)
|
||||
or instructor
|
||||
or has_course_moderator_role()
|
||||
or context.instructor
|
||||
or context.is_moderator
|
||||
or context.is_evaluator
|
||||
)
|
||||
|
||||
if not context.lesson:
|
||||
context.lesson = frappe._dict()
|
||||
|
||||
if frappe.form_dict.get("edit"):
|
||||
if not instructor and not has_course_moderator_role():
|
||||
if not context.instructor and not context.is_moderator:
|
||||
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
||||
context.lesson.edit_mode = True
|
||||
else:
|
||||
|
||||
@@ -40,6 +40,7 @@ def get_context(context):
|
||||
"amount",
|
||||
"currency",
|
||||
"batch_details",
|
||||
"published",
|
||||
],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from lms.lms.utils import has_course_moderator_role, has_course_evaluator_role
|
||||
from lms.www.utils import is_student
|
||||
|
||||
@@ -23,10 +24,17 @@ def get_context(context):
|
||||
"start_time",
|
||||
"end_time",
|
||||
"seat_count",
|
||||
"published",
|
||||
],
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
context.is_evaluator = has_course_evaluator_role()
|
||||
|
||||
if not context.is_moderator and not context.batch_info.published:
|
||||
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
||||
|
||||
context.courses = frappe.get_all(
|
||||
"Batch Course",
|
||||
{"parent": batch_name},
|
||||
@@ -44,6 +52,4 @@ def get_context(context):
|
||||
context.student_count = frappe.db.count("Batch Student", {"parent": batch_name})
|
||||
context.seats_left = context.batch_info.seat_count - context.student_count
|
||||
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
context.is_evaluator = has_course_evaluator_role()
|
||||
context.is_student = is_student(batch_name)
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<div class="common-page-style lms-page-style">
|
||||
<div class="container">
|
||||
{{ Header() }}
|
||||
{% if past_batches | length or upcoming_batches | length %}
|
||||
{{ BatchTabs(past_batches, upcoming_batches, my_batches) }}
|
||||
{% if past_batches | length or upcoming_batches | length or private_batches | length %}
|
||||
{{ BatchTabs(past_batches, upcoming_batches, private_batches, my_batches) }}
|
||||
{% else %}
|
||||
{{ EmptyState() }}
|
||||
{% endif %}
|
||||
@@ -27,7 +27,7 @@
|
||||
</header>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro BatchTabs(past_batches, upcoming_batches, my_batches) %}
|
||||
{% macro BatchTabs(past_batches, upcoming_batches, private_batches, my_batches) %}
|
||||
<article>
|
||||
<ul class="nav lms-nav" id="courses-tab">
|
||||
|
||||
@@ -49,6 +49,15 @@
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#private">
|
||||
{{ _("Private") }}
|
||||
<span class="course-list-count">
|
||||
{{ private_batches | length }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if frappe.session.user != "Guest" %}
|
||||
@@ -75,6 +84,10 @@
|
||||
<div class="tab-pane" id="past" role="tabpanel" aria-labelledby="past">
|
||||
{{ BatchCard(past_batches, show_price=False, label="Archived") }}
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="private" role="tabpanel" aria-labelledby="private">
|
||||
{{ BatchCard(private_batches, show_price=False, label="Private") }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if frappe.session.user != "Guest" %}
|
||||
|
||||
@@ -19,25 +19,29 @@ def get_context(context):
|
||||
"amount",
|
||||
"currency",
|
||||
"seat_count",
|
||||
"published",
|
||||
],
|
||||
order_by="start_date",
|
||||
)
|
||||
|
||||
past_batches, upcoming_batches = [], []
|
||||
past_batches, upcoming_batches, private_batches = [], [], []
|
||||
for batch in batches:
|
||||
batch.student_count = frappe.db.count("Batch Student", {"parent": batch.name})
|
||||
batch.course_count = frappe.db.count("Batch Course", {"parent": batch.name})
|
||||
batch.seats_left = (
|
||||
batch.seat_count - batch.student_count if batch.seat_count else None
|
||||
)
|
||||
print(batch.seat_count, batch.student_count, batch.seats_left)
|
||||
if getdate(batch.start_date) < getdate():
|
||||
print(batch.name, batch.published)
|
||||
if not batch.published:
|
||||
private_batches.append(batch)
|
||||
elif getdate(batch.start_date) < getdate():
|
||||
past_batches.append(batch)
|
||||
else:
|
||||
upcoming_batches.append(batch)
|
||||
|
||||
context.past_batches = sorted(past_batches, key=lambda d: d.start_date)
|
||||
context.upcoming_batches = sorted(upcoming_batches, key=lambda d: d.start_date)
|
||||
context.private_batches = sorted(private_batches, key=lambda d: d.start_date)
|
||||
|
||||
if frappe.session.user != "Guest":
|
||||
my_batches_info = []
|
||||
|
||||
Reference in New Issue
Block a user