Compare commits

..

3 Commits

Author SHA1 Message Date
pateljannat
04d44510de fix: redirect after edit profile save 2021-08-06 14:41:37 +05:30
pateljannat
844fcc9bca fix: username validations 2021-08-06 14:41:11 +05:30
pateljannat
63d70fc037 fix: username space and empty validations 2021-08-05 15:51:21 +05:30
9 changed files with 121 additions and 25 deletions

View File

@@ -194,13 +194,7 @@ 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):

View File

@@ -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"])}`;
})
}
}) })

View File

@@ -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",

View File

@@ -27,7 +27,7 @@
{{ lesson.title }} {{ lesson.title }}
{% if membership %} {% if membership %}
<img class="ml-1 lesson-progress-tick {{ course.get_progress(lesson.name) != 'Complete' and 'hide' }}" <img class="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 %}

View File

@@ -0,0 +1,54 @@
# 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_hyphen_at_end(self):
new_user = frappe.get_doc({
"doctype": "User",
"email": "test_with_hyphen_at_end@example.com",
"first_name": "Username---"
}).insert()
length = len(new_user.username)
self.assertNotEqual(new_user.username[length-1], "-")
@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_hyphen_at_end@example.com"
]
frappe.db.delete("User", {"name": ["in", users]})

View File

@@ -2,9 +2,50 @@ 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 self.is_new():
if self.username.find(" "):
self.username.replace(" ", "")
if not re.match("^[A-Za-z0-9_]*$", self.username):
self.username = self.remove_illegal_characters()
if not self.username:
self.username = self.get_username_from_first_name()
if self.username_exists():
self.username = self.remove_illegal_characters() + str(random.randint(0, 99))
else:
if not re.match("^[A-Za-z0-9_-]*$", self.username):
frappe.throw(_("Username can only contain alphabets, numbers, hyphen and underscore."))
if self.username[0] == "-" or self.username[len(self.username) - 1] == "-":
frappe.throw(_("First and Last character of username cannot be Hyphen(-)."))
def get_username_from_first_name(self):
return frappe.scrub(self.first_name) + str(random.randint(0, 99))
def remove_illegal_characters(self):
username = ''.join([c for c in self.username if c.isalnum() or c in ['-', '_']])
while username[0] == "-" or username[len(username) - 1] == "-":
if username[0] == "-":
username = username[1:]
if username[len(username) - 1]:
username = username[:1]
return username
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.
""" """

View File

@@ -780,7 +780,7 @@ input[type=checkbox] {
} }
.lesson-links { .lesson-links {
display: block; display: flex;
padding: 0 1rem; padding: 0 1rem;
margin-bottom: .25rem; margin-bottom: .25rem;
color: inherit; color: inherit;
@@ -794,13 +794,6 @@ 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;

View File

@@ -58,7 +58,6 @@ 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) => {

View File

@@ -17,9 +17,10 @@ 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"
utils.redirect_to_lesson(context.course, index_) frappe.local.flags.redirect_location = context.course.get_learn_url(index_) + context.course.query_parameter
raise frappe.Redirect
context.lesson = get_current_lesson_details(lesson_number, context) context.lesson = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))[0]
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)
@@ -39,12 +40,6 @@ 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