fix: removing get_doc dependencies for lms course
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
{% set color = member.get_palette() %}
|
{% set color = get_palette(member.full_name) %}
|
||||||
<a class="button-links" href="{{ get_profile_url(member.username) }}">
|
<a class="button-links" href="{{ get_profile_url(member.username) }}">
|
||||||
<span class="avatar {{ avatar_class }}" title="{{ member.full_name }}">
|
<span class="avatar {{ avatar_class }}" title="{{ member.full_name }}">
|
||||||
{% if member.user_image %}
|
{% if member.user_image %}
|
||||||
|
|||||||
@@ -161,7 +161,11 @@ update_website_context = [
|
|||||||
|
|
||||||
jinja = {
|
jinja = {
|
||||||
"methods": [
|
"methods": [
|
||||||
"school.page_renderers.get_profile_url"
|
"school.page_renderers.get_profile_url",
|
||||||
|
"school.overrides.user.get_palette",
|
||||||
|
"school.www.utils.get_membership",
|
||||||
|
"school.www.utils.get_lessons",
|
||||||
|
"school.www.utils.get_tags"
|
||||||
],
|
],
|
||||||
"filters": []
|
"filters": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# Copyright (c) 2021, Frappe and contributors
|
||||||
# Copyright (c) 2021, FOSS United and contributors
|
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
@@ -143,46 +142,7 @@ class LMSCourse(Document):
|
|||||||
fieldname="batch")
|
fieldname="batch")
|
||||||
return batch_name and frappe.get_doc("LMS Batch", batch_name)
|
return batch_name and frappe.get_doc("LMS Batch", batch_name)
|
||||||
|
|
||||||
def get_instructor(self):
|
|
||||||
if self.instructor:
|
|
||||||
return frappe.get_doc("User", self.instructor)
|
|
||||||
return frappe.get_doc("User", self.owner)
|
|
||||||
|
|
||||||
def get_chapters(self):
|
|
||||||
"""Returns all chapters of this course.
|
|
||||||
"""
|
|
||||||
chapters = []
|
|
||||||
for row in self.chapters:
|
|
||||||
chapter_details = frappe.db.get_value("Course Chapter", row.chapter,
|
|
||||||
["name", "title", "description"],
|
|
||||||
as_dict=True)
|
|
||||||
chapter_details.idx = row.idx
|
|
||||||
chapters.append(chapter_details)
|
|
||||||
return chapters
|
|
||||||
|
|
||||||
def get_lessons(self, chapter=None):
|
|
||||||
""" If chapter is passed, returns lessons of only that chapter.
|
|
||||||
Else returns lessons of all chapters of the course """
|
|
||||||
lessons = []
|
|
||||||
|
|
||||||
if chapter:
|
|
||||||
return self.get_lesson_details(chapter)
|
|
||||||
|
|
||||||
for chapter in self.get_chapters():
|
|
||||||
lesson = self.get_lesson_details(chapter)
|
|
||||||
lessons += lesson
|
|
||||||
|
|
||||||
return lessons
|
|
||||||
|
|
||||||
def get_lesson_details(self, chapter):
|
|
||||||
lessons = []
|
|
||||||
lesson_list = frappe.get_all("Lesson Reference", {"parent": chapter.name},
|
|
||||||
["lesson", "idx"], order_by="idx")
|
|
||||||
for row in lesson_list:
|
|
||||||
lesson_details = frappe.get_doc("Course Lesson", row.lesson)
|
|
||||||
lesson_details.number = flt("{}.{}".format(chapter.idx, row.idx))
|
|
||||||
lessons.append(lesson_details)
|
|
||||||
return lessons
|
|
||||||
|
|
||||||
def get_slugified_chapter_title(self, chapter):
|
def get_slugified_chapter_title(self, chapter):
|
||||||
return slugify(chapter)
|
return slugify(chapter)
|
||||||
@@ -201,15 +161,6 @@ class LMSCourse(Document):
|
|||||||
batch_names = {m.batch for m in memberships}
|
batch_names = {m.batch for m in memberships}
|
||||||
return [b for b in batches if b.name in batch_names]
|
return [b for b in batches if b.name in batch_names]
|
||||||
|
|
||||||
def get_upcoming_batches(self):
|
|
||||||
now = frappe.utils.nowdate()
|
|
||||||
batches = find_all("LMS Batch",
|
|
||||||
course=self.name,
|
|
||||||
start_date=[">", now],
|
|
||||||
status="Active",
|
|
||||||
visibility="Public")
|
|
||||||
return batches
|
|
||||||
|
|
||||||
def get_cohorts(self):
|
def get_cohorts(self):
|
||||||
return find_all("Cohort", course=self.name, order_by="creation")
|
return find_all("Cohort", course=self.name, order_by="creation")
|
||||||
|
|
||||||
@@ -263,22 +214,7 @@ class LMSCourse(Document):
|
|||||||
return
|
return
|
||||||
return f"/courses/{self.name}/learn/{lesson_number}"
|
return f"/courses/{self.name}/learn/{lesson_number}"
|
||||||
|
|
||||||
def get_membership(self, member, batch=None):
|
|
||||||
filters = {
|
|
||||||
"member": member,
|
|
||||||
"course": self.name
|
|
||||||
}
|
|
||||||
if batch:
|
|
||||||
filters["batch"] = batch
|
|
||||||
|
|
||||||
membership = frappe.db.get_value("LMS Batch Membership",
|
|
||||||
filters,
|
|
||||||
["name", "batch", "current_lesson", "member_type", "progress"],
|
|
||||||
as_dict=True)
|
|
||||||
|
|
||||||
if membership and membership.batch:
|
|
||||||
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
|
|
||||||
return membership
|
|
||||||
|
|
||||||
def get_all_memberships(self, member):
|
def get_all_memberships(self, member):
|
||||||
all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": self.name}, ["batch"])
|
all_memberships = frappe.get_all("LMS Batch Membership", {"member": member, "course": self.name}, ["batch"])
|
||||||
@@ -302,8 +238,7 @@ class LMSCourse(Document):
|
|||||||
member_names = [m['member'] for m in memberships]
|
member_names = [m['member'] for m in memberships]
|
||||||
return find_all("User", name=["IN", member_names])
|
return find_all("User", name=["IN", member_names])
|
||||||
|
|
||||||
def get_tags(self):
|
|
||||||
return self.tags.split(",") if self.tags else []
|
|
||||||
|
|
||||||
def get_reviews(self):
|
def get_reviews(self):
|
||||||
reviews = frappe.get_all("LMS Course Review",
|
reviews = frappe.get_all("LMS Course Review",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2021, FOSS United and contributors
|
# Copyright (c) 2021, Frappe and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ def sanitize_html(html, macro):
|
|||||||
any broken tags. This makes sures that all those things are fixed
|
any broken tags. This makes sures that all those things are fixed
|
||||||
before passing to the etree parser.
|
before passing to the etree parser.
|
||||||
"""
|
"""
|
||||||
soup = BeautifulSoup(html, features="lxml")
|
soup = BeautifulSoup(html, features="html5lib")
|
||||||
nodes = soup.body.children
|
nodes = soup.body.children
|
||||||
classname = ""
|
classname = ""
|
||||||
if macro == "YouTubeVideo":
|
if macro == "YouTubeVideo":
|
||||||
|
|||||||
@@ -1,47 +1,41 @@
|
|||||||
{% set membership = course.get_membership(frappe.session.user) %}
|
{% set membership = get_membership(course.name, frappe.session.user) %}
|
||||||
{% set progress = frappe.utils.cint(membership.progress) %}
|
{% set progress = frappe.utils.cint(membership.progress) %}
|
||||||
<div class="common-card-style course-card" data-course="{{ course.name }}">
|
<div class="common-card-style course-card" data-course="{{ course.name }}">
|
||||||
|
|
||||||
<div class="course-image {% if not course.image %}default-image{% endif %}" {% if course.image %}
|
<div class="course-image {% if not course.image %}default-image{% endif %}" {% if course.image %}
|
||||||
style="background-image: url( {{ course.image }} );" {% endif %}>
|
style="background-image: url( {{ course.image }} );" {% endif %}>
|
||||||
<div class="course-tags">
|
<div class="course-tags">
|
||||||
{% for tag in course.get_tags() %}
|
{% for tag in get_tags(course.name) %}
|
||||||
<div class="course-card-pills">{{ tag }}</div>
|
<div class="course-card-pills">{{ tag }}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if membership and not read_only %}
|
|
||||||
{% if progress < 100 %} <div class="course-card-pills dark-pills ml-auto">{{ frappe.utils.rounded(progress) }}%
|
|
||||||
{{ _("Completed") }}
|
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% if not course.image %}
|
||||||
<div class="course-card-pills dark-pills ml-auto"> <img src="/assets/school/icons/check.svg"> {{ _("Completed")
|
<div class="default-image-text">{{ course.title[0] }}</div>
|
||||||
}}</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if not course.image %}
|
|
||||||
<div class="default-image-text">{{ course.title[0] }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="course-card-content">
|
<div class="course-card-content">
|
||||||
<div class="course-card-meta muted-text">
|
<div class="course-card-meta">
|
||||||
{% if course.get_chapters() | length %}
|
{% if get_lessons(course.name) | length %}
|
||||||
<span>
|
<span>
|
||||||
{{ course.get_chapters() | length }} {{ _("Chapters") }}
|
{{ get_lessons(course.name) | length }} {{ _("Lessons") }}
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if course.get_chapters() | length and course.get_upcoming_batches() | length %}
|
|
||||||
<span class="font-weight-bold ml-3 mr-3"> . </span>
|
|
||||||
{% endif %}
|
|
||||||
{% if course.get_upcoming_batches() | length %}
|
|
||||||
<span class="">
|
|
||||||
{{ course.get_upcoming_batches() | length }} {{ _("Open Batches") }}
|
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-heading course-card-title">{{ course.title }}</div>
|
<div class="card-heading course-card-title">{{ course.title }}</div>
|
||||||
<div {% if not read_only %} class="mb-4" {% endif %}>
|
|
||||||
<span class="zindex">
|
{% if membership and not read_only %}
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar" role="progressbar" aria-valuenow="{{ progress }}"
|
||||||
|
aria-valuemin="0" aria-valuemax="100" style="width:{{ progress }}%">
|
||||||
|
<span class="sr-only"> {{ progress }} Complete</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-percentage">{{ progress }}% Completed</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="course-card-footer">
|
||||||
|
<span>
|
||||||
{{ widgets.Avatar(member=course.get_instructor(), avatar_class="avatar-small") }}
|
{{ widgets.Avatar(member=course.get_instructor(), avatar_class="avatar-small") }}
|
||||||
<a class="button-links" href="{{ get_profile_url(course.get_instructor().username) }}">
|
<a class="button-links" href="{{ get_profile_url(course.get_instructor().username) }}">
|
||||||
<span class="course-instructor">
|
<span class="course-instructor">
|
||||||
@@ -76,38 +70,21 @@
|
|||||||
{% set certificate = course.is_certified() %}
|
{% set certificate = course.is_certified() %}
|
||||||
|
|
||||||
{% if certificate %}
|
{% if certificate %}
|
||||||
<div class="view-course-link is-default">
|
|
||||||
{{ _("Get Certificate") }}
|
|
||||||
</div>
|
|
||||||
<a class="stretched-link" href="/courses/{{ course.name }}/{{ certificate }}"></a>
|
<a class="stretched-link" href="/courses/{{ course.name }}/{{ certificate }}"></a>
|
||||||
|
|
||||||
{% elif course.enable_certification and progress == 100 %}
|
{% elif course.enable_certification and progress == 100 %}
|
||||||
<div class="view-course-link is-default" id="certification" data-course="{{ course.name }}">
|
<a class="stretched-link" id="certification" data-course="{{ course.name }}"></a>
|
||||||
{{ _("Get Certificate") }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% elif progress == 100 %}
|
{% elif progress == 100 %}
|
||||||
<div class="view-course-link is-default">
|
|
||||||
{{ _("Course Completed") }}
|
|
||||||
</div>
|
|
||||||
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
||||||
|
|
||||||
{% elif course.upcoming %}
|
{% elif course.upcoming %}
|
||||||
<div class="view-course-link is-secondary border">
|
|
||||||
{{ _("Upcoming Course") }}
|
|
||||||
</div>
|
|
||||||
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
||||||
|
|
||||||
{% elif membership %}
|
{% elif membership %}
|
||||||
<div class="view-course-link is-primary">
|
|
||||||
{{ _("Continue Course") }}
|
|
||||||
</div>
|
|
||||||
<a class="stretched-link" href="{{ course.get_learn_url(lesson_index) }}{{ query_parameter }}"></a>
|
<a class="stretched-link" href="{{ course.get_learn_url(lesson_index) }}{{ query_parameter }}"></a>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="view-course-link is-default">
|
|
||||||
{{ _("View Course") }}
|
|
||||||
</div>
|
|
||||||
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -117,21 +94,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
trim_course_titles();
|
|
||||||
|
|
||||||
$("#certification").unbind().click((e) => {
|
$("#certification").unbind().click((e) => {
|
||||||
create_certificate(e);
|
create_certificate(e);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
var trim_course_titles = () => {
|
})
|
||||||
$(".course-card-title").each((i, element) => {
|
|
||||||
var title = $(element).text();
|
|
||||||
var length = $(window).width() <= 375 ? 60 : 65;
|
|
||||||
var suffix = title.length > length ? "..." : "";
|
|
||||||
$(element).text(title.substring(0, length) + suffix);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var create_certificate = (e) => {
|
var create_certificate = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -93,27 +93,6 @@ class CustomUser(User):
|
|||||||
'is_published': True
|
'is_published': True
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_palette(self):
|
|
||||||
"""
|
|
||||||
Returns a color unique to each member for Avatar """
|
|
||||||
|
|
||||||
palette = [
|
|
||||||
['--orange-avatar-bg', '--orange-avatar-color'],
|
|
||||||
['--pink-avatar-bg', '--pink-avatar-color'],
|
|
||||||
['--blue-avatar-bg', '--blue-avatar-color'],
|
|
||||||
['--green-avatar-bg', '--green-avatar-color'],
|
|
||||||
['--dark-green-avatar-bg', '--dark-green-avatar-color'],
|
|
||||||
['--red-avatar-bg', '--red-avatar-color'],
|
|
||||||
['--yellow-avatar-bg', '--yellow-avatar-color'],
|
|
||||||
['--purple-avatar-bg', '--purple-avatar-color'],
|
|
||||||
['--gray-avatar-bg', '--gray-avatar-color0']
|
|
||||||
]
|
|
||||||
|
|
||||||
encoded_name = str(self.full_name).encode("utf-8")
|
|
||||||
hash_name = hashlib.md5(encoded_name).hexdigest()
|
|
||||||
idx = cint((int(hash_name[4:6], 16) + 1) / 5.33)
|
|
||||||
return palette[idx % 8]
|
|
||||||
|
|
||||||
def get_batch_count(self) -> int:
|
def get_batch_count(self) -> int:
|
||||||
"""Returns the number of batches authored by this user.
|
"""Returns the number of batches authored by this user.
|
||||||
"""
|
"""
|
||||||
@@ -174,6 +153,27 @@ class CustomUser(User):
|
|||||||
"completed": completed
|
"completed": completed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_palette(full_name):
|
||||||
|
"""
|
||||||
|
Returns a color unique to each member for Avatar """
|
||||||
|
|
||||||
|
palette = [
|
||||||
|
['--orange-avatar-bg', '--orange-avatar-color'],
|
||||||
|
['--pink-avatar-bg', '--pink-avatar-color'],
|
||||||
|
['--blue-avatar-bg', '--blue-avatar-color'],
|
||||||
|
['--green-avatar-bg', '--green-avatar-color'],
|
||||||
|
['--dark-green-avatar-bg', '--dark-green-avatar-color'],
|
||||||
|
['--red-avatar-bg', '--red-avatar-color'],
|
||||||
|
['--yellow-avatar-bg', '--yellow-avatar-color'],
|
||||||
|
['--purple-avatar-bg', '--purple-avatar-color'],
|
||||||
|
['--gray-avatar-bg', '--gray-avatar-color0']
|
||||||
|
]
|
||||||
|
|
||||||
|
encoded_name = str(full_name).encode("utf-8")
|
||||||
|
hash_name = hashlib.md5(encoded_name).hexdigest()
|
||||||
|
idx = cint((int(hash_name[4:6], 16) + 1) / 5.33)
|
||||||
|
return palette[idx % 8]
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def sign_up(email, full_name, verify_terms):
|
def sign_up(email, full_name, verify_terms):
|
||||||
if is_signup_disabled():
|
if is_signup_disabled():
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
--text-3xl: 22px;
|
--text-3xl: 22px;
|
||||||
--text-4xl: 44px;
|
--text-4xl: 44px;
|
||||||
--navbar-shadow: 0px 1px 8px rgba(0, 0, 0, 0.08)
|
--navbar-shadow: 0px 1px 8px rgba(0, 0, 0, 0.08)
|
||||||
|
--gray-750: #505A62;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=checkbox] {
|
input[type=checkbox] {
|
||||||
@@ -56,15 +57,16 @@ input[type=checkbox] {
|
|||||||
.course-card-pills {
|
.course-card-pills {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: .5rem;
|
margin-right: 1rem;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
padding: 4px 6px;
|
padding: 3.5px 8px;
|
||||||
font-size: 10px;
|
font-size: 11px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
letter-spacing: 0.011em;
|
letter-spacing: 0.011em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
box-shadow: var(--shadow-base);
|
box-shadow: var(--popover-box-shadow);
|
||||||
|
color: var(--gray-900);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark-pills {
|
.dark-pills {
|
||||||
@@ -94,6 +96,8 @@ input[type=checkbox] {
|
|||||||
|
|
||||||
.course-card {
|
.course-card {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.muted-text {
|
.muted-text {
|
||||||
@@ -102,17 +106,24 @@ input[type=checkbox] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.course-card-meta {
|
.course-card-meta {
|
||||||
margin: 16px 0px 8px;
|
margin: 0.75rem 0 0.5rem;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card-meta-2 {
|
||||||
|
color: var(--gray-750);
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-card-content {
|
.course-card-content {
|
||||||
width: 100%;
|
padding: 0 1.25rem 1.25rem;
|
||||||
padding: 0px 1rem 1.25rem;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 350px) {
|
@media (max-width: 350px) {
|
||||||
.course-card-content {
|
.course-card-content {
|
||||||
padding: 0px 10px 20px;
|
padding: 0px 10px 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,8 +135,8 @@ input[type=checkbox] {
|
|||||||
|
|
||||||
.course-card-title {
|
.course-card-title {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
margin-bottom: 1.5rem;
|
font-weight: 600;
|
||||||
height: 56px;
|
margin-bottom: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 360px) {
|
@media (max-width: 360px) {
|
||||||
@@ -145,16 +156,19 @@ input[type=checkbox] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.course-instructor {
|
.course-instructor {
|
||||||
margin-left: 8px;
|
margin-left: 0.625rem;
|
||||||
font-size: 12px;
|
font-size: 0.875rem;
|
||||||
line-height: 135%;
|
|
||||||
color: var(--text-color-dark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-student-count {
|
.course-student-count {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
float: right;
|
float: right;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card-footer {
|
||||||
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-course-link {
|
.view-course-link {
|
||||||
@@ -1181,7 +1195,7 @@ input[type=checkbox] {
|
|||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 8px;
|
height: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
@@ -1189,12 +1203,9 @@ input[type=checkbox] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progress-percentage {
|
.progress-percentage {
|
||||||
width: 100%;
|
margin: 0.5rem 0 1.3rem;
|
||||||
font-size: 12px;
|
font-size: 0.8rem;
|
||||||
line-height: 165%;
|
font-weight: 500;
|
||||||
letter-spacing: 0.02em;
|
|
||||||
color: #000000;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import frappe
|
|
||||||
from school.lms.models import Course
|
|
||||||
|
|
||||||
def get_common_context(context):
|
|
||||||
context.no_cache = 1
|
|
||||||
|
|
||||||
course_name = frappe.form_dict["course"]
|
|
||||||
try:
|
|
||||||
batch_name = frappe.form_dict["batch"]
|
|
||||||
except KeyError:
|
|
||||||
batch_name = None
|
|
||||||
|
|
||||||
course = frappe.get_doc("LMS Course", course_name)
|
|
||||||
if not course:
|
|
||||||
context.template = "www/404.html"
|
|
||||||
return
|
|
||||||
context.course = course
|
|
||||||
context.lessons = course.get_lessons()
|
|
||||||
membership = course.get_membership(frappe.session.user, batch_name)
|
|
||||||
context.membership = membership
|
|
||||||
if membership:
|
|
||||||
batch = course.get_batch(membership.batch)
|
|
||||||
|
|
||||||
if batch:
|
|
||||||
context.batch = batch
|
|
||||||
|
|
||||||
context.course.query_parameter = "?batch=" + membership.batch if membership and membership.batch else ""
|
|
||||||
context.livecode_url = get_livecode_url()
|
|
||||||
|
|
||||||
def get_livecode_url():
|
|
||||||
return frappe.db.get_single_value("LMS Settings", "livecode_url")
|
|
||||||
|
|
||||||
def redirect_to_lesson(course, index_="1.1"):
|
|
||||||
frappe.local.flags.redirect_location = course.get_learn_url(index_) + course.query_parameter
|
|
||||||
raise frappe.Redirect
|
|
||||||
@@ -19,13 +19,13 @@
|
|||||||
|
|
||||||
{% include "school/templates/search_course/search_course.html" %}
|
{% include "school/templates/search_course/search_course.html" %}
|
||||||
<div class="course-list">
|
<div class="course-list">
|
||||||
{% set title = _("Live Courses") %}
|
|
||||||
{% set courses = live_courses %}
|
{% set courses = live_courses %}
|
||||||
|
{% set title = _("All Live Courses ({0})").format(courses | length) %}
|
||||||
{% set classes = "live-courses" %}
|
{% set classes = "live-courses" %}
|
||||||
{% include "school/templates/course_list.html" %}
|
{% include "school/templates/course_list.html" %}
|
||||||
|
|
||||||
{% set title = _("Upcoming Courses") %}
|
|
||||||
{% set courses = upcoming_courses %}
|
{% set courses = upcoming_courses %}
|
||||||
|
{% set title = _("All Upcoming Courses ({0})").format(courses | length) %}
|
||||||
{% set classes = "upcoming-courses mt-10" %}
|
{% set classes = "upcoming-courses mt-10" %}
|
||||||
{% include "school/templates/course_list.html" %}
|
{% include "school/templates/course_list.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,21 +6,21 @@ def get_context(context):
|
|||||||
context.live_courses, context.upcoming_courses = get_courses()
|
context.live_courses, context.upcoming_courses = get_courses()
|
||||||
context.restriction = check_profile_restriction()
|
context.restriction = check_profile_restriction()
|
||||||
context.metatags = {
|
context.metatags = {
|
||||||
"title": "All Courses",
|
"title": "All Live Courses",
|
||||||
"image": frappe.db.get_single_value("Website Settings", "banner_image"),
|
"image": frappe.db.get_single_value("Website Settings", "banner_image"),
|
||||||
"description": "This page lists all the courses published on our website",
|
"description": "This page lists all the courses published on our website",
|
||||||
"keywords": "All Courses, Courses, Learn"
|
"keywords": "All Courses, Courses, Learn"
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_courses():
|
def get_courses():
|
||||||
course_names = frappe.get_all("LMS Course",
|
courses = frappe.get_all("LMS Course",
|
||||||
filters={"is_published": True},
|
filters={"is_published": True},
|
||||||
fields=["name", "upcoming"])
|
fields=["name", "upcoming", "title", "image"])
|
||||||
|
|
||||||
live_courses, upcoming_courses = [], []
|
live_courses, upcoming_courses = [], []
|
||||||
for course in course_names:
|
for course in courses:
|
||||||
if course.upcoming:
|
if course.upcoming:
|
||||||
upcoming_courses.append(frappe.get_doc("LMS Course", course.name))
|
upcoming_courses.append(course)
|
||||||
else:
|
else:
|
||||||
live_courses.append(frappe.get_doc("LMS Course", course.name))
|
live_courses.append(course)
|
||||||
return live_courses, upcoming_courses
|
return live_courses, upcoming_courses
|
||||||
|
|||||||
97
school/www/utils.py
Normal file
97
school/www/utils.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import frappe
|
||||||
|
from school.lms.models import Course
|
||||||
|
from frappe.utils import flt
|
||||||
|
|
||||||
|
def get_common_context(context):
|
||||||
|
context.no_cache = 1
|
||||||
|
|
||||||
|
course_name = frappe.form_dict["course"]
|
||||||
|
try:
|
||||||
|
batch_name = frappe.form_dict["batch"]
|
||||||
|
except KeyError:
|
||||||
|
batch_name = None
|
||||||
|
|
||||||
|
course = frappe.get_doc("LMS Course", course_name)
|
||||||
|
if not course:
|
||||||
|
context.template = "www/404.html"
|
||||||
|
return
|
||||||
|
context.course = course
|
||||||
|
context.lessons = course.get_lessons()
|
||||||
|
membership = get_membership(course_name, frappe.session.user, batch_name)
|
||||||
|
context.membership = membership
|
||||||
|
if membership:
|
||||||
|
batch = course.get_batch(membership.batch)
|
||||||
|
|
||||||
|
if batch:
|
||||||
|
context.batch = batch
|
||||||
|
|
||||||
|
context.course.query_parameter = "?batch=" + membership.batch if membership and membership.batch else ""
|
||||||
|
context.livecode_url = get_livecode_url()
|
||||||
|
|
||||||
|
def get_livecode_url():
|
||||||
|
return frappe.db.get_single_value("LMS Settings", "livecode_url")
|
||||||
|
|
||||||
|
def redirect_to_lesson(course, index_="1.1"):
|
||||||
|
frappe.local.flags.redirect_location = course.get_learn_url(index_) + course.query_parameter
|
||||||
|
raise frappe.Redirect
|
||||||
|
|
||||||
|
def get_membership(course, member, batch=None):
|
||||||
|
filters = {
|
||||||
|
"member": member,
|
||||||
|
"course": course
|
||||||
|
}
|
||||||
|
if batch:
|
||||||
|
filters["batch"] = batch
|
||||||
|
|
||||||
|
membership = frappe.db.get_value("LMS Batch Membership",
|
||||||
|
filters,
|
||||||
|
["name", "batch", "current_lesson", "member_type", "progress"],
|
||||||
|
as_dict=True)
|
||||||
|
|
||||||
|
if membership and membership.batch:
|
||||||
|
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
|
||||||
|
return membership
|
||||||
|
|
||||||
|
def get_chapters(course):
|
||||||
|
"""Returns all chapters of this course.
|
||||||
|
"""
|
||||||
|
chapters = frappe.get_all("Course Chapter",
|
||||||
|
{ "course": course },
|
||||||
|
["name", "title", "description", "idx"])
|
||||||
|
return chapters
|
||||||
|
|
||||||
|
def get_lessons(course, chapter=None):
|
||||||
|
""" If chapter is passed, returns lessons of only that chapter.
|
||||||
|
Else returns lessons of all chapters of the course """
|
||||||
|
lessons = []
|
||||||
|
|
||||||
|
if chapter:
|
||||||
|
return get_lesson_details(chapter)
|
||||||
|
|
||||||
|
for chapter in get_chapters(course):
|
||||||
|
lesson = get_lesson_details(chapter)
|
||||||
|
lessons += lesson
|
||||||
|
|
||||||
|
return lessons
|
||||||
|
|
||||||
|
def get_lesson_details(chapter):
|
||||||
|
lessons = []
|
||||||
|
lesson_list = frappe.get_all("Lesson Reference",
|
||||||
|
{"parent": chapter.name},
|
||||||
|
["lesson", "idx"],
|
||||||
|
order_by="idx")
|
||||||
|
|
||||||
|
for row in lesson_list:
|
||||||
|
lesson_details = frappe.db.get_value("Course Lesson", row.lesson, "name", as_dict=True)
|
||||||
|
lesson_details.number = flt("{}.{}".format(chapter.idx, row.idx))
|
||||||
|
lessons.append(lesson_details)
|
||||||
|
return lessons
|
||||||
|
|
||||||
|
def get_tags(course):
|
||||||
|
tags = frappe.db.get_value("LMS Course", course, "tags")
|
||||||
|
return tags.split(",") if tags else []
|
||||||
|
|
||||||
|
def get_instructor(course):
|
||||||
|
if self.instructor:
|
||||||
|
return frappe.get_doc("User", self.instructor)
|
||||||
|
return frappe.get_doc("User", self.owner)
|
||||||
Reference in New Issue
Block a user