fix: conflicts

This commit is contained in:
pateljannat
2021-09-21 12:38:43 +05:30
23 changed files with 116 additions and 35 deletions

View File

@@ -1,5 +1,6 @@
{ {
"actions": [], "actions": [],
"allow_rename": 1,
"autoname": "format:{####} {title}", "autoname": "format:{####} {title}",
"creation": "2021-05-03 05:49:08.383057", "creation": "2021-05-03 05:49:08.383057",
"doctype": "DocType", "doctype": "DocType",
@@ -38,7 +39,7 @@
"fieldname": "lessons", "fieldname": "lessons",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Lessons", "label": "Lessons",
"options": "Lessons" "options": "Lesson Reference"
}, },
{ {
"fieldname": "column_break_3", "fieldname": "column_break_3",
@@ -57,10 +58,11 @@
"link_fieldname": "chapter" "link_fieldname": "chapter"
} }
], ],
"modified": "2021-08-31 10:43:45.866864", "modified": "2021-09-20 10:58:47.241660",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Chapter", "name": "Chapter",
"naming_rule": "Expression",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@@ -23,7 +23,7 @@
"modified": "2021-07-27 16:25:02.903245", "modified": "2021-07-27 16:25:02.903245",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Chapters", "name": "Chapter Reference",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"sort_field": "modified", "sort_field": "modified",

View File

@@ -4,5 +4,5 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class Lessons(Document): class ChapterReference(Document):
pass pass

View File

@@ -1,5 +1,6 @@
{ {
"actions": [], "actions": [],
"allow_rename": 1,
"autoname": "format:{####} {title}", "autoname": "format:{####} {title}",
"creation": "2021-05-03 06:21:12.995987", "creation": "2021-05-03 06:21:12.995987",
"doctype": "DocType", "doctype": "DocType",
@@ -70,10 +71,11 @@
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-08-31 10:44:14.168257", "modified": "2021-09-20 10:52:29.116536",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Lesson", "name": "Lesson",
"naming_rule": "Expression",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@@ -23,7 +23,7 @@
"modified": "2021-08-31 10:44:42.048232", "modified": "2021-08-31 10:44:42.048232",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "Lessons", "name": "Lesson Reference",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"sort_field": "modified", "sort_field": "modified",

View File

@@ -4,5 +4,5 @@
# import frappe # import frappe
from frappe.model.document import Document from frappe.model.document import Document
class Chapters(Document): class LessonReference(Document):
pass pass

View File

@@ -100,7 +100,7 @@
"fieldname": "chapters", "fieldname": "chapters",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Chapters", "label": "Chapters",
"options": "Chapters" "options": "Chapter Reference"
}, },
{ {
"fieldname": "instructor", "fieldname": "instructor",
@@ -160,9 +160,14 @@
"group": "Mentors", "group": "Mentors",
"link_doctype": "LMS Course Mentor Mapping", "link_doctype": "LMS Course Mentor Mapping",
"link_fieldname": "course" "link_fieldname": "course"
},
{
"group": "Interests",
"link_doctype": "LMS Course Interest",
"link_fieldname": "course"
} }
], ],
"modified": "2021-08-25 11:04:57.211898", "modified": "2021-09-20 12:00:18.325579",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Course", "name": "LMS Course",

View File

@@ -176,7 +176,7 @@ class LMSCourse(Document):
def get_lesson_details(self, chapter): def get_lesson_details(self, chapter):
lessons = [] lessons = []
lesson_list = frappe.get_all("Lessons", {"parent": chapter.name}, lesson_list = frappe.get_all("Lesson Reference", {"parent": chapter.name},
["lesson", "idx"], order_by="idx") ["lesson", "idx"], order_by="idx")
for row in lesson_list: for row in lesson_list:
lesson_details = frappe.get_doc("Lesson", row.lesson) lesson_details = frappe.get_doc("Lesson", row.lesson)
@@ -213,7 +213,7 @@ class LMSCourse(Document):
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.db.get_value("Lesson Reference", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True)
if not lesson: if not lesson:
return None return None

View File

