diff --git a/community/community/doctype/community_member/community_member.json b/community/community/doctype/community_member/community_member.json index d82d2fd7..5047e257 100644 --- a/community/community/doctype/community_member/community_member.json +++ b/community/community/doctype/community_member/community_member.json @@ -11,15 +11,15 @@ "email", "enabled", "column_break_4", - "role", - "short_intro", + "username", + "email_preference", "section_break_7", "bio", "section_break_9", - "username", + "role", "photo", "column_break_12", - "email_preference", + "short_intro", "route", "abbr" ], @@ -77,8 +77,10 @@ "unique": 1 }, { + "allow_in_quick_entry": 1, "fieldname": "username", "fieldtype": "Data", + "in_list_view": 1, "label": "User Name", "unique": 1 }, @@ -111,10 +113,9 @@ "read_only": 1 } ], - "has_web_view": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2021-04-16 10:22:46.837311", + "modified": "2021-04-28 11:22:35.402217", "modified_by": "Administrator", "module": "Community", "name": "Community Member", diff --git a/community/community/doctype/community_member/community_member.py b/community/community/doctype/community_member/community_member.py index 411a475c..0f022828 100644 --- a/community/community/doctype/community_member/community_member.py +++ b/community/community/doctype/community_member/community_member.py @@ -4,12 +4,12 @@ from __future__ import unicode_literals import frappe -from frappe.website.website_generator import WebsiteGenerator import re from frappe import _ -from frappe.model.rename_doc import rename_doc +from frappe.model.document import Document +import random -class CommunityMember(WebsiteGenerator): +class CommunityMember(Document): def validate(self): self.validate_username() @@ -18,6 +18,9 @@ class CommunityMember(WebsiteGenerator): self.route = self.username def validate_username(self): + if not self.username: + self.username = create_username_from_email(self.email) + if self.username: if len(self.username) < 4: frappe.throw(_("Username must be atleast 4 characters long.")) @@ -29,12 +32,33 @@ class CommunityMember(WebsiteGenerator): return f"" def create_member_from_user(doc, method): + username = doc.username + + if ( doc.username and username_exists(doc.username)) or not doc.username: + username = create_username_from_email(doc.email) + + elif len(doc.username) < 4: + username = adjust_username(doc.username) + + if username_exists(username): + username = username + str(random.randint(0,9)) + member = frappe.get_doc({ "doctype": "Community Member", "full_name": doc.full_name, - "username": doc.username if len(doc.username) > 3 else ("").join([ s for s in doc.full_name.split() ]), + "username": username, "email": doc.email, "route": doc.username, "owner": doc.email }) member.save(ignore_permissions=True) + +def username_exists(username): + return frappe.db.exists("Community Member", dict(username=username)) + +def create_username_from_email(email): + string = email.split("@")[0] + return ''.join(e for e in string if e.isalnum()) + +def adjust_username(username): + return username.ljust(4, str(random.randint(0,9))) \ No newline at end of file diff --git a/community/community/doctype/community_member/test_community_member.py b/community/community/doctype/community_member/test_community_member.py index c28a96ed..4cde095c 100644 --- a/community/community/doctype/community_member/test_community_member.py +++ b/community/community/doctype/community_member/test_community_member.py @@ -2,9 +2,91 @@ # Copyright (c) 2021, Frappe and Contributors # See license.txt from __future__ import unicode_literals - -# import frappe +from community.lms.doctype.lms_course.test_lms_course import new_user +import frappe import unittest class TestCommunityMember(unittest.TestCase): - pass + + @classmethod + def setUpClass(self): + users = ["test_user@example.com","test_user1@example.com"] + + for user in users: + if not frappe.db.exists("User", user): + new_user("Test User", user) + + def test_member_created_from_user(self): + user = frappe.db.get_value("User","test_user@example.com", ["full_name", "email", "username"], as_dict=True) + self.assertTrue(frappe.db.exists("Community Member", {"username":user.username})) + + member = frappe.db.get_value("Community Member", + filters={"email": user.email}, + fieldname=["full_name", "email", "owner", "username", "route"], + as_dict=True + ) + + self.assertEqual(user.full_name, member.full_name) + self.assertEqual(member.owner, user.email) + self.assertEqual(user.username, member.username) + self.assertEqual(member.username, member.route) + + def test_members_with_same_name(self): + user1 = frappe.db.get_value("User","test_user@example.com", ["email"], as_dict=True) + user2 = frappe.get_doc("User","test_user1@example.com", ["email"], as_dict=True) + + self.assertTrue(frappe.db.exists("Community Member", {"email": user1.email} )) + self.assertTrue(frappe.db.exists("Community Member", {"email": user2.email })) + + member1 = frappe.db.get_value("Community Member", + filters={"email": user1.email}, + fieldname=["full_name", "email", "owner", "username", "route"], + as_dict=True + ) + member2 = frappe.db.get_value("Community Member", + filters={"email": user2.email}, + fieldname=["full_name", "email", "owner", "username", "route"], + as_dict=True + ) + + self.assertEqual(member1.full_name, member2.full_name) + self.assertEqual(member1.email, user1.email) + self.assertEqual(member2.email, user2.email) + self.assertNotEqual(member1.username, member2.username) + + def test_username_validations(self): + user = new_user("Tst", "tst@example.com") + self.assertTrue(frappe.db.exists("Community Member", {"email":user.email} )) + + member = frappe.db.get_value("Community Member", + filters={"email": user.email}, + fieldname=["username"], + as_dict=True + ) + + self.assertEqual(len(member.username), 4) + frappe.delete_doc("User", user.email) + + def test_user_without_username(self): + user = new_user("Test User", "test_user2@example.com") + self.assertTrue(frappe.db.exists("Community Member", {"email":user.email} )) + + member = frappe.db.get_value("Community Member", + filters={"email": user.email}, + fieldname=["username"], + as_dict=True + ) + + self.assertTrue(member.username) + frappe.delete_doc("User", user.email) + + @classmethod + def tearDownClass(self): + users = ["test_user@example.com","test_user1@example.com"] + + for user in users: + if frappe.db.exists("User", user): + frappe.delete_doc("User", user) + + if frappe.db.exists("Community Member", {"email": user}): + frappe.delete_doc("Community Member", {"email": user}) \ No newline at end of file diff --git a/community/community/utils.py b/community/community/utils.py index 4522ffd9..ccc3ad48 100644 --- a/community/community/utils.py +++ b/community/community/utils.py @@ -7,7 +7,6 @@ def create_members_from_users(): doc = frappe.get_doc("User", {"email": user.email}) username = doc.username if doc.username and len(doc.username) > 3 else ("").join([ s for s in doc.full_name.split() ]) if not frappe.db.exists("Community Member", username): - print(doc.email, username) member = frappe.new_doc("Community Member") member.full_name = doc.full_name member.username = username diff --git a/community/hooks.py b/community/hooks.py index 0727f9ca..abaedcb0 100644 --- a/community/hooks.py +++ b/community/hooks.py @@ -94,7 +94,10 @@ web_include_css = "/assets/css/community.css" doc_events = { "User": { "after_insert": "community.community.doctype.community_member.community_member.create_member_from_user" - } + }, + "LMS Message": { + "after_insert": "community.lms.doctype.lms_message.lms_message.publish_message" + } } # Scheduled Tasks diff --git a/community/lms/doctype/lms_batch/lms_batch.py b/community/lms/doctype/lms_batch/lms_batch.py index 1943ed9f..ad5c32b1 100644 --- a/community/lms/doctype/lms_batch/lms_batch.py +++ b/community/lms/doctype/lms_batch/lms_batch.py @@ -36,5 +36,4 @@ def save_message(message, batch): "author": get_member_with_email(), "message": message }) - doc.save(ignore_permissions=True) - return doc \ No newline at end of file + doc.save(ignore_permissions=True) \ No newline at end of file diff --git a/community/lms/doctype/lms_course/test_lms_course.py b/community/lms/doctype/lms_course/test_lms_course.py index 42a6366b..2f50829b 100644 --- a/community/lms/doctype/lms_course/test_lms_course.py +++ b/community/lms/doctype/lms_course/test_lms_course.py @@ -11,7 +11,6 @@ class TestLMSCourse(unittest.TestCase): frappe.db.sql('delete from `tabLMS Course Mentor Mapping`') frappe.db.sql('delete from `tabLMS Course`') frappe.db.sql('delete from `tabCommunity Member`') - frappe.db.sql('delete from `tabUser` where email like "%@example.com"') def new_course(self, title): doc = frappe.get_doc({ @@ -21,28 +20,31 @@ class TestLMSCourse(unittest.TestCase): doc.insert() return doc - def new_user(self, name, email): - doc = frappe.get_doc(dict( - doctype='User', - email=email, - first_name=name)) - doc.insert() - return doc - def test_new_course(self): course = self.new_course("Test Course") assert course.title == "Test Course" assert course.slug == "test-course" assert course.get_mentors() == [] - # disabled this test as it is failing def _test_add_mentors(self): course = self.new_course("Test Course") assert course.get_mentors() == [] - user = self.new_user("Tester", "tester@example.com") + user = new_user("Tester", "tester@example.com") course.add_mentor("tester@example.com") mentors = course.get_mentors() mentors_data = [dict(email=mentor.email, batch_count=mentor.batch_count) for mentor in mentors] assert mentors_data == [{"email": "tester@example.com", "batch_count": 0}] + + def tearDown(self): + if frappe.db.exists("User", "tester@example.com"): + frappe.delete_doc("User", "tester@example.com") + +def new_user(name, email): + doc = frappe.get_doc(dict( + doctype='User', + email=email, + first_name=name)) + doc.insert() + return doc \ No newline at end of file diff --git a/community/lms/doctype/lms_message/lms_message.json b/community/lms/doctype/lms_message/lms_message.json index 929aac4c..38bc417b 100644 --- a/community/lms/doctype/lms_message/lms_message.json +++ b/community/lms/doctype/lms_message/lms_message.json @@ -58,7 +58,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-04-26 16:11:20.142164", + "modified": "2021-04-28 10:17:57.618127", "modified_by": "Administrator", "module": "LMS", "name": "LMS Message", @@ -80,5 +80,6 @@ "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", + "title_field": "author", "track_changes": 1 } \ No newline at end of file diff --git a/community/lms/doctype/lms_message/lms_message.py b/community/lms/doctype/lms_message/lms_message.py index 68b15143..c3b2d012 100644 --- a/community/lms/doctype/lms_message/lms_message.py +++ b/community/lms/doctype/lms_message/lms_message.py @@ -7,11 +7,12 @@ import frappe from frappe.model.document import Document from frappe import _ from frappe.utils import add_days, nowdate +from community.www.courses.utils import get_batch_members + class LMSMessage(Document): - def after_insert(self): - frappe.publish_realtime("new_lms_message", {"message":"JJannat"}, user="Administrator") - self.send_email() - + """ def after_insert(self): + self.send_email() """ + def send_email(self): membership = frappe.get_all("LMS Batch Membership", {"batch": self.batch}, ["member"]) for entry in membership: @@ -60,4 +61,44 @@ def send_daily_digest(): "batches": group_by_batch }, delayed = False - ) \ No newline at end of file + ) + +def publish_message(doc, method): + email = frappe.db.get_value("Community Member", doc.author, "email") + template = get_message_template() + message = frappe._dict() + message.author_name = doc.author_name + message.message_time = frappe.utils.pretty_date(doc.creation) + message.message = frappe.utils.md_to_html(doc.message) + + js = """ + $(".msger-input").val(""); + var template = `{0}`; + var message = {1}; + var session_user = ("{2}" == frappe.session.user) ? true : false; + message.author_name = session_user ? "You" : message.author_name + message.is_author = session_user; + template = frappe.render_template(template, {{ + "message": message + }}) + $(".message-section").append(template); + """.format(template, message, email) + + frappe.publish_realtime(event="eval_js", message=js, after_commit=True) + +def get_message_template(): + return """ +
+
+
+ {{ message.author_name }} +
+
+ {{ message.message_time }} +
+
+
+ {{ message.message }} +
+
+ """ \ No newline at end of file diff --git a/community/public/css/style.css b/community/public/css/style.css index 89ebfa13..bf157299 100644 --- a/community/public/css/style.css +++ b/community/public/css/style.css @@ -290,4 +290,5 @@ nav.navbar { .message-section { margin-left: 5%; + display: inline-block; } \ No newline at end of file diff --git a/community/www/courses/course.js b/community/www/courses/course.js index a0996a2e..79683fde 100644 --- a/community/www/courses/course.js +++ b/community/www/courses/course.js @@ -1,15 +1,4 @@ frappe.ready(() => { - frappe.require("/assets/frappe/js/lib/socket.io.min.js"); - frappe.require("/assets/frappe/js/frappe/socketio_client.js"); - if (window.dev_server) { - frappe.boot.socketio_port = "9000" //use socketio port shown when bench starts - } - frappe.socketio.init(); - console.log(frappe.socketio) - //frappe.socketio.emittedDemo("mydata"); - frappe.realtime.on("new_lms_message", (data) => { - console.log(data) - }) if (frappe.session.user != "Guest") { frappe.call({ 'method': 'community.lms.doctype.lms_mentor_request.lms_mentor_request.has_requested', @@ -25,21 +14,6 @@ frappe.ready(() => { }) } - $(".list-batch").click((e) => { - var batch = decodeURIComponent($(e.currentTarget).attr("data-label")) - $(".current-batch").text(batch) - $(".send-message").attr("data-batch", batch) - frappe.call("community.www.courses.course.get_messages", { batch: batch }, (data) => { - if (data.message) { - $(".discussions").children().remove(); - for (var i = 0; i < data.message.length; i++) { - var element = add_message(data.message[i]) - $(".discussions").append(element); - } - } - }) - }) - $(".apply-now").click((e) => { if (frappe.session.user == "Guest") { window.location.href = "/login"; @@ -94,19 +68,4 @@ frappe.ready(() => { }) }) }) -/* -var show_enrollment_badge = () => { - $(".btn-enroll").addClass("hide"); - $(".enrollment-badge").removeClass("hide"); -} - -var get_search_params = () => { - return new URLSearchParams(window.location.search) -} - -$('.btn-enroll').on('click', (e) => { - frappe.call('community.www.courses.course.enroll', { course: get_search_params().get("course") }, (data) => { - show_enrollment_badge() - }); -}); */ diff --git a/community/www/courses/discuss/index.html b/community/www/courses/discuss/index.html index 31301ce7..6c8c124b 100644 --- a/community/www/courses/discuss/index.html +++ b/community/www/courses/discuss/index.html @@ -35,7 +35,6 @@
{{ message.message }}
- {% endfor %} {% endmacro %} diff --git a/community/www/courses/discuss/index.js b/community/www/courses/discuss/index.js index 64ab83b5..d6380ac2 100644 --- a/community/www/courses/discuss/index.js +++ b/community/www/courses/discuss/index.js @@ -1,22 +1,18 @@ frappe.ready(() => { const assets = [ "/assets/frappe/js/lib/socket.io.min.js", - "/assets/frappe/js/frappe/socketio_client.js" + "/assets/frappe/js/frappe/socketio_client.js", ] frappe.require(assets, () => { if (window.dev_server) { frappe.boot.socketio_port = "9000" //use socketio port shown when bench starts } frappe.socketio.init(9000); - console.log(frappe.socketio) - }) - frappe.realtime.on("new_lms_message", (data) => { - console.log(data) }) setTimeout(() => { window.scrollTo(0, document.body.scrollHeight); - }, 0); + }, 300); $(".msger-send-btn").click((e) => { e.preventDefault(); @@ -27,10 +23,6 @@ frappe.ready(() => { "args": { "batch": decodeURIComponent($(e.target).attr("data-batch")), "message": message - }, - "callback": (data) => { - $(".msger-input").val(""); - frappe.realtime.publish("new_lms_message", {"message":"JJK"}) } }) } diff --git a/community/www/profiles/profile.py b/community/www/profiles/profile.py index 31aa1be0..cbb48edd 100644 --- a/community/www/profiles/profile.py +++ b/community/www/profiles/profile.py @@ -12,6 +12,6 @@ def get_context(context): def get_member(username): try: - frappe.get_doc("Community Member", {"username":username}) + return frappe.get_doc("Community Member", {"username":username}) except frappe.DoesNotExistError: return