Compare commits

..

1 Commits

Author SHA1 Message Date
Anand Chitipothu
7f371aa7a9 fix: remove references to old styles in the hooks
Old styles were removed in #157, but a reference to it was hanging
around in the hooks.
2021-07-19 17:40:30 +05:30
28 changed files with 319 additions and 336 deletions

View File

@@ -19,7 +19,6 @@ app_license = "AGPL"
# app_include_js = "/assets/community/js/community.js" # app_include_js = "/assets/community/js/community.js"
# include js, css files in header of web template # include js, css files in header of web template
web_include_css = "community.bundle.css"
# web_include_css = "/assets/community/css/community.css" # web_include_css = "/assets/community/css/community.css"
# web_include_js = "/assets/community/js/community.js" # web_include_js = "/assets/community/js/community.js"

View File

@@ -2,15 +2,7 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('Chapter', { frappe.ui.form.on('Chapter', {
// refresh: function(frm) {
onload: function (frm) { // }
frm.set_query("lesson", "lessons", function () {
return {
filters: {
"chapter": frm.doc.name,
}
};
});
}
}); });

View File

@@ -9,7 +9,8 @@
"course", "course",
"title", "title",
"description", "description",
"lessons" "locked",
"index_"
], ],
"fields": [ "fields": [
{ {
@@ -23,6 +24,12 @@
"fieldtype": "Markdown Editor", "fieldtype": "Markdown Editor",
"label": "Description" "label": "Description"
}, },
{
"default": "0",
"fieldname": "locked",
"fieldtype": "Check",
"label": "Locked"
},
{ {
"fieldname": "course", "fieldname": "course",
"fieldtype": "Link", "fieldtype": "Link",
@@ -31,10 +38,10 @@
"options": "LMS Course" "options": "LMS Course"
}, },
{ {
"fieldname": "lessons", "default": "1",
"fieldtype": "Table", "fieldname": "index_",
"label": "Lessons", "fieldtype": "Int",
"options": "Lessons" "label": "Index"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
@@ -45,7 +52,7 @@
"link_fieldname": "chapter" "link_fieldname": "chapter"
} }
], ],
"modified": "2021-07-27 16:28:08.667964", "modified": "2021-05-13 21:05:20.531890",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Chapter", "name": "Chapter",

View File

@@ -5,6 +5,15 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
from ...utils import slugify
class Chapter(Document): class Chapter(Document):
pass def get_lessons(self):
rows = frappe.db.get_all("Lesson",
filters={"chapter": self.name},
fields='name',
order_by="index_")
return [frappe.get_doc('Lesson', row['name']) for row in rows]
def get_slugified_chapter_title(self):
return slugify(self.title)

View File