@@ -1,5 +1,6 @@
{ {
"actions": [], "actions": [],
"allow_rename": 1,
"autoname": "field:title", "autoname": "field:title",
"creation": "2021-06-07 10:50:17.893625", "creation": "2021-06-07 10:50:17.893625",
"doctype": "DocType", "doctype": "DocType",
@@ -33,10 +34,11 @@
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-07-23 19:06:12.551633", "modified": "2021-09-20 10:44:15.930892",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Quiz", "name": "LMS Quiz",
"naming_rule": "By fieldname",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@@ -21,7 +21,7 @@
<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 or is_instructor %} {% if membership or lesson.include_in_preview %}
<a class="lesson-links" href="{{ course.get_learn_url(lesson.number) }}{{course.query_parameter}}" <a class="lesson-links" href="{{ course.get_learn_url(lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}"> data-course="{{ course.name }}">
{{ lesson.title }} {{ lesson.title }}
@@ -33,6 +33,15 @@
</a> </a>
{% elif is_instructor and not lesson.include_in_preview %}
<a class="lesson-links"
title="This lesson is not available for preview but as an instructor you can access it."
href="{{ course.get_learn_url(lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}">
{{ lesson.title }}
<img class="ml-2" src="/assets/community/icons/lock.svg">
</a>
{% else %} {% else %}
<div class="no-preview" title="This lesson is not available for preview"> <div class="no-preview" title="This lesson is not available for preview">
<div class="lesson-links"> <div class="lesson-links">

View File

@@ -1,16 +1,15 @@
{% if not course.upcoming %} {% if not course.upcoming %}
<div class="reviews-parent"> <div class="reviews-parent">
{% set reviews = course.get_reviews() %} {% set reviews = course.get_reviews() %}
{% if reviews | length or course.is_eligible_to_review(membership) %}
<div class="mb-5"> <div class="mb-5">
<span class="course-home-headings">Reviews</span> <span class="course-home-headings">Reviews</span>
{% if course.is_eligible_to_review(membership) %} {% if course.is_eligible_to_review(membership) and reviews | length %}
<span class="review-link button is-secondary pull-right"> <span class="review-link button is-secondary pull-right">
Write a review Write a review
</span> </span>
{% endif %} {% endif %}
</div> </div>
{% endif %}
{% if reviews | length %} {% if reviews | length %}
<div class="reviews-section"> <div class="reviews-section">
{% for review in reviews %} {% for review in reviews %}
@@ -36,9 +35,20 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% else %} {% else %}
<div class="common-card-style thread-card"> <div class="common-card-style thread-card">
<span class="text-center"> No Reviews <img src="/assets/community/icons/slash.svg"></span> <div class="w-25 text-center" style="margin: 0 auto;">
<span class="font-weight-bold"> No Reviews </span>
<div class="small">
There are no reviews for this course.
</div>
{% if course.is_eligible_to_review(membership) %}
<span class="review-link button is-secondary ml-auto mr-auto mt-3">
Write a review
</span>
{% endif %}
</div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
@@ -48,7 +58,7 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<div class="course-home-headings modal-headings">Review</div> <div class="font-weight-bold">Write a Review</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>

View File

@@ -18,6 +18,8 @@ class CustomUser(User):
else: else:
underscore_condition = '' underscore_condition = ''
regex = re.compile('[@!#$%^&*()<>?/\|}{~:-]')
if self.is_new(): if self.is_new():
if not self.username: if not self.username:
self.username = self.get_username_from_first_name() self.username = self.get_username_from_first_name()
@@ -25,7 +27,7 @@ class CustomUser(User):
if self.username.find(" "): if self.username.find(" "):
self.username.replace(" ", "") self.username.replace(" ", "")
if not re.match("^[A-Za-z0-9_]*$", self.username) or underscore_condition: if regex.search(self.username) or underscore_condition:
self.username = self.remove_illegal_characters() self.username = self.remove_illegal_characters()
if len(self.username) < 4: if len(self.username) < 4:
@@ -38,8 +40,8 @@ class CustomUser(User):
if not self.username: if not self.username:
frappe.throw(_("Username already exists.")) frappe.throw(_("Username already exists."))
if not re.match("^[A-Za-z0-9_]*$", self.username): if regex.search(self.username):
frappe.throw(_("Username can only contain alphabets, numbers and unedrscore.")) frappe.throw(_("Username can only contain alphabets, numbers and underscore."))
if underscore_condition: if underscore_condition:
frappe.throw(_("First and Last character of username cannot be Underscore(_).")) frappe.throw(_("First and Last character of username cannot be Underscore(_)."))

