Compare commits
12 Commits
quiz-clean
...
username-f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66aace247c | ||
|
|
bc3db06960 | ||
|
|
d5067a4bcd | ||
|
|
04d44510de | ||
|
|
844fcc9bca | ||
|
|
145b5efab0 | ||
|
|
4079ed97b9 | ||
|
|
63d70fc037 | ||
|
|
ce86b5deda | ||
|
|
037e946bbe | ||
|
|
a51c8de1eb | ||
|
|
53dc517180 |
@@ -1,5 +1,5 @@
|
|||||||
{% set color = member.get_palette() %}
|
{% set color = member.get_palette() %}
|
||||||
<a href="/{{member.username}}">
|
<a class="button-links" href="/{{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 %}
|
||||||
<img class="avatar-frame standard-image" style="object-fit: cover;" src="{{ member.user_image }}" title="{{ member.full_name }}">
|
<img class="avatar-frame standard-image" style="object-fit: cover;" src="{{ member.user_image }}" title="{{ member.full_name }}">
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
"fieldname": "member_type",
|
"fieldname": "member_type",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 1,
|
||||||
"label": "Member Type",
|
"label": "Member Type",
|
||||||
"options": "\nStudent\nMentor\nStaff"
|
"options": "\nStudent\nMentor\nStaff"
|
||||||
},
|
},
|
||||||
@@ -44,7 +45,6 @@
|
|||||||
"default": "Member",
|
"default": "Member",
|
||||||
"fieldname": "role",
|
"fieldname": "role",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"in_standard_filter": 1,
|
|
||||||
"label": "Role",
|
"label": "Role",
|
||||||
"options": "\nMember\nAdmin"
|
"options": "\nMember\nAdmin"
|
||||||
},
|
},
|
||||||
@@ -63,9 +63,10 @@
|
|||||||
{
|
{
|
||||||
"fetch_from": "batch.course",
|
"fetch_from": "batch.course",
|
||||||
"fieldname": "course",
|
"fieldname": "course",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Course"
|
"label": "Course",
|
||||||
|
"options": "LMS Course"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "current_lesson",
|
"fieldname": "current_lesson",
|
||||||
@@ -83,7 +84,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-07-06 20:50:46.885325",
|
"modified": "2021-08-04 17:10:42.708479",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Batch Membership",
|
"name": "LMS Batch Membership",
|
||||||
|
|||||||
@@ -74,8 +74,11 @@ class LMSCourse(Document):
|
|||||||
mentors = frappe.get_all("LMS Course Mentor Mapping", {"course": self.name}, ["mentor"])
|
mentors = frappe.get_all("LMS Course Mentor Mapping", {"course": self.name}, ["mentor"])
|
||||||
for mentor in mentors:
|
for mentor in mentors:
|
||||||
member = frappe.get_doc("User", mentor.mentor)
|
member = frappe.get_doc("User", mentor.mentor)
|
||||||
# TODO: change this to count query
|
member.batch_count = frappe.db.count("LMS Batch Membership",
|
||||||
member.batch_count = len(frappe.get_all("LMS Batch Membership", {"member": member.name, "member_type": "Mentor"}))
|
{
|
||||||
|
"member": member.name,
|
||||||
|
"member_type": "Mentor"
|
||||||
|
})
|
||||||
course_mentors.append(member)
|
course_mentors.append(member)
|
||||||
return course_mentors
|
return course_mentors
|
||||||
|
|
||||||
@@ -191,7 +194,13 @@ class LMSCourse(Document):
|
|||||||
"""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.db.get_value("Lessons", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True)
|
||||||
|
if not lesson:
|
||||||
|
return None
|
||||||
|
|
||||||
chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True)
|
chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True)
|
||||||
|
if not chapter:
|
||||||
|
return None
|
||||||
|
|
||||||
return f"{chapter.idx}.{lesson.idx}"
|
return f"{chapter.idx}.{lesson.idx}"
|
||||||
|
|
||||||
def reindex_exercises(self):
|
def reindex_exercises(self):
|
||||||
@@ -238,21 +247,6 @@ class LMSCourse(Document):
|
|||||||
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
|
membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title")
|
||||||
return all_memberships
|
return all_memberships
|
||||||
|
|
||||||
def get_mentors(self, batch=None):
|
|
||||||
filters = {
|
|
||||||
"course": self.name,
|
|
||||||
"member_type": "Mentor"
|
|
||||||
}
|
|
||||||
if batch:
|
|
||||||
filters["batch"] = batch
|
|
||||||
|
|
||||||
memberships = frappe.get_all(
|
|
||||||
"LMS Batch Membership",
|
|
||||||
filters,
|
|
||||||
["member"])
|
|
||||||
member_names = [m['member'] for m in memberships]
|
|
||||||
return find_all("User", name=["IN", member_names])
|
|
||||||
|
|
||||||
def get_students(self, batch=None):
|
def get_students(self, batch=None):
|
||||||
"""Returns (email, full_name, username) of all the students of this batch as a list of dict.
|
"""Returns (email, full_name, username) of all the students of this batch as a list of dict.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
frappe.ready(function () {
|
frappe.ready(function () {
|
||||||
|
|
||||||
frappe.web_form.after_load = () => {
|
frappe.web_form.after_load = () => {
|
||||||
if (!frappe.utils.get_url_arg("name")) {
|
if (!frappe.utils.get_url_arg("name")) {
|
||||||
window.location.href = `/edit-profile?name=${frappe.session.user}`;
|
window.location.href = `/edit-profile?name=${frappe.session.user}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frappe.web_form.after_save = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = `/${frappe.web_form.get_value(["username"])}`;
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"apply_document_permissions": 0,
|
"apply_document_permissions": 0,
|
||||||
"breadcrumbs": "",
|
"breadcrumbs": "",
|
||||||
"button_label": "Save",
|
"button_label": "Save",
|
||||||
|
"client_script": "",
|
||||||
"creation": "2021-06-30 13:48:13.682851",
|
"creation": "2021-06-30 13:48:13.682851",
|
||||||
"custom_css": "[data-doctype=\"Web Form\"] {\n max-width: 720px;\n margin: 6rem auto;\n}",
|
"custom_css": "[data-doctype=\"Web Form\"] {\n max-width: 720px;\n margin: 6rem auto;\n}",
|
||||||
"doc_type": "User",
|
"doc_type": "User",
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"login_required": 1,
|
"login_required": 1,
|
||||||
"max_attachment_size": 0,
|
"max_attachment_size": 0,
|
||||||
"modified": "2021-07-14 17:15:15.424855",
|
"modified": "2021-08-06 14:40:39.013776",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "profile",
|
"name": "profile",
|
||||||
@@ -72,6 +73,18 @@
|
|||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"show_in_filter": 0
|
"show_in_filter": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "username",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Username",
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"show_in_filter": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_read_on_all_link_options": 0,
|
"allow_read_on_all_link_options": 0,
|
||||||
"description": "Get your globally recognized avatar from Gravatar.com",
|
"description": "Get your globally recognized avatar from Gravatar.com",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
{{ lesson.title }}
|
{{ lesson.title }}
|
||||||
|
|
||||||
{% if membership %}
|
{% if membership %}
|
||||||
<img class="lesson-progress-tick {{ course.get_progress(lesson.name) != 'Complete' and 'hide' }}"
|
<img class="ml-1 lesson-progress-tick {{ course.get_progress(lesson.name) != 'Complete' and 'hide' }}"
|
||||||
src="/assets/community/icons/check.svg">
|
src="/assets/community/icons/check.svg">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
<div class="batch">
|
|
||||||
<div class="batch-details">
|
|
||||||
<div class="">Session every {{batch.sessions_on}}</div>
|
|
||||||
<div>{{frappe.utils.format_time(batch.start_time, "short")}} -
|
|
||||||
{{frappe.utils.format_time(batch.end_time, "short")}}
|
|
||||||
</div>
|
|
||||||
<div>Starting {{frappe.utils.format_date(batch.start_date, "medium")}}</div>
|
|
||||||
<div class="course-type" style="color: #888; padding: 10px 0px;">mentors</div>
|
|
||||||
|
|
||||||
{% for m in course.get_mentors(batch.name) %}
|
|
||||||
<div>
|
|
||||||
{{ widgets.Avatar(member=m, avatar_class="avatar-medium" ) }}
|
|
||||||
<span class="instructor-title">{{m.full_name}}</span>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% if can_manage or can_join %}
|
|
||||||
<div class="cta">
|
|
||||||
<div class="">
|
|
||||||
{% if can_manage %}
|
|
||||||
<a href="/courses/{{ course.name }}/home?batch={{ batch.name }}" class="btn btn-primary manage-batch" data-batch="{{ batch.name | urlencode }}"
|
|
||||||
data-course="{{ course.name | urlencode }}">Manage</a>
|
|
||||||
{% elif can_join %}
|
|
||||||
<button class="join-batch btn btn-secondary" data-batch="{{ batch.name | urlencode }}"
|
|
||||||
data-course="{{ course.name | urlencode }}">Join this Batch</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
@@ -18,9 +18,11 @@
|
|||||||
<div class="review-card-footer">
|
<div class="review-card-footer">
|
||||||
<div>
|
<div>
|
||||||
{{ widgets.Avatar(member=review.owner_details, avatar_class="avatar-medium") }}
|
{{ widgets.Avatar(member=review.owner_details, avatar_class="avatar-medium") }}
|
||||||
<span class="course-instructor">
|
<a class="button-links" href="/{{review.owner_details.username}}">
|
||||||
{{ review.owner_details.full_name }}
|
<span class="course-instructor">
|
||||||
</span>
|
{{ review.owner_details.full_name }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="rating">
|
<div class="rating">
|
||||||
{% for i in [1, 2, 3, 4, 5] %}
|
{% for i in [1, 2, 3, 4, 5] %}
|
||||||
|
|||||||
63
community/overrides/test_user.py
Normal file
63
community/overrides/test_user.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Copyright (c) 2021, FOSS United and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
class TestCustomUser(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_with_basic_username(self):
|
||||||
|
new_user = frappe.get_doc({
|
||||||
|
"doctype": "User",
|
||||||
|
"email": "test_with_basic_username@example.com",
|
||||||
|
"first_name": "Username"
|
||||||
|
}).insert()
|
||||||
|
self.assertEqual(new_user.username, "username")
|
||||||
|
|
||||||
|
def test_without_username(self):
|
||||||
|
""" The user in this test has the same first name as the user of the test test_with_basic_username.
|
||||||
|
In such cases frappe makes the username of the second user empty.
|
||||||
|
The condition in community app should override this and save a username. """
|
||||||
|
new_user = frappe.get_doc({
|
||||||
|
"doctype": "User",
|
||||||
|
"email": "test-without-username@example.com",
|
||||||
|
"first_name": "Username"
|
||||||
|
}).insert()
|
||||||
|
self.assertTrue(new_user.username)
|
||||||
|
|
||||||
|
def test_with_illegal_characters(self):
|
||||||
|
new_user = frappe.get_doc({
|
||||||
|
"doctype": "User",
|
||||||
|
"email": "test_with_illegal_characters@example.com",
|
||||||
|
"first_name": "Username$$"
|
||||||
|
}).insert()
|
||||||
|
self.assertEqual(new_user.username[:8], "username")
|
||||||
|
|
||||||
|
def test_with_underscore_at_end(self):
|
||||||
|
new_user = frappe.get_doc({
|
||||||
|
"doctype": "User",
|
||||||
|
"email": "test_with_underscore_at_end@example.com",
|
||||||
|
"first_name": "Username___"
|
||||||
|
}).insert()
|
||||||
|
self.assertNotEqual(new_user.username[-1], "_")
|
||||||
|
|
||||||
|
|
||||||
|
def test_with_short_first_name(self):
|
||||||
|
new_user = frappe.get_doc({
|
||||||
|
"doctype": "User",
|
||||||
|
"email": "test_with_short_first_name@example.com",
|
||||||
|
"first_name": "USN"
|
||||||
|
}).insert()
|
||||||
|
self.assertGreaterEqual(len(new_user.username), 4)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls) -> None:
|
||||||
|
users = [
|
||||||
|
"test_with_basic_username@example.com",
|
||||||
|
"test-without-username@example.com",
|
||||||
|
"test_with_illegal_characters@example.com",
|
||||||
|
"test_with_underscore_at_end@example.com",
|
||||||
|
"test_with_short_first_name@example.com"
|
||||||
|
]
|
||||||
|
frappe.db.delete("User", {"name": ["in", users]})
|
||||||
@@ -2,9 +2,57 @@ import frappe
|
|||||||
from frappe.core.doctype.user.user import User
|
from frappe.core.doctype.user.user import User
|
||||||
from frappe.utils import cint
|
from frappe.utils import cint
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
class CustomUser(User):
|
class CustomUser(User):
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
super(CustomUser, self).validate()
|
||||||
|
self.validate_username_characters()
|
||||||
|
|
||||||
|
def validate_username_characters(self):
|
||||||
|
if len(self.username):
|
||||||
|
underscore_condition = self.username[0] == "_" or self.username[-1] == "_"
|
||||||
|
else:
|
||||||
|
underscore_condition = ''
|
||||||
|
|
||||||
|
if self.is_new():
|
||||||
|
if not self.username:
|
||||||
|
self.username = self.get_username_from_first_name()
|
||||||
|
|
||||||
|
if self.username.find(" "):
|
||||||
|
self.username.replace(" ", "")
|
||||||
|
|
||||||
|
if not re.match("^[A-Za-z0-9_]*$", self.username) or underscore_condition:
|
||||||
|
self.username = self.remove_illegal_characters()
|
||||||
|
|
||||||
|
if len(self.username) < 4:
|
||||||
|
self.username = self.email.replace("@", "").replace(".", "")
|
||||||
|
|
||||||
|
while self.username_exists():
|
||||||
|
self.username = self.remove_illegal_characters() + str(random.randint(0, 99))
|
||||||
|
|
||||||
|
else:
|
||||||
|
if not self.username:
|
||||||
|
frappe.throw(_("Username already exists."))
|
||||||
|
|
||||||
|
if not re.match("^[A-Za-z0-9_]*$", self.username):
|
||||||
|
frappe.throw(_("Username can only contain alphabets, numbers and unedrscore."))
|
||||||
|
|
||||||
|
if underscore_condition:
|
||||||
|
frappe.throw(_("First and Last character of username cannot be Underscore(_)."))
|
||||||
|
|
||||||
|
if len(self.username) < 4:
|
||||||
|
frappe.throw(_("Username cannot be less than 4 characters"))
|
||||||
|
|
||||||
|
def get_username_from_first_name(self):
|
||||||
|
return frappe.scrub(self.first_name) + str(random.randint(0, 99))
|
||||||
|
|
||||||
|
def remove_illegal_characters(self):
|
||||||
|
return re.sub("[^\w]+", "", self.username).strip("_")
|
||||||
|
|
||||||
def get_authored_courses(self) -> int:
|
def get_authored_courses(self) -> int:
|
||||||
"""Returns the number of courses authored by this user.
|
"""Returns the number of courses authored by this user.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -780,7 +780,7 @@ input[type=checkbox] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lesson-links {
|
.lesson-links {
|
||||||
display: flex;
|
display: block;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
margin-bottom: .25rem;
|
margin-bottom: .25rem;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@@ -794,6 +794,13 @@ input[type=checkbox] {
|
|||||||
border-radius: .25rem;
|
border-radius: .25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.course-content-parent .lesson-links {
|
||||||
|
padding: 0 0 0 1rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
.chapter-content {
|
.chapter-content {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-left: .875rem;
|
margin-left: .875rem;
|
||||||
@@ -1214,7 +1221,19 @@ input[type=checkbox] {
|
|||||||
left: 174px;
|
left: 174px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 165%;
|
line-height: 165%;
|
||||||
width: fit-content;
|
width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.profile-profession {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.profile-profession {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
@@ -1228,6 +1247,7 @@ input[type=checkbox] {
|
|||||||
.profile-profession {
|
.profile-profession {
|
||||||
top: 5px;
|
top: 5px;
|
||||||
left: 70px;
|
left: 70px;
|
||||||
|
width: 75%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
<div class="questions">
|
<div class="questions">
|
||||||
{% for question in quiz.questions %}
|
{% for question in quiz.questions %}
|
||||||
<div class="question {% if loop.index == 1 %} active-question {% else %} hide {% endif %}"
|
<div class="question {% if loop.index == 1 %} active-question {% else %} hide {% endif %}"
|
||||||
data-question="{{ question.question }}"data-multi="{{ question.multiple}}" data-qt-index="{{ loop.index }}">
|
data-question="{{ question.question }}" data-multi="{{ question.multiple}}" data-qt-index="{{ loop.index }}">
|
||||||
<p>{{ question.question }}</p>
|
<p>{{ frappe.utils.md_to_html(question.question) }}</p>
|
||||||
|
|
||||||
{% if question.multiple %}
|
{% if question.multiple %}
|
||||||
<small class="font-weight-bold">Choose all answers that apply:</small>
|
<small class="font-weight-bold">Choose all answers that apply:</small>
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ var mark_active_question = (e = undefined) => {
|
|||||||
$(".current-question").text(`${next_index}`);
|
$(".current-question").text(`${next_index}`);
|
||||||
$("#check").removeClass("hide").attr("disabled", true);
|
$("#check").removeClass("hide").attr("disabled", true);
|
||||||
$("#next").addClass("hide");
|
$("#next").addClass("hide");
|
||||||
|
$(".explanation").addClass("hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
var mark_progress = (e) => {
|
var mark_progress = (e) => {
|
||||||
|
|||||||
@@ -17,10 +17,9 @@ def get_context(context):
|
|||||||
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"
|
||||||
else:
|
else:
|
||||||
index_ = "1.1"
|
index_ = "1.1"
|
||||||
frappe.local.flags.redirect_location = context.course.get_learn_url(index_) + context.course.query_parameter
|
utils.redirect_to_lesson(context.course, index_)
|
||||||
raise frappe.Redirect
|
|
||||||
|
|
||||||
context.lesson = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))[0]
|
context.lesson = get_current_lesson_details(lesson_number, context)
|
||||||
neighbours = context.course.get_neighbours(lesson_number, context.lessons)
|
neighbours = context.course.get_neighbours(lesson_number, context.lessons)
|
||||||
context.next_url = get_learn_url(neighbours["next"], context.course)
|
context.next_url = get_learn_url(neighbours["next"], context.course)
|
||||||
context.prev_url = get_learn_url(neighbours["prev"], context.course)
|
context.prev_url = get_learn_url(neighbours["prev"], context.course)
|
||||||
@@ -40,6 +39,12 @@ def get_context(context):
|
|||||||
"is_member": context.membership is not None
|
"is_member": context.membership is not None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_current_lesson_details(lesson_number, context):
|
||||||
|
details_list = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))
|
||||||
|
if not len(details_list):
|
||||||
|
utils.redirect_to_lesson(context.course)
|
||||||
|
return details_list[0]
|
||||||
|
|
||||||
def get_learn_url(lesson_number, course):
|
def get_learn_url(lesson_number, course):
|
||||||
return course.get_learn_url(lesson_number) and course.get_learn_url(lesson_number) + course.query_parameter
|
return course.get_learn_url(lesson_number) and course.get_learn_url(lesson_number) + course.query_parameter
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ def get_common_context(context):
|
|||||||
if batch:
|
if batch:
|
||||||
context.batch = batch
|
context.batch = batch
|
||||||
|
|
||||||
context.members = course.get_mentors(membership.batch) + course.get_students(membership.batch)
|
|
||||||
context.member_count = len(context.members)
|
|
||||||
|
|
||||||
context.course.query_parameter = "?batch=" + membership.batch if membership and membership.batch else ""
|
context.course.query_parameter = "?batch=" + membership.batch if membership and membership.batch else ""
|
||||||
context.livecode_url = get_livecode_url()
|
context.livecode_url = get_livecode_url()
|
||||||
|
|
||||||
|
|||||||
@@ -102,24 +102,33 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ widgets.MemberCard(member=course.get_instructor(), show_course_count=True, dimension_class="member-card-large") }}
|
{{ widgets.MemberCard(member=course.get_instructor(), show_course_count=True, dimension_class="member-card-large") }}
|
||||||
</div>
|
</div>
|
||||||
{% if course.get_course_progress() %}
|
{% set progress = course.get_course_progress() %}
|
||||||
|
{% if progress %}
|
||||||
<div class="course-progress-section">
|
<div class="course-progress-section">
|
||||||
<div class="course-home-headings">
|
<div class="course-home-headings">
|
||||||
Your Progress
|
Your Progress
|
||||||
</div>
|
</div>
|
||||||
<div class="common-card-style progress-card">
|
<div class="common-card-style progress-card">
|
||||||
<p class="small-title">
|
<p class="small-title">
|
||||||
|
{% if progress != 100 %}
|
||||||
Great work so far!
|
Great work so far!
|
||||||
|
{% else %}
|
||||||
|
Excellent Work on completing this course 👏
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p class="progress-text">
|
<p class="progress-text">
|
||||||
|
{% if progress != 100 %}
|
||||||
Challenge yourself to complete the lessons and grow professionally.
|
Challenge yourself to complete the lessons and grow professionally.
|
||||||
|
{% else %}
|
||||||
|
You have reached a new level in your journey to success!
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<div class="progress-percentage">
|
<div class="progress-percentage">
|
||||||
{{ frappe.utils.rounded(course.get_course_progress()) }}%
|
{{ frappe.utils.rounded(progress) }}%
|
||||||
</div>
|
</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="progress-bar" role="progressbar" style="width: {{ course.get_course_progress() }}%"
|
<div class="progress-bar" role="progressbar" style="width: {{ progress }}%"
|
||||||
aria-valuenow="{{ course.get_course_progress() }}" aria-valuemin="0" aria-valuemax="100"></div>
|
aria-valuenow="{{ progress }}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -187,55 +196,3 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro BatchSection(course) %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-8 col-md-12">
|
|
||||||
{% if course.is_mentor(frappe.session.user) %}
|
|
||||||
{{ BatchSectionForMentors(course, course.get_batches(mentor=frappe.session.user)) }}
|
|
||||||
{% else %}
|
|
||||||
{{ BatchSectionForStudents(course, course.get_upcoming_batches()) }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
{% macro BatchSectionForMentors(course, mentor_batches) %}
|
|
||||||
<h2>Your Batches</h2>
|
|
||||||
|
|
||||||
{% if mentor_batches %}
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
{% for batch in mentor_batches %}
|
|
||||||
<div class="col-lg-4 col-md-6">
|
|
||||||
{{ widgets.RenderBatch(course=course, batch=batch, can_manage=True) }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a class="add-batch margin-bottom" href="/add-a-new-batch?new=1&course={{course.name}}">Add a new batch</a>
|
|
||||||
{% else %}
|
|
||||||
<div class="mentor_message">
|
|
||||||
<p>
|
|
||||||
You are a mentor for this course.
|
|
||||||
</p>
|
|
||||||
<a class="" href="/add-a-new-batch?new=1&course={{course.name}}">Create your first batch</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% macro BatchSectionForStudents(course, upcoming_batches) %}
|
|
||||||
{% if upcoming_batches %}
|
|
||||||
<div class="mt-5">
|
|
||||||
<h3 class="upcoming">Upcoming Batches</h3>
|
|
||||||
<div class="row">
|
|
||||||
{% for batch in upcoming_batches %}
|
|
||||||
<div class="col-lg-4 col-md-6">
|
|
||||||
{{ widgets.RenderBatch(course=course, batch=batch, can_join=True) }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="mt-5 upcoming">There are no Upcoming Batches for this course currently.</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|||||||
@@ -35,21 +35,24 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="social-icons">
|
<span class="social-icons">
|
||||||
{% if member.linkedin %}
|
{% if member.linkedin %}
|
||||||
<a class="linkedin" href="{{ member.linkedin }}">
|
<a class="linkedin button-links" href="{{ member.linkedin }}">
|
||||||
<img src="/assets/community/images/linkedin.png">
|
<img src="/assets/community/images/linkedin.png">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if member.medium %}
|
{% if member.medium %}
|
||||||
<a class="medium" href="{{ member.medium}}">
|
<a class="medium button-links" href="{{ member.medium}}">
|
||||||
<img src="/assets/community/icons/medium.svg">
|
<img src="/assets/community/icons/medium.svg">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if member.github %}
|
{% if member.github %}
|
||||||
<a class="github" href="{{ member.github }}">
|
<a class="github button-links" href="{{ member.github }}">
|
||||||
<img src="/assets/community/icons/github.svg">
|
<img src="/assets/community/icons/github.svg">
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
{% if frappe.session.user == member.email %}
|
||||||
|
<a class="dark-links pull-right" href="edit-profile?name={{ member.email }}">Edit Profile</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user