diff --git a/community/lms/doctype/lms_batch/lms_batch.py b/community/lms/doctype/lms_batch/lms_batch.py index 0f0d9fee..1943ed9f 100644 --- a/community/lms/doctype/lms_batch/lms_batch.py +++ b/community/lms/doctype/lms_batch/lms_batch.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from community.www.courses.utils import get_member_with_email class LMSBatch(Document): def validate(self): @@ -15,3 +16,25 @@ class LMSBatch(Document): short_code = frappe.db.get_value("LMS Course", self.course, "short_code") course_batches = frappe.get_all("LMS Batch",{"course":self.course}) self.code = short_code + str(len(course_batches) + 1) + +@frappe.whitelist() +def get_messages(batch): + messages = frappe.get_all("LMS Message", {"batch": batch}, ["*"], order_by="creation") + for message in messages: + message.message = frappe.utils.md_to_html(message.message) + member_email = frappe.db.get_value("Community Member", message.author, ["email"]) + if member_email == frappe.session.user: + message.author_name = "You" + message.is_author = True + return messages + +@frappe.whitelist() +def save_message(message, batch): + doc = frappe.get_doc({ + "doctype": "LMS Message", + "batch": batch, + "author": get_member_with_email(), + "message": message + }) + doc.save(ignore_permissions=True) + return doc \ No newline at end of file diff --git a/community/lms/doctype/lms_batch_membership/lms_batch_membership.json b/community/lms/doctype/lms_batch_membership/lms_batch_membership.json index 8bd1c68b..02352fdc 100644 --- a/community/lms/doctype/lms_batch_membership/lms_batch_membership.json +++ b/community/lms/doctype/lms_batch_membership/lms_batch_membership.json @@ -39,7 +39,6 @@ { "fieldname": "role", "fieldtype": "Select", - "in_list_view": 1, "in_standard_filter": 1, "label": "Role", "options": "\nMember\nAdmin" @@ -59,7 +58,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-04-22 15:30:00.069946", + "modified": "2021-04-26 12:52:59.826509", "modified_by": "Administrator", "module": "LMS", "name": "LMS Batch Membership", diff --git a/community/lms/doctype/lms_message/lms_message.json b/community/lms/doctype/lms_message/lms_message.json index df6a85b3..929aac4c 100644 --- a/community/lms/doctype/lms_message/lms_message.json +++ b/community/lms/doctype/lms_message/lms_message.json @@ -5,10 +5,13 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "batch", "author", - "message", - "pin" + "batch", + "column_break_3", + "author_name", + "pin", + "section_break_6", + "message" ], "fields": [ { @@ -36,11 +39,26 @@ "fieldname": "pin", "fieldtype": "Check", "label": "Pin" + }, + { + "fetch_from": "author.full_name", + "fieldname": "author_name", + "fieldtype": "Data", + "label": "Author Name", + "read_only": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_6", + "fieldtype": "Section Break" } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-03-23 18:06:25.086377", + "modified": "2021-04-26 16:11:20.142164", "modified_by": "Administrator", "module": "LMS", "name": "LMS Message", diff --git a/community/lms/doctype/lms_message/lms_message.py b/community/lms/doctype/lms_message/lms_message.py index 4e490075..68b15143 100644 --- a/community/lms/doctype/lms_message/lms_message.py +++ b/community/lms/doctype/lms_message/lms_message.py @@ -9,9 +9,7 @@ from frappe import _ from frappe.utils import add_days, nowdate class LMSMessage(Document): def after_insert(self): - message = self.as_dict() - message['broadcast'] = True - frappe.publish_realtime('new_lms_message', message, after_commit=True) + frappe.publish_realtime("new_lms_message", {"message":"JJannat"}, user="Administrator") self.send_email() def send_email(self): diff --git a/community/lms/web_form/add_a_new_batch/add_a_new_batch.json b/community/lms/web_form/add_a_new_batch/add_a_new_batch.json index c0f49820..61903c7c 100644 --- a/community/lms/web_form/add_a_new_batch/add_a_new_batch.json +++ b/community/lms/web_form/add_a_new_batch/add_a_new_batch.json @@ -18,7 +18,7 @@ "is_standard": 1, "login_required": 1, "max_attachment_size": 0, - "modified": "2021-04-21 16:39:09.457653", + "modified": "2021-04-26 11:08:00.026388", "modified_by": "Administrator", "module": "LMS", "name": "add-a-new-batch", @@ -47,41 +47,6 @@ "reqd": 0, "show_in_filter": 0 }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "start_date", - "fieldtype": "Date", - "hidden": 0, - "label": "Start Date", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "start_time", - "fieldtype": "Data", - "hidden": 0, - "label": "Start Time (HH:MM:SS)", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, { "allow_read_on_all_link_options": 0, "fieldname": "title", @@ -94,6 +59,18 @@ "reqd": 1, "show_in_filter": 0 }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "start_date", + "fieldtype": "Date", + "hidden": 0, + "label": "Start Date", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, { "allow_read_on_all_link_options": 0, "description": "", @@ -108,6 +85,18 @@ "reqd": 1, "show_in_filter": 0 }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "start_time", + "fieldtype": "Data", + "hidden": 0, + "label": "Start Time (HH:MM:SS)", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, { "allow_read_on_all_link_options": 0, "fieldname": "end_time", diff --git a/community/public/css/style.css b/community/public/css/style.css index a3c6296d..89ebfa13 100644 --- a/community/public/css/style.css +++ b/community/public/css/style.css @@ -8,8 +8,8 @@ --c4: #2a9d8f; --c5: #f4a261; --c6: #e76f51; - --c7: #ccd5ae; + --c8: #EEEEEE; --bg: var(--c1); --header-bg: var(--c2); @@ -23,6 +23,8 @@ --text-color-light: #ccc; --cta-color: var(--c4); + --send-message: var(--c7); + --received-message: var(--c8); } body { @@ -232,4 +234,60 @@ nav.navbar { width: 59px; height: 57px; border-radius: 50%; +} + +.msger-inputarea { + position: fixed; + bottom: 0; + width: 100%; + display: flex; + padding: 10px; + border-top: 2px solid #ddd; + background: #eee; + z-index: 1; +} +.msger-inputarea * { + padding: 10px; + border: none; + border-radius: 3px; + font-size: 1em; +} +.msger-input { + flex: 1; + background: #ddd; +} +.msger-send-btn { + margin-left: 10px; + background: var(--cta-color); + color: #fff; + font-weight: bold; + cursor: pointer; + transition: background 0.23s; +} + +.discussion { + border: 1px solid var(--text-color); + padding: 10px; + margin: 10px; + border-radius: 10px; + background: var(--received-message); + width: 50%; + display: flex; + flex-direction: column; +} + +.is-author { + float: right; + background: var(--send-message); +} + +.batch-header { + position: fixed; + top: 0; + background: var(--bg); + width: 100%; +} + +.message-section { + margin-left: 5%; } \ No newline at end of file diff --git a/community/www/courses/about/index.html b/community/www/courses/about/index.html index ecfbafbf..1b17616c 100644 --- a/community/www/courses/about/index.html +++ b/community/www/courses/about/index.html @@ -1,5 +1,7 @@ {% extends "templates/base.html" %} {% from "www/macros/sidebar.html" import Sidebar %} +{% from "www/macros/common_macro.html" import InstructorsSection, MentorsSection %} + {% block title %}About{% endblock %} {% block head_include %} @@ -7,7 +9,38 @@ {% endblock %} {% block content %} -{{ Sidebar(course, batch_code) }} +{{ Sidebar(course_slug, batch_code) }}
+ {{ CourseBasicDetail(course)}} + {{ InstructorsSection(instructor) }} + {% if batch.description %} + {{ BatchDetails(batch.description) }} + {% endif %} + {{ MentorsSection(mentors, True) }}
{% endblock %} + +{% macro CourseBasicDetail(course) %} +