View File

@@ -31,7 +31,7 @@ def get_profile_url_prefix():
hooks = frappe.get_hooks("profile_url_prefix") or ["/users/"] hooks = frappe.get_hooks("profile_url_prefix") or ["/users/"]
return hooks[-1] return hooks[-1]
RE_USERNAME = re.compile("[a-zA-Z0-9_]{4,}") RE_INVALID_USERNAME = re.compile("[@!#$%^&*()<>?/\\|}{~:-]")
class ProfileRedirectPage(BaseRenderer): class ProfileRedirectPage(BaseRenderer):
"""Renderer to redirect /profile_/foo to <profile_prefix>/foo. """Renderer to redirect /profile_/foo to <profile_prefix>/foo.
@@ -63,9 +63,8 @@ class ProfilePage(BaseRenderer):
# not a userpage? # not a userpage?
username = self.get_username() username = self.get_username()
if not RE_USERNAME.match(username): if RE_INVALID_USERNAME.search(username):
return False return False
# if there is prefix then we can allow all usernames # if there is prefix then we can allow all usernames
if prefix: if prefix:
return True return True

View File

@@ -11,3 +11,4 @@ execute:frappe.delete_doc("DocType", "LMS Message")
community.patches.v0_0.course_instructor_update community.patches.v0_0.course_instructor_update
execute:frappe.delete_doc("DocType", "Discussion Message") execute:frappe.delete_doc("DocType", "Discussion Message")
execute:frappe.delete_doc("DocType", "Discussion Thread") execute:frappe.delete_doc("DocType", "Discussion Thread")
community.patches.v0_0.rename_chapters_and_lessons_doctype

View File

@@ -0,0 +1,32 @@
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", "chapter_reference")
frappe.reload_doc("lms", "doctype", "lesson_reference")
if not frappe.db.count("Chapter Reference"):
move_chapters()
if not frappe.db.count("Lesson Reference"):
move_lessons()
def move_chapters():
docs = frappe.get_all("Chapters", fields=["*"])
for doc in docs:
keys = doc
keys.update({"doctype": "Chapter Reference"})
del keys["name"]
frappe.get_doc(keys).save()
def move_lessons():
docs = frappe.get_all("Lessons", fields=["*"])
for doc in docs:
keys = doc
keys.update({"doctype": "Lesson Reference"})
del keys["name"]
frappe.get_doc(keys).save()

View File

