From 12b628d885cc7eacea0ff5c9520bf49df4d7baa2 Mon Sep 17 00:00:00 2001 From: Achilles Rasquinha Date: Thu, 29 Mar 2018 13:50:49 +0530 Subject: [PATCH] Added Attachments --- .../doctype/chat_message/chat_message.json | 490 ++++++++++-------- .../chat/doctype/chat_message/chat_message.py | 21 +- frappe/public/js/frappe/chat.js | 71 ++- frappe/public/js/frappe/upload.js | 2 +- 4 files changed, 334 insertions(+), 250 deletions(-) diff --git a/frappe/chat/doctype/chat_message/chat_message.json b/frappe/chat/doctype/chat_message/chat_message.json index d3f668f794..c37923b341 100644 --- a/frappe/chat/doctype/chat_message/chat_message.json +++ b/frappe/chat/doctype/chat_message/chat_message.json @@ -1,247 +1,285 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-11-10 11:10:40.011099", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 1, + "creation": "2017-11-10 11:10:40.011099", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "room_type", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Room Type", - "length": 0, - "no_copy": 0, - "options": "Direct\nGroup\nVisitor", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "room_type", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Room Type", + "length": 0, + "no_copy": 0, + "options": "Direct\nGroup\nVisitor", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "user", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "User", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "type", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Type", + "length": 0, + "no_copy": 0, + "options": "Content\nFile", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "room", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Room", - "length": 0, - "no_copy": 0, - "options": "Chat Room", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "user", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "User", + "length": 0, + "no_copy": 0, + "options": "User", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "content", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Content", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "room", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Room", + "length": 0, + "no_copy": 0, + "options": "Chat Room", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "mentions", - "fieldtype": "Code", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Mentions", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "content", + "fieldtype": "Text", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Content", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "urls", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "URLs", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "mentions", + "fieldtype": "Code", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Mentions", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "urls", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "URLs", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-01-21 12:35:12.069954", - "modified_by": "faris@erpnext.com", - "module": "Chat", - "name": "Chat Message", - "name_case": "", - "owner": "arjun@gmail.com", + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2018-03-29 12:41:10.890765", + "modified_by": "achilles@erpnext.com", + "module": "Chat", + "name": "Chat Message", + "name_case": "", + "owner": "arjun@gmail.com", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "content, user", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "content", - "track_changes": 1, + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "search_fields": "content, user", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "content", + "track_changes": 1, "track_seen": 1 } \ No newline at end of file diff --git a/frappe/chat/doctype/chat_message/chat_message.py b/frappe/chat/doctype/chat_message/chat_message.py index 653454a871..3c58a6c07d 100644 --- a/frappe/chat/doctype/chat_message/chat_message.py +++ b/frappe/chat/doctype/chat_message/chat_message.py @@ -87,7 +87,7 @@ def sanitize_message_content(content): return content -def get_new_chat_message_doc(user, room, content, link = True): +def get_new_chat_message_doc(user, room, content, type = "Content", link = True): user = get_user_doc(user) room = frappe.get_doc('Chat Room', room) @@ -96,6 +96,7 @@ def get_new_chat_message_doc(user, room, content, link = True): mess.room = room.name mess.room_type = room.type mess.content = sanitize_message_content(content) + mess.type = type mess.user = user.name mess.mentions = json.dumps(meta.mentions) @@ -110,15 +111,15 @@ def get_new_chat_message_doc(user, room, content, link = True): return mess -def get_new_chat_message(user, room, content): - mess = get_new_chat_message_doc(user, room, content) +def get_new_chat_message(user, room, content, type = "Content"): + mess = get_new_chat_message_doc(user, room, content, type) resp = dict( name = mess.name, user = mess.user, room = mess.room, room_type = mess.room_type, - content = mess.content, + content = json.loads(mess.content) if mess.type in ["File"] else mess.content, urls = mess.urls, mentions = json.loads(mess.mentions), creation = mess.creation, @@ -128,8 +129,8 @@ def get_new_chat_message(user, room, content): return resp @frappe.whitelist(allow_guest = True) -def send(user, room, content): - mess = get_new_chat_message(user, room, content) +def send(user, room, content, type = "Content"): + mess = get_new_chat_message(user, room, content, type) frappe.publish_realtime('frappe.chat.message:create', mess, room = room, after_commit = True) @@ -154,7 +155,7 @@ def history(room, fields = None, limit = 10, start = None, end = None): ('Chat Message', 'room_type', '=', room.type) ], fields = fields if fields else [ - 'name', 'room_type', 'room', 'content', 'user', 'mentions', 'urls', 'creation', '_seen' + 'name', 'room_type', 'room', 'content', 'type', 'user', 'mentions', 'urls', 'creation', '_seen' ], order_by = 'creation' ) @@ -163,6 +164,9 @@ def history(room, fields = None, limit = 10, start = None, end = None): for m in mess: m['seen'] = json.loads(m._seen) if m._seen else [ ] del m['_seen'] + if not fields or 'content' in fields: + for m in mess: + m['content'] = json.loads(m.content) if m.type in ["File"] else m.content return mess @@ -176,7 +180,8 @@ def get(name, rooms = None, fields = None): user = dmess.user, room = dmess.room, room_type = dmess.room_type, - content = dmess.content, + content = json.loads(dmess.content) if dmess.type in ["File"] else dmess.content, + type = dmess.type, urls = dmess.urls, mentions = dmess.mentions, creation = dmess.creation, diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js index 33b5cc03fc..746c17cf58 100644 --- a/frappe/public/js/frappe/chat.js +++ b/frappe/public/js/frappe/chat.js @@ -730,7 +730,10 @@ frappe.chat.room.get = function (names, fields, fn) { rooms = frappe._.as_array(rooms) rooms = rooms.map(room => { return { ...room, creation: new frappe.datetime.datetime(room.creation), - last_message: room.last_message ? { ...room.last_message, creation: new frappe.datetime.datetime(room.last_message.creation) } : null + last_message: room.last_message ? { + ...room.last_message, + creation: new frappe.datetime.datetime(room.last_message.creation) + } : null } }) rooms = frappe._.squash(rooms) @@ -777,7 +780,11 @@ frappe.chat.room.history = function (name, fn) { { room: name, user: frappe.session.user }, r => { let messages = r.message ? frappe._.as_array(r.message) : [ ] // frappe.api BOGZ! (emtpy arrays are falsified, not good design). - messages = messages.map(m => { return { ...m, creation: new frappe.datetime.datetime(m.creation) } }) + messages = messages.map(m => { + return { ...m, + creation: new frappe.datetime.datetime(m.creation) + } + }) if ( fn ) fn(messages) @@ -859,7 +866,9 @@ frappe.chat.room.on.update = function (fn) { * @param {function} fn - callback with the created Chat Room. */ frappe.chat.room.on.create = function (fn) { - frappe.realtime.on("frappe.chat.room:create", r => fn({ ...r, creation: new frappe.datetime.datetime(r.creation) })) + frappe.realtime.on("frappe.chat.room:create", r => + fn({ ...r, creation: new frappe.datetime.datetime(r.creation) }) + ) } /** @@ -878,9 +887,9 @@ frappe.chat.message.typing = function (room, user) { frappe.realtime.publish("frappe.chat.message:typing", { user: user || frappe.session.user, room: room }) } -frappe.chat.message.send = function (room, message) { +frappe.chat.message.send = function (room, message, type = "Content") { frappe.call("frappe.chat.doctype.chat_message.chat_message.send", - { user: frappe.session.user, room: room, content: message }) + { user: frappe.session.user, room: room, content: message, type: type }) } frappe.chat.message.update = function (message, update, fn) { @@ -913,10 +922,11 @@ frappe.chat.message.seen = (mess, user) => { frappe.provide('frappe.chat.message.on') frappe.chat.message.on.create = function (fn) { - frappe.realtime.on("frappe.chat.message:create", r => fn({ ...r, creation: new frappe.datetime.datetime(r.creation) })) + frappe.realtime.on("frappe.chat.message:create", r => + fn({ ...r, creation: new frappe.datetime.datetime(r.creation) }) + ) } - frappe.chat.message.on.update = function (fn) { frappe.realtime.on("frappe.chat.message:update", r => fn(r.message, r.data)) } @@ -1874,8 +1884,16 @@ class extends Component { const names = props.typing.map(user => frappe.user.first_name(user)) item.subtitle = `${names.join(", ")} typing...` } else - if ( props.last_message ) - item.subtitle = props.last_message.content + if ( props.last_message ) { + const message = props.last_message + const content = message.content + + if ( message.type === "File" ) { + item.subtitle = `📁 ${content.name}` + } else { + item.subtitle = props.last_message.content + } + } } else { const user = props.owner === frappe.session.user ? frappe._.squash(props.users) : props.owner @@ -1886,8 +1904,17 @@ class extends Component { if ( !frappe._.is_empty(props.typing) ) item.subtitle = 'typing...' else - if ( props.last_message ) - item.subtitle = props.last_message.content + if ( props.last_message ) { + const message = props.last_message + console.log(message) + const content = message.content + + if ( message.type === "File" ) { + item.subtitle = `📁 ${content.name}` + } else { + item.subtitle = props.last_message.content + } + } } if ( props.last_message ) @@ -2027,7 +2054,13 @@ class extends Component { icon: "file", label: "File", onclick: ( ) => { - + const dialog = frappe.upload.make({ + args: { doctype: "Chat Room", docname: props.name }, + callback: (a, b, args) => { + const { file_url, filename } = args + frappe.chat.message.send(props.name, { path: file_url, name: filename }, "File") + } + }) } } ]) @@ -2209,13 +2242,14 @@ class extends Component { const { props } = this const me = props.user === frappe.session.user - + const content = props.content + return ( h("div",{class: "chat-list-item list-group-item"}, props.type === "Notification" ? h("div",{class:"chat-list-notification"}, h("div",{class:"chat-list-notification-content"}, - props.content + content ) ) : @@ -2266,7 +2300,14 @@ class extends Component { ) ) : null, h("div",{class:"chat-bubble-content"}, - h("small","",content) + h("small","", + props.type === "File" ? + h("a", { class: "no-decoration", href: content.path, target: "_blank" }, + h(frappe.components.FontAwesome, { type: "file", fixed: true }), ` ${content.name}` + ) + : + content + ) ), h("div",{class:"chat-bubble-meta"}, h("span",{class:"chat-bubble-creation"},creation), diff --git a/frappe/public/js/frappe/upload.js b/frappe/public/js/frappe/upload.js index 7704b6fd65..7fdb1a2124 100644 --- a/frappe/public/js/frappe/upload.js +++ b/frappe/public/js/frappe/upload.js @@ -367,7 +367,7 @@ frappe.upload = { } var attachment = r.message; opts.loopcallback && opts.loopcallback(); - opts.callback && opts.callback(attachment, r); + opts.callback && opts.callback(attachment, r, args); $(document).trigger("upload_complete", attachment); }, error: function(r) {