{{course.name}}

+
+ {{course.short_introduction}} +
+{% if course.video_link %} +
+ +
+{% endif %} +

About the Course

+
{{frappe.utils.md_to_html(course.description)}}
+{% endmacro %} + +{% macro BatchDetails(description) %} +
+

About the Batch

+
+ {{ frappe.utils.md_to_html(description) }} +
+
+{% endmacro %} \ No newline at end of file diff --git a/community/www/courses/about/index.py b/community/www/courses/about/index.py index 03180785..238177a6 100644 --- a/community/www/courses/about/index.py +++ b/community/www/courses/about/index.py @@ -1,8 +1,23 @@ import frappe -from community.www.courses.utils import redirect_if_not_a_member +from community.www.courses.utils import redirect_if_not_a_member, get_course, get_instructor, get_batch def get_context(context): context.no_cache = 1 - context.course = frappe.form_dict["course"] + context.course_slug = frappe.form_dict["course"] + context.course = get_course(context.course_slug) context.batch_code = frappe.form_dict["batch"] - redirect_if_not_a_member(context.course, context.batch_code) \ No newline at end of file + redirect_if_not_a_member(context.course_slug, context.batch_code) + + context.instructor = get_instructor(context.course.owner) + context.batch = get_batch(context.batch_code) + context.mentors = get_mentors(context.batch.name) + print(context.mentors) + +def get_mentors(batch): + mentors = [] + memberships = frappe.get_all("LMS Batch Membership", {"batch": batch, "member_type": "Mentor"}, ["member"]) + for membership in memberships: + member = frappe.db.get_value("Community Member", membership.member, ["name","full_name"], as_dict=True) + member.batch_count = len(frappe.get_all("LMS Batch Membership", {"member": member.name, "member_type": "Mentor"})) + mentors.append(member) + return mentors \ No newline at end of file diff --git a/community/www/courses/course.html b/community/www/courses/course.html index c1ee4c76..5989e0f6 100644 --- a/community/www/courses/course.html +++ b/community/www/courses/course.html @@ -1,4 +1,5 @@ {% extends "templates/base.html" %} +{% from "www/macros/common_macro.html" import InstructorsSection, MentorsSection %} {% block title %}{{ course.title }}{% endblock %} {% block head_include %} @@ -27,7 +28,7 @@ @@ -59,7 +60,7 @@ {% macro BatchSection(course, is_mentor, upcoming_batches, mentor_batches) %} {% if is_mentor %} {{ BatchSectionForMentors(course, mentor_batches) }} - {% else %} + {% else %} {{ BatchSectionForStudents(course, upcoming_batches) }} {% endif %} {% endmacro %} @@ -152,27 +153,3 @@ {% endfor %} {% endmacro %} - -{% macro InstructorsSection(instructor) %} -