@@ -1,32 +0,0 @@
{
"actions": [],
"creation": "2021-07-27 16:25:02.903245",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"chapter"
],
"fields": [
{
"fieldname": "chapter",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Chapter",
"options": "Chapter",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-07-27 16:25:02.903245",
"modified_by": "Administrator",
"module": "LMS",
"name": "Chapters",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -1,8 +0,0 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class Chapters(Document):
pass

View File

@@ -10,6 +10,7 @@
"include_in_preview", "include_in_preview",
"column_break_4", "column_break_4",
"title", "title",
"index_",
"index_label", "index_label",
"section_break_6", "section_break_6",
"body", "body",
@@ -30,6 +31,13 @@
"in_list_view": 1, "in_list_view": 1,
"label": "Title" "label": "Title"
}, },
{
"default": "1",
"fieldname": "index_",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Index"
},
{ {
"fieldname": "body", "fieldname": "body",
"fieldtype": "Markdown Editor", "fieldtype": "Markdown Editor",
@@ -67,7 +75,7 @@
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-07-27 16:28:29.203624", "modified": "2021-06-29 13:34:49.077363",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Lesson", "name": "Lesson",

View File

@@ -1,31 +0,0 @@
{
"actions": [],
"creation": "2021-07-27 16:25:48.269536",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"lesson"
],
"fields": [
{
"fieldname": "lesson",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Lesson",
"options": "Lesson"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-07-27 16:53:52.732191",
"modified_by": "Administrator",
"module": "LMS",
"name": "Lessons",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -1,8 +0,0 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class Lessons(Document):
pass

View File

@@ -2,15 +2,7 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('LMS Course', { frappe.ui.form.on('LMS Course', {
// refresh: function(frm) {
onload: function (frm) { // }
frm.set_query("chapter", "chapters", function () {
return {
filters: {
"course": frm.doc.name,
}
};
});
}
}); });

View File

@@ -1,5 +1,11 @@
{ {
"actions": [ "actions": [
{
"action": "community.lms.doctype.lms_course.lms_course.reindex_lessons",
"action_type": "Server Action",
"group": "Reindex",
"label": "Reindex Lessons"
},
{ {
"action": "community.lms.doctype.lms_course.lms_course.reindex_exercises", "action": "community.lms.doctype.lms_course.lms_course.reindex_exercises",
"action_type": "Server Action", "action_type": "Server Action",
@@ -15,17 +21,16 @@
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"title", "title",
"short_code",
"video_link", "video_link",
"image",
"column_break_3", "column_break_3",
"tags",
"is_published", "is_published",
"upcoming",
"disable_self_learning", "disable_self_learning",
"image",
"section_break_5", "section_break_5",
"tags",
"short_introduction", "short_introduction",
"description", "description"
"chapters"
], ],
"fields": [ "fields": [
{ {
@@ -48,6 +53,11 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Published" "label": "Published"
}, },
{
"fieldname": "short_code",
"fieldtype": "Data",
"label": "Short Code"
},
{ {
"fieldname": "column_break_3", "fieldname": "column_break_3",
"fieldtype": "Column Break" "fieldtype": "Column Break"
@@ -82,18 +92,6 @@
"fieldname": "tags", "fieldname": "tags",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Tags" "label": "Tags"
},
{
"default": "0",
"fieldname": "upcoming",
"fieldtype": "Check",
"label": "Is an Upcoming Course"
},
{
"fieldname": "chapters",
"fieldtype": "Table",
"label": "Chapters",
"options": "Chapters"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
@@ -113,9 +111,14 @@
"group": "Mentors", "group": "Mentors",
"link_doctype": "LMS Course Mentor Mapping", "link_doctype": "LMS Course Mentor Mapping",
"link_fieldname": "course" "link_fieldname": "course"
},
{
"group": "Mentors",
"link_doctype": "LMS Mentor Request",
"link_fieldname": "course"
} }
], ],
"modified": "2021-07-28 19:01:50.677445", "modified": "2021-07-09 15:05:05.372430",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Course", "name": "LMS Course",
@@ -138,5 +141,6 @@
"sort_field": "creation", "sort_field": "creation",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "title", "title_field": "title",
"track_changes": 1 "track_changes": 1,
"track_views": 1
} }

View File

@@ -9,10 +9,8 @@ import json
from ...utils import slugify from ...utils import slugify
from community.query import find, find_all from community.query import find, find_all
from frappe.utils import flt, cint from frappe.utils import flt, cint
from ...utils import slugify
class LMSCourse(Document): class LMSCourse(Document):
@staticmethod @staticmethod
def find(name): def find(name):
"""Returns the course with specified name. """Returns the course with specified name.
@@ -114,42 +112,17 @@ class LMSCourse(Document):
def get_chapters(self): def get_chapters(self):
"""Returns all chapters of this course. """Returns all chapters of this course.
""" """
chapters = [] # TODO: chapters should have a way to specify the order
for row in self.chapters: return find_all("Chapter", course=self.name, order_by="index_")
chapter_details = frappe.db.get_value("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): def get_lessons(self):
""" If chapter is passed, returns lessons of only that chapter. """ Returns all lessons of this course """
Else returns lessons of all chapters of the course """
lessons = [] lessons = []
chapters = self.get_chapters()
if chapter: for chapter in chapters:
return self.get_lesson_details(chapter) lessons.append(frappe.get_all("Lesson", {"chapter": chapter.name}))
for chapter in self.get_chapters():
lesson = self.get_lesson_details(chapter)
lessons += lesson
return lessons return lessons
def get_lesson_details(self, chapter):
lessons = []
lesson_list = frappe.get_all("Lessons", {"parent": chapter.name},
["lesson", "idx"], order_by="idx")
for row in lesson_list:
lesson_details = frappe.get_doc("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):
return slugify(chapter)
def get_course_progress(self): def get_course_progress(self):
""" Returns the course progress of the session user """ """ Returns the course progress of the session user """
lesson_count = len(self.get_lessons()) lesson_count = len(self.get_lessons())
@@ -187,12 +160,38 @@ class LMSCourse(Document):
visibility="Public") visibility="Public")
return batches return batches
def get_chapter(self, index):
return find("Chapter", course=self.name, index_=index)
def get_lesson(self, chapter_index, lesson_index):
chapter_name = frappe.get_value(
"Chapter",
{"course": self.name, "index_": chapter_index},
"name")
lesson_name = chapter_name and frappe.get_value(
"Lesson",
{"chapter": chapter_name, "index_": lesson_index},
"name")
return lesson_name and frappe.get_doc("Lesson", lesson_name)
def get_lesson_index(self, lesson_name): def get_lesson_index(self, lesson_name):
"""Returns the {chapter_index}.{lesson_index} for the lesson. """Returns the {chapter_index}.{lesson_index} for the lesson.
""" """
lesson = frappe.db.get_value("Lessons", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True) lesson = frappe.get_doc("Lesson", lesson_name)
chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True) chapter = frappe.get_doc("Chapter", lesson.chapter)
return f"{chapter.idx}.{lesson.idx}" return f"{chapter.index_}.{lesson.index_}"
def reindex_lessons(self):
for i, c in enumerate(self.get_chapters(), start=1):
c.index_ = i
c.save()
self._reindex_lessons_in_chapter(c)
def _reindex_lessons_in_chapter(self, c):
for i, lesson in enumerate(c.get_lessons(), start=1):
lesson.index = i
lesson.index_label = f"{c.index_}.{i}"
lesson.save()
def reindex_exercises(self): def reindex_exercises(self):
for i, c in enumerate(self.get_chapters(), start=1): for i, c in enumerate(self.get_chapters(), start=1):
@@ -203,7 +202,7 @@ class LMSCourse(Document):
def _reindex_exercises_in_chapter(self, c): def _reindex_exercises_in_chapter(self, c):
i = 1 i = 1
for lesson in self.get_lessons(c): for lesson in c.get_lessons():
for exercise in lesson.get_exercises(): for exercise in lesson.get_exercises():
exercise.index_ = i exercise.index_ = i
exercise.index_label = f"{c.index_}.{i}" exercise.index_label = f"{c.index_}.{i}"
@@ -303,6 +302,9 @@ class LMSCourse(Document):
return None return None
return sum(ratings)/len(ratings) return sum(ratings)/len(ratings)
def get_outline(self):
return CourseOutline(self)
def get_progress(self, lesson): def get_progress(self, lesson):
return frappe.db.get_value("LMS Course Progress", return frappe.db.get_value("LMS Course Progress",
{ {
@@ -312,14 +314,55 @@ class LMSCourse(Document):
}, },
["status"]) ["status"])
def get_neighbours(self, current, lessons): class CourseOutline:
def __init__(self, course):
self.course = course
self.chapters = self.get_chapters()
self.lessons = self.get_lessons()
def get_next(self, current):
current = flt(current) current = flt(current)
numbers = sorted(lesson.number for lesson in lessons) numbers = sorted(lesson['number'] for lesson in self.lessons)
try:
index = numbers.index(current) index = numbers.index(current)
return { return numbers[index+1]
"prev": numbers[index-1] if index-1 >= 0 else None, except IndexError:
"next": numbers[index+1] if index+1 < len(numbers) else None return None
}
def get_prev(self, current):
current = flt(current)
numbers = sorted(lesson['number'] for lesson in self.lessons)
try:
index = numbers.index(current)
if index == 0:
return None
return numbers[index-1]
except IndexError:
return None
def get_chapters(self):
return frappe.db.get_all("Chapter",
filters={"course": self.course.name},
fields=["name", "title", "index_"],
order_by="index_")
def get_lessons(self):
chapters = [c['name'] for c in self.chapters]
lessons = frappe.db.get_all("Lesson",
filters={"chapter": ["IN", chapters]},
fields=["name", "title", "chapter", "index_"])
chapter_numbers = {c['name']: c['index_'] for c in self.chapters}
for lesson in lessons:
lesson['number'] = flt("{}.{}".format(chapter_numbers[lesson['chapter']], lesson['index_']))
return lessons
@frappe.whitelist()
def reindex_lessons(doc):
course_data = json.loads(doc)
course = frappe.get_doc("LMS Course", course_data['name'])
course.reindex_lessons()
frappe.msgprint("All lessons in this course have been re-indexed.")
@frappe.whitelist() @frappe.whitelist()
def reindex_exercises(doc): def reindex_exercises(doc):

View File

@@ -27,13 +27,12 @@
"fieldname": "lesson", "fieldname": "lesson",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Lesson", "label": "Lesson",
"options": "Lesson", "options": "Lesson"
"read_only": 1
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-07-23 19:06:12.551633", "modified": "2021-06-23 17:58:57.642873",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Quiz", "name": "LMS Quiz",

View File

@@ -0,0 +1,67 @@
<div class="mt-5">
<a class="anchor_style" href="/courses">Courses</a> /{% if course.is_mentor(frappe.session.user) %} <a
class="anchor_style" href="/courses/{{ course.name }}"> {{ course.title }}</a> {% else %} <span class="text-muted">
{{ course.title }}</span> {% endif %}
{% set all_memberships = course.get_all_memberships(frappe.session.user) %}
{% if membership and membership.batch and all_memberships | length > 1 %}
<a class="pull-right dropdown-item border rounded" style="width: 10rem;" href="#" id="navbarDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ membership.batch_title }}
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
{% for data in all_memberships %}
{% if data.batch != membership.batch %}
<a class="dropdown-item switch-batch"
href="/courses/{{ course.name }}/home?batch={{ data.batch }}">{{ data.batch_title }}</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
{% if not membership %}
{% set display_class = "hide" %}
{% else %}
{% set display_class = "" %}
{% endif %}
<ul class="nav nav-tabs mt-4">
<li class="nav-item">
<a class="nav-link" id="home" href="/courses/{{course.name}}/home{{ course.query_parameter }}">Home</a>
</li>
<li class="nav-item">
{% set lesson_index = course.get_lesson_index(membership.current_lesson) if membership and membership.current_lesson
else '1.1' %}
<a class="nav-link" id="learn"
href="{{ course.get_learn_url(lesson_index) }}{{ course.query_parameter }}">Lessons</a>
</li>
<!-- <li class="nav-item">
<a class="nav-link" id="schedule" href="/courses/{{course.name}}/schedule">Schedule</a>
</li> -->
<li class="nav-item {{ display_class }}">
<a class="nav-link" id="members" href="/courses/{{course.name}}/members{{ course.query_parameter }}">Members</a>
</li>
<!-- <li class="nav-item {{ display_class }}">
<a class="nav-link" id="discussion" href="/courses/{{course.name}}/discuss">Discussion</a>
</li> -->
<!-- <li class="nav-item">
<a class="nav-link" id="about" href="/courses/{{course.name}}/about">About</a>
</li> -->
{% if membership and membership.batch and course.is_mentor(frappe.session.user) %}
<li class="nav-item">
<a class="nav-link" id="progress" href="/courses/{{course.name}}/progress{{ course.query_parameter }}">Progress</a>
</li>
{% endif %}
</ul>
{% block script %}
<script>
frappe.ready(() => {
var selector = document.querySelector(`a[href="${decodeURIComponent(window.location.pathname)}{{ course.query_parameter }}"]`)
if (selector) {
selector.classList.add('active');
}
else {
$("#learn").addClass('active')
}
})
</script>
{% endblock %}

View File

@@ -1,28 +1,26 @@
<div> <div>
<div class="small-title chapter-title" data-target="#{{ course.get_slugified_chapter_title(chapter.title) }}" <div class="small-title chapter-title" data-target="#{{ chapter.get_slugified_chapter_title() }}"
data-toggle="collapse" aria-expanded="false"> data-toggle="collapse" aria-expanded="false">
<img class="chapter-icon" src="/assets/community/icons/chevron-right.svg"> <img class="chapter-icon" src="/assets/community/icons/chevron-right.svg">
{{ index }}. {{ chapter.title }} {{ index }}. {{ chapter.title }}
</div> </div>
<div class="chapter-content collapse navbar-collapse" id="{{ course.get_slugified_chapter_title(chapter.title) }}"> <div class="chapter-content collapse navbar-collapse" id="{{ chapter.get_slugified_chapter_title() }}">
{% if chapter.description %}
<div class="chapter-description muted-text"> <div class="chapter-description muted-text">
{{ chapter.description }} {{ chapter.description }}
</div> </div>
{% endif %}
<div class="lessons"> <div class="lessons">
{% for lesson in course.get_lessons(chapter) %} {% for lesson in chapter.get_lessons() %}
<div class="lesson-info{% if membership.current_lesson == lesson.name %} active-lesson {% endif %}"> <div class="lesson-info {% if membership.current_lesson == lesson.name %} active-lesson {% endif %}">
{% if membership or lesson.include_in_preview %} {% if membership or lesson.include_in_preview %}
<a class="lesson-links" <a class="lesson-links"
href="{{ course.get_learn_url(lesson.number) }}{{course.query_parameter}}" href="{{ course.get_learn_url(course.get_lesson_index(lesson.name)) }}{{course.query_parameter}}"
data-course="{{ course.name }}"> data-course="{{ course.name }}">
{{ lesson.title }} {{ lesson.title }}

View File

@@ -53,19 +53,15 @@
{% set query_parameter = "?batch=" + membership.batch if membership and membership.batch else "" %} {% set query_parameter = "?batch=" + membership.batch if membership and membership.batch else "" %}
{% if course.upcoming %} {% if membership %}
<div class="view-course-link is-default">
Upcoming Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
</div>
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
{% elif membership %}
<div class="view-course-link is-primary"> <div class="view-course-link is-primary">
Continue Course <img class="ml-3" src="/assets/community/icons/white-arrow.svg" /> Continue Course <img class="ml-3" src="/assets/community/icons/white-arrow.svg" />
</div> </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"> <div class="view-course-link">
View Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" /> View Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
</div> </div>

View File

@@ -10,8 +10,7 @@ class CustomUser(User):
""" """
return frappe.get_all( return frappe.get_all(
'LMS Course', { 'LMS Course', {
'owner': self.name, 'owner': self.name
'is_published': True
}) })
def get_palette(self): def get_palette(self):
@@ -63,16 +62,9 @@ class CustomUser(User):
def get_mentored_courses(self): def get_mentored_courses(self):
""" Returns all courses mentored by this user """ """ Returns all courses mentored by this user """
mentored_courses = [] return frappe.get_all("LMS Course Mentor Mapping",
mapping = frappe.get_all("LMS Course Mentor Mapping",
{ {
"mentor": self.name, "mentor": self.name
}, },
["name", "course"] ["name", "course"]
) )
for map in mapping:
if frappe.db.get_value("LMS Course", map.course, "is_published"):
mentored_courses.append(map)
return mentored_courses

View File

@@ -6,4 +6,3 @@ community.patches.replace_member_with_user_in_batch_membership
community.patches.replace_member_with_user_in_course_mentor_mapping community.patches.replace_member_with_user_in_course_mentor_mapping
community.patches.replace_member_with_user_in_lms_message community.patches.replace_member_with_user_in_lms_message
community.patches.replace_member_with_user_in_mentor_request community.patches.replace_member_with_user_in_mentor_request
community.patches.v0_0.chapter_lesson_index_table

View File

@@ -1,50 +0,0 @@
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc("lms", "doctype", "lms_course")
frappe.reload_doc("lms", "doctype", "chapter")
frappe.reload_doc("lms", "doctype", "lesson")
frappe.reload_doc("lms", "doctype", "lessons")
frappe.reload_doc("lms", "doctype", "chapters")
update_chapters()
update_lessons()
def update_chapters():
courses = frappe.get_all("LMS Course", pluck="name")
for course in courses:
course_details = frappe.get_doc("LMS Course", course)
chapters = frappe.get_all("Chapter",
{
"course": course
},
["name"],
order_by= "index_"
)
for chapter in chapters:
course_details.append("chapters",
{
"chapter": chapter.name
})
course_details.save()
def update_lessons():
chapters = frappe.get_all("Chapter", pluck="name")
for chapter in chapters:
chapter_details = frappe.get_doc("Chapter", chapter)
lessons = frappe.get_all("Lesson",
{
"chapter": chapter
},
["name"],
order_by= "index_"
)
for lesson in lessons:
chapter_details.append("lessons",
{
"lesson": lesson.name
})
chapter_details.save()

View File

@@ -390,7 +390,7 @@ input[type=checkbox] {
letter-spacing: -0.0175em letter-spacing: -0.0175em
} }
@media (min-width: 576px) and (max-width: 992px) { @media (min-width: 576px) {
.container { .container {
padding-left: 1rem; padding-left: 1rem;
padding-right: 1rem; padding-right: 1rem;
@@ -653,14 +653,9 @@ div.custom-checkbox>label>input:checked+img {
color: #FFFFFF; color: #FFFFFF;
} }
.is-default {
background-color: white;
border: 1px solid #C8CFD5;
box-sizing: border-box;
}
.course-home-outline { .course-home-outline {
margin-top: 3rem; margin-top: 3rem;
flex: 1;
} }
.small-title { .small-title {
@@ -678,7 +673,6 @@ div.custom-checkbox>label>input:checked+img {
.chapter-description { .chapter-description {
height: fit-content; height: fit-content;
padding-left: 1rem; padding-left: 1rem;
padding-right: 1rem;
} }
.chapter-icon { .chapter-icon {
@@ -686,39 +680,26 @@ div.custom-checkbox>label>input:checked+img {
} }
.course-outline-instructor-parent { .course-outline-instructor-parent {
display: grid; display: flex;
grid-gap: 2rem; justify-content: space-between;
grid-template-columns: 4fr 1fr;
}
@media (max-width: 768px) {
.course-outline-instructor-parent {
grid-gap: 1rem;
}
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.course-outline-instructor-parent { .course-outline-instructor-parent {
flex-direction: column;
padding: 0px 24px 0px; padding: 0px 24px 0px;
grid-template-columns: none;
} }
} }
.profile-parent-section { .profile-parent-section {
display: grid; display: flex;
grid-gap: 2rem; justify-content: space-between;
grid-template-columns: 4fr 1fr;
}
@media (max-width: 768px) {
.profile-parent-section {
grid-gap: 1rem;
}
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.profile-parent-section { .profile-parent-section {
grid-template-columns: none; flex-direction: column;
} }
} }
@@ -750,6 +731,18 @@ div.custom-checkbox>label>input:checked+img {
margin-top: 3rem; margin-top: 3rem;
} }
@media (min-width: 1024px) {
.course-overview-section {
margin-left: 2rem;
}
}
@media (min-width: 600px) {
.course-overview-section {
margin-left: 1rem;
}
}
.lesson-info { .lesson-info {
font-size: 16px; font-size: 16px;
line-height: 250%; line-height: 250%;
@@ -757,7 +750,7 @@ div.custom-checkbox>label>input:checked+img {
} }
.lesson-links { .lesson-links {
display: flex; display: block;
padding: 0 1rem; padding: 0 1rem;
margin-bottom: .25rem; margin-bottom: .25rem;
color: inherit; color: inherit;
@@ -907,18 +900,14 @@ div.custom-checkbox>label>input:checked+img {
} }
.description-card { .description-card {
padding: 1.5rem; padding: 24px;
flex-direction: column; flex-direction: column;
} }
.overview-card { .overview-card {
padding: 1.5rem; padding: 24px 26px 24px;
width: 256px; width: 256px;
flex-direction: column; flex-direction: column;
display: grid;
-moz-column-gap: 1rem;
column-gap: 1rem;
row-gap: 1rem;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
@@ -951,6 +940,10 @@ div.custom-checkbox>label>input:checked+img {
} }
} }
.overtime-item {
margin: 16px 0px 16px;
}
.view-all-mentors { .view-all-mentors {
width: 100%; width: 100%;
display: flex; display: flex;
@@ -1019,7 +1012,8 @@ div.custom-checkbox>label>input:checked+img {
} }
.course-details-outline { .course-details-outline {
margin-top: 1rem; margin-top: 16px;
flex: 1;
} }
.lesson-content-card { .lesson-content-card {
@@ -1028,15 +1022,14 @@ div.custom-checkbox>label>input:checked+img {
} }
.course-content-parent { .course-content-parent {
display: grid; display: flex;
grid-gap: 2rem; justify-content: space-between;
grid-template-columns: 2fr minmax(600px, 5fr);
} }
@media (max-width: 1024px) { @media (max-width: 768px) {
.course-content-parent { .course-content-parent {
display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
justify-content: center;
} }
} }
@@ -1051,7 +1044,8 @@ div.custom-checkbox>label>input:checked+img {
} }
.lesson-pagination-parent { .lesson-pagination-parent {
margin-top: 1rem; margin: 1rem 0px 0px 2rem;
flex: 3;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
@@ -1135,7 +1129,7 @@ div.custom-checkbox>label>input:checked+img {
line-height: 156%; line-height: 156%;
letter-spacing: -0.0175em; letter-spacing: -0.0175em;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.64); text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.64);
padding: 1.5rem; padding: 20px;
} }
@media (max-width: 375px) { @media (max-width: 375px) {
@@ -1159,7 +1153,7 @@ div.custom-checkbox>label>input:checked+img {
height: fit-content; height: fit-content;
box-shadow: 0px 1px 1px rgb(0 0 0 / 16%); box-shadow: 0px 1px 1px rgb(0 0 0 / 16%);
border-radius: 4px; border-radius: 4px;
margin-top: 2rem; margin-top: 25px;
} }
@media (max-width: 375px) { @media (max-width: 375px) {
@@ -1175,7 +1169,6 @@ div.custom-checkbox>label>input:checked+img {
left: 174px; left: 174px;
font-size: 12px; font-size: 12px;
line-height: 165%; line-height: 165%;
width: fit-content;
} }
@media (max-width: 500px) { @media (max-width: 500px) {
@@ -1193,6 +1186,7 @@ div.custom-checkbox>label>input:checked+img {
} }
.social-icons { .social-icons {
float: right;
margin: 16px; margin: 16px;
} }
@@ -1222,6 +1216,12 @@ div.custom-checkbox>label>input:checked+img {
flex-direction: column; flex-direction: column;
} }
@media (min-width: 600px) {
.course-creator-progress-parent {
margin-left: 2rem;
}
}
.course-creator-section { .course-creator-section {
margin-top: 3rem; margin-top: 3rem;
} }

View File

@@ -11,6 +11,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
{{ widgets.BatchTabs(course=course, membership=membership) }}
<div class="messages-container mt-5"> <div class="messages-container mt-5">
{{ widgets.BatchHeader(batch_name=batch.title, member_count=member_count)}} {{ widgets.BatchHeader(batch_name=batch.title, member_count=member_count)}}
<ol class="messages"> <ol class="messages">

View File

@@ -30,7 +30,7 @@
<div class="lesson-pagination-parent"> <div class="lesson-pagination-parent">
{{ LessonContent(lesson) }} {{ LessonContent(lesson) }}
{% if membership %} {% if membership %}
{{ pagination(prev_url, next_url) }} {{ pagination(prev_chap, prev_url, next_chap, next_url) }}
{% endif %} {% endif %}
</div> </div>
</div> </div>
@@ -49,15 +49,16 @@
{% if membership or lesson.include_in_preview %} {% if membership or lesson.include_in_preview %}
<div class="common-card-style lesson-content-card from-markdown">{{ lesson.render_html() }}</div> <div class="common-card-style lesson-content-card from-markdown">{{ lesson.render_html() }}</div>
{% else %} {% else %}
<div class="common-card-style lesson-content-card"> <div class="no-preview-message">
<span>This lesson is not available for Preview. Please join the course to access this lesson. <a href="/courses/{{ course.name }}">Checkout Course Details.</a></span> <span>This lesson is not available for Preview. Please join the course to access this lesson.</span>
<a href="/courses/{{ course.name }}">Checkout Course Details.</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>
{% endmacro %} {% endmacro %}
{% macro pagination(prev_url, next_url) %} {% macro pagination(prev_chap, prev_url, next_chap, next_url) %}
<div class="lesson-pagination"> <div class="lesson-pagination">
<div> <div>

View File

@@ -12,6 +12,7 @@ def get_context(context):
lesson_index = frappe.form_dict.get("lesson") lesson_index = frappe.form_dict.get("lesson")
lesson_number = f"{chapter_index}.{lesson_index}" lesson_number = f"{chapter_index}.{lesson_index}"
course_name = context.course.name
if not chapter_index or not lesson_index: if not chapter_index or not lesson_index:
if context.batch: if context.batch:
index_ = get_lesson_index(context.course, context.batch, frappe.session.user) or "1.1" index_ = get_lesson_index(context.course, context.batch, frappe.session.user) or "1.1"
@@ -20,12 +21,20 @@ def get_context(context):
frappe.local.flags.redirect_location = context.course.get_learn_url(index_) + context.course.query_parameter frappe.local.flags.redirect_location = context.course.get_learn_url(index_) + context.course.query_parameter
raise frappe.Redirect raise frappe.Redirect
context.lesson = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))[0] context.lesson = context.course.get_lesson(chapter_index, lesson_index)
neighbours = context.course.get_neighbours(lesson_number, context.lessons) context.lesson_index = lesson_index
context.next_url = get_learn_url(neighbours["next"], context.course) context.chapter_index = chapter_index
context.prev_url = get_learn_url(neighbours["prev"], context.course)
outline = context.course.get_outline()
prev_ = outline.get_prev(lesson_number)
next_ = outline.get_next(lesson_number)
context.prev_chap = get_chapter_title(course_name, prev_)
context.next_chap = get_chapter_title(course_name, next_)
context.next_url = context.course.get_learn_url(next_) and context.course.get_learn_url(next_) + context.course.query_parameter
context.prev_url = context.course.get_learn_url(prev_) and context.course.get_learn_url(prev_) + context.course.query_parameter
context.page_extensions = get_page_extensions() context.page_extensions = get_page_extensions()
context.page_context = { context.page_context = {
"course": context.course.name, "course": context.course.name,
"batch": context.get("batch") and context.batch.name, "batch": context.get("batch") and context.batch.name,
@@ -33,9 +42,6 @@ def get_context(context):
"is_member": context.membership is not None "is_member": context.membership is not None
} }
def get_learn_url(lesson_number, course):
return course.get_learn_url(lesson_number) and course.get_learn_url(lesson_number) + course.query_parameter
def get_chapter_title(course_name, lesson_number): def get_chapter_title(course_name, lesson_number):
if not lesson_number: if not lesson_number:
return return

View File

@@ -10,12 +10,12 @@ def get_common_context(context):
except KeyError: except KeyError:
batch_name = None batch_name = None
course = frappe.get_doc("LMS Course", course_name) course = Course.find(course_name)
if not course: if not course:
context.template = "www/404.html" context.template = "www/404.html"
return return
context.course = course context.course = course
context.lessons = course.get_lessons()
membership = course.get_membership(frappe.session.user, batch_name) membership = course.get_membership(frappe.session.user, batch_name)
context.membership = membership context.membership = membership
if membership: if membership:

View File

@@ -1,4 +1,5 @@
import frappe import frappe
from community.lms.models import Course
def get_context(context): def get_context(context):
context.no_cache = 1 context.no_cache = 1
@@ -9,7 +10,7 @@ def get_context(context):
frappe.local.flags.redirect_location = "/courses" frappe.local.flags.redirect_location = "/courses"
raise frappe.Redirect raise frappe.Redirect
course = frappe.get_doc("LMS Course", course_name) course = Course.find(course_name)
if course is None: if course is None:
frappe.local.flags.redirect_location = "/courses" frappe.local.flags.redirect_location = "/courses"
raise frappe.Redirect raise frappe.Redirect

View File

@@ -29,11 +29,10 @@
</div> </div>
</div> </div>
<div class="profile-info"> <div class="profile-info">
<div class="profile-profession">
{% if member.profession %} {% if member.profession %}
<span class=""> {{ member.profession }} </span> <span class="profile-profession"> {{ member.profession }} </span>
{% endif %} {% endif %}
<span class="social-icons"> <div class="social-icons">
{% if member.linkedin %} {% if member.linkedin %}
<a class="linkedin" href="{{ member.linkedin }}"> <a class="linkedin" href="{{ member.linkedin }}">
<img src="/assets/community/images/linkedin.png"> <img src="/assets/community/images/linkedin.png">
@@ -49,7 +48,6 @@
<img src="/assets/community/icons/github.svg"> <img src="/assets/community/icons/github.svg">
</a> </a>
{% endif %} {% endif %}
</span>
</div> </div>
</div> </div>
</div> </div>