@@ -330,6 +330,11 @@ input[type=checkbox] {
.quiz-label { .quiz-label {
margin-bottom: 0; margin-bottom: 0;
cursor: pointer;
}
.quiz-label p {
display: inline;
} }
.course-card-wide { .course-card-wide {
@@ -519,7 +524,7 @@ input[type=checkbox] {
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
padding-bottom: 0.5rem; padding-bottom: 1rem;
} }
.chapter-description { .chapter-description {
@@ -637,7 +642,7 @@ input[type=checkbox] {
.course-outline { .course-outline {
flex-direction: column; flex-direction: column;
padding: 16px 12px 16px; padding: 1rem 0.75rem 0;
} }
.lessons { .lessons {
@@ -881,8 +886,8 @@ input[type=checkbox] {
.question { .question {
flex-direction: column; flex-direction: column;
width: 688px; width: 85%;
margin: auto; margin: 0 auto;
} }
.question p { .question p {
@@ -919,6 +924,10 @@ input[type=checkbox] {
flex-direction: column; flex-direction: column;
} }
.lesson-content-card .alert-dismissible .close {
padding: 0.5rem;
}
.course-content-parent { .course-content-parent {
display: grid; display: grid;
grid-gap: 2rem; grid-gap: 2rem;

View File

@@ -29,8 +29,8 @@
data-correct="{{ question['is_correct_' + loop.index | string] }}" {% if question.multiple %} data-correct="{{ question['is_correct_' + loop.index | string] }}" {% if question.multiple %}
type="checkbox" {% else %} type="radio" name="{{ question.question | urlencode }}" {% endif %}> type="checkbox" {% else %} type="radio" name="{{ question.question | urlencode }}" {% endif %}>
<img class="empty-checkbox mr-3" /> <img class="empty-checkbox mr-3" />
<span class="label-area">{{ frappe.utils.md_to_html(option) }}</span>
</label> </label>
<span class="label-area">{{ frappe.utils.md_to_html(option) }}</span>
</div> </div>
{% set explanation = question['explanation_' + loop.index | string] %} {% set explanation = question['explanation_' + loop.index | string] %}

View File

@@ -45,11 +45,18 @@
{% if membership or lesson.include_in_preview or is_instructor %} {% if membership or lesson.include_in_preview or is_instructor %}
<div class="common-card-style lesson-content-card markdown-source">{{ lesson.render_html() }}</div> <div class="common-card-style lesson-content-card markdown-source">
{% if is_instructor %}
<small class="alert alert-secondary alert-dismissible">
This lesson is not available for preview. As you are the Instructor of the course only you can see it.
<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
</small>
{% endif %}
{{ lesson.render_html() }}</div>
{% else %} {% else %}
<div class="common-card-style lesson-content-card"> <div class="common-card-style lesson-content-card">
<div class="w-25 text-center" style="margin: 0 auto;"> <div class="w-25 text-center" style="margin: 0 auto;">
<small>This lesson is not available for preview. Please join the course to access this lesson.</small> <small>This lesson is not available for preview. Please join the course to access it.</small>
<a class="button is-primary ml-auto mr-auto mt-3" href="/courses/{{ course.name }}"> Start Learning </a> <a class="button is-primary ml-auto mr-auto mt-3" href="/courses/{{ course.name }}"> Start Learning </a>
</div> </div>
</div> </div>

View File

@@ -169,7 +169,8 @@ var parse_options = () => {
} }
var add_icon = (element, icon) => { var add_icon = (element, icon) => {
$(element).parent().empty().html(`<img class="mr-3" src="/assets/community/icons/${icon}.svg">`); var label = $(element).parent().find(".label-area p").text();
$(element).parent().empty().html(`<img class="mr-3" src="/assets/community/icons/${icon}.svg"> ${label}`);
} }
var add_to_local_storage = (quiz_name, current_index, answer, is_correct) => { var add_to_local_storage = (quiz_name, current_index, answer, is_correct) => {

View File

@@ -11,7 +11,7 @@ def get_context(context):
} }
def get_courses(): def get_courses():
course_names = frappe.get_all("LMS Course", filters={"is_published": True}, pluck="name") course_names = frappe.get_all("LMS Course", filters={"is_published": True}, order_by="upcoming", pluck="name")
courses = [] courses = []
for course in course_names: for course in course_names:
courses.append(frappe.get_doc("LMS Course", course)) courses.append(frappe.get_doc("LMS Course", course))

View File

@@ -1,5 +1,6 @@
import frappe import frappe
from community.page_renderers import get_profile_url_prefix from community.page_renderers import get_profile_url_prefix
from urllib.parse import urlencode
def get_context(context): def get_context(context):
context.no_cache = 1 context.no_cache = 1
@@ -9,14 +10,13 @@ def get_context(context):
except KeyError: except KeyError:
username = frappe.db.get_value("User", frappe.session.user, ["username"]) username = frappe.db.get_value("User", frappe.session.user, ["username"])
if username: if username:
frappe.local.flags.redirect_location = get_profile_url_prefix() + username frappe.local.flags.redirect_location = get_profile_url_prefix() + urlencode({"username": username})
raise frappe.Redirect raise frappe.Redirect
try: try:
context.member = frappe.get_doc("User", {"username": username}) context.member = frappe.get_doc("User", {"username": username})
except: except:
context.template = "www/404.html" context.template = "www/404.html"
return return
context.profile_tabs = get_profile_tabs(context.member) context.profile_tabs = get_profile_tabs(context.member)
def get_profile_tabs(user): def get_profile_tabs(user):