Instructor

-
-
{{instructor.full_name}}
-
Created {{instructor.course_count}} courses
-
-{% endmacro %} - -{% macro MentorsSection(instructor) %} -

Mentors

- {% for m in mentors %} -
-
{{m.full_name}}
-
Mentored {{m.batch_count}} batches
-
- {% endfor %} - -
- Interested to become a mentor? - -
Apply Now!
-
-{% endmacro %} diff --git a/community/www/courses/course.js b/community/www/courses/course.js index 1bde111e..a0996a2e 100644 --- a/community/www/courses/course.js +++ b/community/www/courses/course.js @@ -1,4 +1,15 @@ 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', @@ -29,28 +40,6 @@ frappe.ready(() => { }) }) - $(".send-message").click((e) => { - var message = $(".message-text").val().trim(); - if (message) { - frappe.call({ - "method": "community.www.courses.course.save_message", - "args": { - "batch": decodeURIComponent($(e.target).attr("data-batch")), - "author": decodeURIComponent($(e.target).attr("data-author")), - "message": message - }, - "callback": (data) => { - $(".message-text").val(""); - var element = add_message(data.message, true) - $(".discussions").prepend(element); - } - }) - } - else { - $(".message-text").val(""); - } - }) - $(".apply-now").click((e) => { if (frappe.session.user == "Guest") { window.location.href = "/login"; @@ -104,15 +93,6 @@ frappe.ready(() => { } }) }) - - var add_message = (message, session_user = false) => { - var author_name = session_user ? "You" : message.author_name - return `
-
${author_name}
- ${message.message} -
${message.creation}
-
`; - } }) /* var show_enrollment_badge = () => { diff --git a/community/www/courses/course.py b/community/www/courses/course.py index c154477a..e0418096 100644 --- a/community/www/courses/course.py +++ b/community/www/courses/course.py @@ -1,4 +1,5 @@ import frappe +from community.www.courses.utils import get_instructor from frappe.utils import nowdate, getdate def get_context(context): @@ -61,16 +62,6 @@ def get_membership(batches): memberships.append(membership) return memberships -def get_instructor(owner): - instructor = frappe._dict() - try: - instructor = frappe.get_doc("Community Member", {"email": owner}) - except frappe.DoesNotExistError: - instructor.full_name = owner - instructor.abbr = ("").join([ s[0] for s in owner.split() ]) - instructor.course_count = len(frappe.get_all("LMS Course", {"owner": owner})) - return instructor - def get_mentors(course): course_mentors = [] mentors = frappe.get_all("LMS Course Mentor Mapping", {"course": course}, ["mentor"]) @@ -108,25 +99,3 @@ def is_mentor(course): if len(mapping): return True -@frappe.whitelist() -def get_messages(batch): - messages = frappe.get_all("LMS Message", {"batch": batch}, ["*"], order_by="creation desc") - for message in messages: - message.message = frappe.utils.md_to_html(message.message) - message.creation = frappe.utils.format_datetime(message.creation, "medium") - message.author_name, member_email = frappe.db.get_value("Community Member", message.author, ["full_name","email"]) - if member_email == frappe.session.user: - message.author_name = "You" - return messages - -@frappe.whitelist() -def save_message(message, author, batch): - doc = frappe.get_doc({ - "doctype": "LMS Message", - "author": author, - "batch": batch, - "message": message - }) - doc.save(ignore_permissions=True) - return doc - diff --git a/community/www/courses/discuss/index.html b/community/www/courses/discuss/index.html index c1695192..31301ce7 100644 --- a/community/www/courses/discuss/index.html +++ b/community/www/courses/discuss/index.html @@ -1,5 +1,7 @@ {% extends "templates/base.html" %} {% from "www/macros/sidebar.html" import Sidebar %} +{% from "www/macros/common_macro.html" import BatchHearder %} + {% block title %}Discuss{% endblock %} {% block head_include %} @@ -7,7 +9,40 @@ {% endblock %} {% block content %} -{{ Sidebar(course, batch_code) }} -
+{{ Sidebar(course_slug, batch_code) }} +
+
+ {{ BatchHearder(course.name, member_count) }} +
+
+ {{ Messages(messages) }} +
+ {{ TextArea() }}
{% endblock %} + +{% macro Messages(messages) %} +{% for message in messages %} +
+
+
+ {{ message.author_name }} +
+
+ {{ frappe.utils.pretty_date(message.creation) }} +
+
+
+ {{ message.message }} +
+ +
+{% endfor %} +{% endmacro %} + +{% macro TextArea() %} +
+ + +
+{% endmacro %} \ No newline at end of file diff --git a/community/www/courses/discuss/index.js b/community/www/courses/discuss/index.js new file mode 100644 index 00000000..64ab83b5 --- /dev/null +++ b/community/www/courses/discuss/index.js @@ -0,0 +1,41 @@ +frappe.ready(() => { + const assets = [ + "/assets/frappe/js/lib/socket.io.min.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); + + $(".msger-send-btn").click((e) => { + e.preventDefault(); + var message = $(".msger-input").val().trim(); + if (message) { + frappe.call({ + "method": "community.lms.doctype.lms_batch.lms_batch.save_message", + "args": { + "batch": decodeURIComponent($(e.target).attr("data-batch")), + "message": message + }, + "callback": (data) => { + $(".msger-input").val(""); + frappe.realtime.publish("new_lms_message", {"message":"JJK"}) + } + }) + } + else { + $(".msger-input").val(""); + } + }) +}) \ No newline at end of file diff --git a/community/www/courses/discuss/index.py b/community/www/courses/discuss/index.py index 03180785..7c34761a 100644 --- a/community/www/courses/discuss/index.py +++ b/community/www/courses/discuss/index.py @@ -1,8 +1,15 @@ import frappe -from community.www.courses.utils import redirect_if_not_a_member +from community.www.courses.utils import redirect_if_not_a_member, get_course, get_batch_members, get_batch +from community.lms.doctype.lms_batch.lms_batch import get_messages def get_context(context): context.no_cache = 1 - context.course = frappe.form_dict["course"] + context.course_slug = frappe.form_dict["course"] + context.course = get_course(context.course_slug) context.batch_code = frappe.form_dict["batch"] - redirect_if_not_a_member(context.course, context.batch_code) \ No newline at end of file + redirect_if_not_a_member(context.course_slug, context.batch_code) + + context.batch = get_batch(context.batch_code) + context.members = get_batch_members(context.batch.name) + context.member_count = len(context.members) + context.messages = get_messages(context.batch.name) \ No newline at end of file diff --git a/community/www/courses/members/index.html b/community/www/courses/members/index.html index 651b3aa8..618ce2ac 100644 --- a/community/www/courses/members/index.html +++ b/community/www/courses/members/index.html @@ -1,6 +1,8 @@ {% extends "templates/base.html" %} {% from "www/macros/sidebar.html" import Sidebar %} {% from "www/macros/profile.html" import Profile %} +{% from "www/macros/common_macro.html" import BatchHearder %} + {% block title %}Members{% endblock %} {% block head_include %} @@ -8,28 +10,29 @@ {% endblock %} {% block content %} -{{ Sidebar(course, batch_code) }} +{{ Sidebar(course_slug, batch_code) }}
-
-

{{course.name}}

-
{{member_count}} members
-
- -
- {% for member in members %} -
-
- {{ Profile(member.photo, member.full_name, member.abbr, "small") }} -
-
- {{member.full_name}} -
- {% if member.is_mentor %} -
Mentor
- {% endif %} -
-
- {% endfor %} -
+ {{ BatchHearder(course.name, member_count)}} + {{ MembersList(members)}}
-{% endblock %} \ No newline at end of file +{% endblock %} + + +{% macro MembersList(members) %} +
+ {% for member in members %} +
+
+ {{ Profile(member.photo, member.full_name, member.abbr, "small") }} +
+
+ {{member.full_name}} +
+ {% if member.is_mentor %} +
Mentor
+ {% endif %} +
+
+ {% endfor %} +
+{% endmacro %} \ No newline at end of file diff --git a/community/www/courses/members/index.py b/community/www/courses/members/index.py index 1ae3e266..7e9bf36a 100644 --- a/community/www/courses/members/index.py +++ b/community/www/courses/members/index.py @@ -1,5 +1,5 @@ import frappe -from community.www.courses.utils import redirect_if_not_a_member, get_batch, get_member_with_name, get_course +from community.www.courses.utils import redirect_if_not_a_member, get_batch, get_member_with_name, get_course, get_batch_members def get_context(context): context.no_cache = 1 @@ -8,16 +8,5 @@ def get_context(context): context.batch_code = frappe.form_dict["batch"] redirect_if_not_a_member(context.course_slug, context.batch_code) context.batch = get_batch(context.batch_code) - context.members = get_members(context.batch) - context.member_count = len(context.members) - -def get_members(batch): - members = [] - memberships = frappe.get_all("LMS Batch Membership", {"batch": batch}, ["member", "member_type"]) - - for membership in memberships: - member = get_member_with_name(membership.member) - if membership.member_type == "Mentor": - member.is_mentor = True - members.append(member) - return members \ No newline at end of file + context.members = get_batch_members(context.batch.name) + context.member_count = len(context.members) \ No newline at end of file diff --git a/community/www/courses/utils.py b/community/www/courses/utils.py index 424b88e1..9537d320 100644 --- a/community/www/courses/utils.py +++ b/community/www/courses/utils.py @@ -14,12 +14,12 @@ def get_member_with_name(name): def get_batch(code): try: - return frappe.db.get_value("LMS Batch", {"code": code}, "name") + return frappe.db.get_value("LMS Batch", {"code": code}, ["name", "description"], as_dict=True) except frappe.DoesNotExistError: return def is_member_of_batch(batch_code): - membership = frappe.get_all("LMS Batch Membership", {"batch": get_batch(batch_code), "member": get_member_with_email()}) + membership = frappe.get_all("LMS Batch Membership", {"batch": get_batch(batch_code).name, "member": get_member_with_email()}) if len(membership): return True return False @@ -31,6 +31,27 @@ def redirect_if_not_a_member(course,batch_code): def get_course(slug): try: - return frappe.db.get_value("LMS Course", {"slug": slug}, "name", as_dict=True) + return frappe.get_doc("LMS Course", {"slug": slug}) except frappe.DoesNotExistError: - return \ No newline at end of file + return + +def get_instructor(owner): + instructor = frappe._dict() + try: + instructor = frappe.get_doc("Community Member", {"email": owner}) + except frappe.DoesNotExistError: + instructor.full_name = owner + instructor.abbr = ("").join([ s[0] for s in owner.split() ]) + instructor.course_count = len(frappe.get_all("LMS Course", {"owner": owner})) + return instructor + +def get_batch_members(batch): + members = [] + memberships = frappe.get_all("LMS Batch Membership", {"batch": batch}, ["member", "member_type"]) + + for membership in memberships: + member = get_member_with_name(membership.member) + if membership.member_type == "Mentor": + member.is_mentor = True + members.append(member) + return members \ No newline at end of file diff --git a/community/www/macros/common_macro.html b/community/www/macros/common_macro.html new file mode 100644 index 00000000..f5cf190e --- /dev/null +++ b/community/www/macros/common_macro.html @@ -0,0 +1,32 @@ +{% macro InstructorsSection(instructor) %} +

Instructor

+
+
{{instructor.full_name}}
+
Created {{instructor.course_count}} courses
+
+{% endmacro %} + +{% macro MentorsSection(mentors, is_mentor) %} +

Mentors

+{% for m in mentors %} +
+
{{m.full_name}}
+
Mentored {{m.batch_count}} batches
+
+{% endfor %} +{% if not is_mentor %} +
+ Interested to become a mentor? + +
Apply Now!
+
+{% endif %} +{% endmacro %} + + +{% macro BatchHearder(course_name, member_count) %} +
+

{{course_name}}

+
{{member_count}} members
+
+{% endmacro %} \ No newline at end of file