Compare commits
10 Commits
only-show-
...
chapter-le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a667643681 | ||
|
|
f278e4b6a5 | ||
|
|
33a12c2dec | ||
|
|
508f90f459 | ||
|
|
709f0c2274 | ||
|
|
be47700e7c | ||
|
|
40842830a4 | ||
|
|
11d070fa0d | ||
|
|
dd2f830a33 | ||
|
|
324033e9ee |
@@ -2,7 +2,15 @@
|
|||||||
// 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,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
"course",
|
"course",
|
||||||
"title",
|
"title",
|
||||||
"description",
|
"description",
|
||||||
"locked",
|
"lessons"
|
||||||
"index_"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -24,12 +23,6 @@
|
|||||||
"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",
|
||||||
@@ -38,10 +31,10 @@
|
|||||||
"options": "LMS Course"
|
"options": "LMS Course"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "1",
|
"fieldname": "lessons",
|
||||||
"fieldname": "index_",
|
"fieldtype": "Table",
|
||||||
"fieldtype": "Int",
|
"label": "Lessons",
|
||||||
"label": "Index"
|
"options": "Lessons"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
@@ -52,7 +45,7 @@
|
|||||||
"link_fieldname": "chapter"
|
"link_fieldname": "chapter"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-05-13 21:05:20.531890",
|
"modified": "2021-07-27 16:28:08.667964",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "Chapter",
|
"name": "Chapter",
|
||||||
|
|||||||
@@ -5,15 +5,6 @@
|
|||||||
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):
|
||||||
def get_lessons(self):
|
pass
|
||||||
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)
|
|
||||||
|
|||||||
0
community/lms/doctype/chapters/__init__.py
Normal file
0
community/lms/doctype/chapters/__init__.py
Normal file
32
community/lms/doctype/chapters/chapters.json
Normal file
32
community/lms/doctype/chapters/chapters.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
8
community/lms/doctype/chapters/chapters.py
Normal file
8
community/lms/doctype/chapters/chapters.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
"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",
|
||||||
@@ -31,13 +30,6 @@
|
|||||||
"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",
|
||||||
@@ -75,7 +67,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-06-29 13:34:49.077363",
|
"modified": "2021-07-27 16:28:29.203624",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "Lesson",
|
"name": "Lesson",
|
||||||
|
|||||||
0
community/lms/doctype/lessons/__init__.py
Normal file
0
community/lms/doctype/lessons/__init__.py
Normal file
31
community/lms/doctype/lessons/lessons.json
Normal file
31
community/lms/doctype/lessons/lessons.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
8
community/lms/doctype/lessons/lessons.py
Normal file
8
community/lms/doctype/lessons/lessons.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
||||||
@@ -2,7 +2,15 @@
|
|||||||
// 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,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
{
|
{
|
||||||
"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",
|
||||||
@@ -21,16 +15,17 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"title",
|
"title",
|
||||||
"short_code",
|
|
||||||
"video_link",
|
"video_link",
|
||||||
"column_break_3",
|
|
||||||
"is_published",
|
|
||||||
"disable_self_learning",
|
|
||||||
"image",
|
"image",
|
||||||
"section_break_5",
|
"column_break_3",
|
||||||
"tags",
|
"tags",
|
||||||
|
"is_published",
|
||||||
|
"upcoming",
|
||||||
|
"disable_self_learning",
|
||||||
|
"section_break_5",
|
||||||
"short_introduction",
|
"short_introduction",
|
||||||
"description"
|
"description",
|
||||||
|
"chapters"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -53,11 +48,6 @@
|
|||||||
"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"
|
||||||
@@ -92,6 +82,18 @@
|
|||||||
"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,
|
||||||
@@ -111,14 +113,9 @@
|
|||||||
"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-09 15:05:05.372430",
|
"modified": "2021-07-28 19:01:50.677445",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Course",
|
"name": "LMS Course",
|
||||||
@@ -141,6 +138,5 @@
|
|||||||
"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
|
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,10 @@ 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.
|
||||||
@@ -112,17 +114,42 @@ class LMSCourse(Document):
|
|||||||
def get_chapters(self):
|
def get_chapters(self):
|
||||||
"""Returns all chapters of this course.
|
"""Returns all chapters of this course.
|
||||||
"""
|
"""
|
||||||
# TODO: chapters should have a way to specify the order
|
chapters = []
|
||||||
return find_all("Chapter", course=self.name, order_by="index_")
|
for row in self.chapters:
|
||||||
|
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):
|
def get_lessons(self, chapter=None):
|
||||||
""" Returns all lessons of this course """
|
""" If chapter is passed, returns lessons of only that chapter.
|
||||||
|
Else returns lessons of all chapters of the course """
|
||||||
lessons = []
|
lessons = []
|
||||||
chapters = self.get_chapters()
|
|
||||||
for chapter in chapters:
|
if chapter:
|
||||||
lessons.append(frappe.get_all("Lesson", {"chapter": chapter.name}))
|
return self.get_lesson_details(chapter)
|
||||||
|
|
||||||
|
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())
|
||||||
@@ -160,38 +187,12 @@ 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.get_doc("Lesson", lesson_name)
|
lesson = frappe.db.get_value("Lessons", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True)
|
||||||
chapter = frappe.get_doc("Chapter", lesson.chapter)
|
chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True)
|
||||||
return f"{chapter.index_}.{lesson.index_}"
|
return f"{chapter.idx}.{lesson.idx}"
|
||||||
|
|
||||||
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):
|
||||||
@@ -202,7 +203,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 c.get_lessons():
|
for lesson in self.get_lessons(c):
|
||||||
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}"
|
||||||
@@ -302,9 +303,6 @@ 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",
|
||||||
{
|
{
|
||||||
@@ -314,55 +312,14 @@ class LMSCourse(Document):
|
|||||||
},
|
},
|
||||||
["status"])
|
["status"])
|
||||||
|
|
||||||
class CourseOutline:
|
def get_neighbours(self, current, lessons):
|
||||||
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 self.lessons)
|
numbers = sorted(lesson.number for lesson in 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):
|
||||||
|
|||||||
@@ -27,12 +27,13 @@
|
|||||||
"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-06-23 17:58:57.642873",
|
"modified": "2021-07-23 19:06:12.551633",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Quiz",
|
"name": "LMS Quiz",
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
<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 %}
|
|
||||||
@@ -1,26 +1,28 @@
|
|||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div class="small-title chapter-title" data-target="#{{ chapter.get_slugified_chapter_title() }}"
|
<div class="small-title chapter-title" data-target="#{{ course.get_slugified_chapter_title(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="{{ chapter.get_slugified_chapter_title() }}">
|
<div class="chapter-content collapse navbar-collapse" id="{{ course.get_slugified_chapter_title(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 chapter.get_lessons() %}
|
{% for lesson in course.get_lessons(chapter) %}
|
||||||
|
|
||||||
<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(course.get_lesson_index(lesson.name)) }}{{course.query_parameter}}"
|
href="{{ course.get_learn_url(lesson.number) }}{{course.query_parameter}}"
|
||||||
data-course="{{ course.name }}">
|
data-course="{{ course.name }}">
|
||||||
{{ lesson.title }}
|
{{ lesson.title }}
|
||||||
|
|
||||||
|
|||||||
@@ -53,15 +53,19 @@
|
|||||||
|
|
||||||
{% 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 membership %}
|
{% if course.upcoming %}
|
||||||
|
<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>
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ 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
|
||||||
|
|||||||
50
community/patches/v0_0/chapter_lesson_index_table.py
Normal file
50
community/patches/v0_0/chapter_lesson_index_table.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
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()
|
||||||
@@ -653,6 +653,12 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -751,7 +757,7 @@ div.custom-checkbox>label>input:checked+img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lesson-links {
|
.lesson-links {
|
||||||
display: block;
|
display: flex;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
margin-bottom: .25rem;
|
margin-bottom: .25rem;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@@ -1129,7 +1135,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: 20px;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 375px) {
|
@media (max-width: 375px) {
|
||||||
@@ -1153,7 +1159,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: 25px;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 375px) {
|
@media (max-width: 375px) {
|
||||||
@@ -1169,6 +1175,7 @@ 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) {
|
||||||
@@ -1186,7 +1193,6 @@ div.custom-checkbox>label>input:checked+img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.social-icons {
|
.social-icons {
|
||||||
float: right;
|
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
{% 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">
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<div class="lesson-pagination-parent">
|
<div class="lesson-pagination-parent">
|
||||||
{{ LessonContent(lesson) }}
|
{{ LessonContent(lesson) }}
|
||||||
{% if membership %}
|
{% if membership %}
|
||||||
{{ pagination(prev_chap, prev_url, next_chap, next_url) }}
|
{{ pagination(prev_url, next_url) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,16 +49,15 @@
|
|||||||
{% 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="no-preview-message">
|
<div class="common-card-style lesson-content-card">
|
||||||
<span>This lesson is not available for Preview. Please join the course to access this lesson.</span>
|
<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>
|
||||||
<a href="/courses/{{ course.name }}">Checkout Course Details.</a>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro pagination(prev_chap, prev_url, next_chap, next_url) %}
|
{% macro pagination(prev_url, next_url) %}
|
||||||
<div class="lesson-pagination">
|
<div class="lesson-pagination">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ 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"
|
||||||
@@ -21,20 +20,12 @@ 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 = context.course.get_lesson(chapter_index, lesson_index)
|
context.lesson = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))[0]
|
||||||
context.lesson_index = lesson_index
|
neighbours = context.course.get_neighbours(lesson_number, context.lessons)
|
||||||
context.chapter_index = chapter_index
|
context.next_url = get_learn_url(neighbours["next"], context.course)
|
||||||
|
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,
|
||||||
@@ -42,6 +33,9 @@ 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
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ def get_common_context(context):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
batch_name = None
|
batch_name = None
|
||||||
|
|
||||||
course = Course.find(course_name)
|
course = frappe.get_doc("LMS Course", 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:
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
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
|
||||||
@@ -10,7 +9,7 @@ def get_context(context):
|
|||||||
frappe.local.flags.redirect_location = "/courses"
|
frappe.local.flags.redirect_location = "/courses"
|
||||||
raise frappe.Redirect
|
raise frappe.Redirect
|
||||||
|
|
||||||
course = Course.find(course_name)
|
course = frappe.get_doc("LMS Course", 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
|
||||||
|
|||||||
@@ -20,34 +20,36 @@
|
|||||||
{% macro ProfileBanner(member) %}
|
{% macro ProfileBanner(member) %}
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="profile-banner" style="background-image: url(/assets/community/images/profile-banner.png)">
|
<div class="profile-banner" style="background-image: url(/assets/community/images/profile-banner.png)">
|
||||||
<div class="profile-avatar">
|
<div class="profile-avatar">
|
||||||
{{ widgets.Avatar(member=member, avatar_class="avatar-xl") }}
|
{{ widgets.Avatar(member=member, avatar_class="avatar-xl") }}
|
||||||
<div class="profile-name"> {{ member.full_name }} </div>
|
<div class="profile-name"> {{ member.full_name }} </div>
|
||||||
{% if member.get_authored_courses() | length %}
|
{% if member.get_authored_courses() | length %}
|
||||||
<div class="creator-badge"> Creator </div>
|
<div class="creator-badge"> Creator </div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile-info">
|
<div class="profile-info">
|
||||||
{% if member.profession %}
|
<div class="profile-profession">
|
||||||
<span class="profile-profession"> {{ member.profession }} </span>
|
{% if member.profession %}
|
||||||
{% endif %}
|
<span class=""> {{ member.profession }} </span>
|
||||||
<div class="social-icons">
|
|
||||||
{% if member.linkedin %}
|
|
||||||
<a class="linkedin" href="{{ member.linkedin }}">
|
|
||||||
<img src="/assets/community/images/linkedin.png">
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if member.medium %}
|
|
||||||
<a class="medium" href="{{ member.medium}}">
|
|
||||||
<img src="/assets/community/icons/medium.svg">
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if member.github %}
|
|
||||||
<a class="github" href="{{ member.github }}">
|
|
||||||
<img src="/assets/community/icons/github.svg">
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="social-icons">
|
||||||
|
{% if member.linkedin %}
|
||||||
|
<a class="linkedin" href="{{ member.linkedin }}">
|
||||||
|
<img src="/assets/community/images/linkedin.png">
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.medium %}
|
||||||
|
<a class="medium" href="{{ member.medium}}">
|
||||||
|
<img src="/assets/community/icons/medium.svg">
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if member.github %}
|
||||||
|
<a class="github" href="{{ member.github }}">
|
||||||
|
<img src="/assets/community/icons/github.svg">
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user