|
|
@ -1,36 +1,101 @@ |
|
|
|
odoo.define('mail_archives.archives', function (require) { |
|
|
|
"use strict"; |
|
|
|
|
|
|
|
// var core = require('web.core');
|
|
|
|
// var utils = require('web.utils');
|
|
|
|
// var Widget = require('web.Widget');
|
|
|
|
|
|
|
|
var bus = require('bus.bus').bus; |
|
|
|
var config = require('web.config'); |
|
|
|
var core = require('web.core'); |
|
|
|
var data = require('web.data'); |
|
|
|
var chat_manager = require('mail.chat_manager'); |
|
|
|
var Model = require('web.Model'); |
|
|
|
var session = require('web.session'); |
|
|
|
var time = require('web.time'); |
|
|
|
var web_client = require('web.web_client'); |
|
|
|
|
|
|
|
var _t = core._t; |
|
|
|
var LIMIT = 100; |
|
|
|
var preview_msg_max_size = 350; // optimal for native english speakers
|
|
|
|
|
|
|
|
var Model = require('web.Model'); |
|
|
|
var MessageModel = new Model('mail.message', session.context); |
|
|
|
var ChannelModel = new Model('mail.channel', session.context); |
|
|
|
var UserModel = new Model('res.users', session.context); |
|
|
|
var PartnerModel = new Model('res.partner', session.context); |
|
|
|
var chat_manager = require('mail.chat_manager'); |
|
|
|
|
|
|
|
// Private model
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
var messages = []; |
|
|
|
var channels = []; |
|
|
|
var channels_preview_def; |
|
|
|
var channel_defs = {}; |
|
|
|
var chat_unread_counter = 0; |
|
|
|
var unread_conversation_counter = 0; |
|
|
|
var needaction_counter = 0; |
|
|
|
var mention_partner_suggestions = []; |
|
|
|
var emojis = []; |
|
|
|
var emoji_substitutions = {}; |
|
|
|
var needaction_counter = 0; |
|
|
|
var mention_partner_suggestions = []; |
|
|
|
var discuss_ids = {}; |
|
|
|
var global_unread_counter = 0; |
|
|
|
var pinned_dm_partners = []; // partner_ids we have a pinned DM with
|
|
|
|
var client_action_open = false; |
|
|
|
|
|
|
|
// Utils: Window focus/unfocus, beep, tab title, parsing html strings
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
var beep = (function () { |
|
|
|
if (typeof(Audio) === "undefined") { |
|
|
|
return function () {}; |
|
|
|
} |
|
|
|
var audio = new Audio(); |
|
|
|
var ext = audio.canPlayType("audio/ogg; codecs=vorbis") ? ".ogg" : ".mp3"; |
|
|
|
audio.src = session.url("/mail/static/src/audio/ting" + ext); |
|
|
|
return function () { audio.play(); }; |
|
|
|
})(); |
|
|
|
|
|
|
|
bus.on("window_focus", null, function() { |
|
|
|
global_unread_counter = 0; |
|
|
|
web_client.set_title_part("_chat"); |
|
|
|
}); |
|
|
|
|
|
|
|
// to do: move this to mail.utils
|
|
|
|
function send_native_notification(title, content) { |
|
|
|
var notification = new Notification(title, {body: content, icon: "/mail/static/src/img/odoo_o.png"}); |
|
|
|
notification.onclick = function (e) { |
|
|
|
window.focus(); |
|
|
|
if (this.cancel) { |
|
|
|
this.cancel(); |
|
|
|
} else if (this.close) { |
|
|
|
this.close(); |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function notify_incoming_message (msg, options) { |
|
|
|
if (bus.is_odoo_focused() && options.is_displayed) { |
|
|
|
// no need to notify
|
|
|
|
return; |
|
|
|
} |
|
|
|
var title = _t('New message'); |
|
|
|
if (msg.author_id[1]) { |
|
|
|
title = _.escape(msg.author_id[1]); |
|
|
|
} |
|
|
|
var content = parse_and_transform(msg.body, strip_html).substr(0, preview_msg_max_size); |
|
|
|
|
|
|
|
if (!bus.is_odoo_focused()) { |
|
|
|
global_unread_counter++; |
|
|
|
var tab_title = _.str.sprintf(_t("%d Messages"), global_unread_counter); |
|
|
|
web_client.set_title_part("_chat", tab_title); |
|
|
|
} |
|
|
|
|
|
|
|
if (Notification && Notification.permission === "granted") { |
|
|
|
if (bus.is_master) { |
|
|
|
send_native_notification(title, content); |
|
|
|
} |
|
|
|
} else { |
|
|
|
web_client.do_notify(title, content); |
|
|
|
if (bus.is_master) { |
|
|
|
beep(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function parse_and_transform(html_string, transform_function) { |
|
|
|
var open_token = "OPEN" + Date.now(); |
|
|
|
var string = html_string.replace(/</g, open_token); |
|
|
@ -61,6 +126,20 @@ function add_link (node, transform_children) { |
|
|
|
return node.outerHTML; |
|
|
|
} |
|
|
|
|
|
|
|
function strip_html (node, transform_children) { |
|
|
|
if (node.nodeType === 3) return node.data; // text node
|
|
|
|
if (node.tagName === "BR") return "\n"; |
|
|
|
return transform_children(); |
|
|
|
} |
|
|
|
|
|
|
|
function inline (node, transform_children) { |
|
|
|
if (node.nodeType === 3) return node.data; |
|
|
|
if (node.tagName === "BR") return " "; |
|
|
|
if (node.tagName.match(/^(A|P|DIV|PRE|BLOCKQUOTE)$/)) return transform_children(); |
|
|
|
node.innerHTML = transform_children(); |
|
|
|
return node.outerHTML; |
|
|
|
} |
|
|
|
|
|
|
|
// Message and channel manipulation helpers
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
|
|
@ -68,8 +147,9 @@ function add_link (node, transform_children) { |
|
|
|
function add_message (data, options) { |
|
|
|
options = options || {}; |
|
|
|
var msg = _.findWhere(messages, { id: data.id }); |
|
|
|
|
|
|
|
if (!msg) { |
|
|
|
msg = make_message(data); |
|
|
|
msg = chat_manager.make_message(data); |
|
|
|
// Keep the array ordered by id when inserting the new message
|
|
|
|
messages.splice(_.sortedIndex(messages, msg, 'id'), 0, msg); |
|
|
|
_.each(msg.channel_ids, function (channel_id) { |
|
|
@ -94,7 +174,7 @@ function add_message (data, options) { |
|
|
|
} |
|
|
|
var query = {is_displayed: false}; |
|
|
|
chat_manager.bus.trigger('anyone_listening', channel, query); |
|
|
|
// notify_incoming_message(msg, query);
|
|
|
|
notify_incoming_message(msg, query); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -156,7 +236,7 @@ function make_message (data) { |
|
|
|
Object.defineProperties(msg, { |
|
|
|
is_starred: property_descr("channel_starred"), |
|
|
|
is_needaction: property_descr("channel_inbox"), |
|
|
|
is_archive: property_descr("channel_archive"), |
|
|
|
is_archive: property_descr("channel_archive") |
|
|
|
}); |
|
|
|
|
|
|
|
if (_.contains(data.needaction_partner_ids, session.partner_id)) { |
|
|
@ -234,18 +314,84 @@ function add_channel (data, options) { |
|
|
|
return channel; |
|
|
|
} |
|
|
|
|
|
|
|
function make_channel (data, options) { |
|
|
|
var channel = { |
|
|
|
id: data.id, |
|
|
|
name: data.name, |
|
|
|
type: data.type || data.channel_type, |
|
|
|
all_history_loaded: false, |
|
|
|
uuid: data.uuid, |
|
|
|
is_detached: data.is_minimized, |
|
|
|
is_folded: data.state === "folded", |
|
|
|
autoswitch: 'autoswitch' in options ? options.autoswitch : true, |
|
|
|
hidden: options.hidden, |
|
|
|
display_needactions: options.display_needactions, |
|
|
|
mass_mailing: data.mass_mailing, |
|
|
|
needaction_counter: data.message_needaction_counter || 0, |
|
|
|
unread_counter: 0, |
|
|
|
last_seen_message_id: data.seen_message_id, |
|
|
|
cache: {'[]': { |
|
|
|
all_history_loaded: false, |
|
|
|
loaded: false, |
|
|
|
messages: [], |
|
|
|
}}, |
|
|
|
}; |
|
|
|
if (channel.type === "channel" && data.public !== "private") { |
|
|
|
channel.type = "public"; |
|
|
|
} else if (data.public === "private") { |
|
|
|
channel.type = "private"; |
|
|
|
} |
|
|
|
if (_.size(data.direct_partner) > 0) { |
|
|
|
channel.type = "dm"; |
|
|
|
channel.name = data.direct_partner[0].name; |
|
|
|
channel.direct_partner_id = data.direct_partner[0].id; |
|
|
|
channel.status = data.direct_partner[0].im_status; |
|
|
|
pinned_dm_partners.push(channel.direct_partner_id); |
|
|
|
bus.update_option('bus_presence_partner_ids', pinned_dm_partners); |
|
|
|
} else if ('anonymous_name' in data) { |
|
|
|
channel.name = data.anonymous_name; |
|
|
|
} |
|
|
|
channel.is_chat = !channel.type.match(/^(public|private|static)$/); |
|
|
|
if (data.message_unread_counter) { |
|
|
|
update_channel_unread_counter(channel, data.message_unread_counter); |
|
|
|
} |
|
|
|
return channel; |
|
|
|
} |
|
|
|
|
|
|
|
function remove_channel (channel) { |
|
|
|
if (!channel) { return; } |
|
|
|
if (channel.type === 'dm') { |
|
|
|
var index = pinned_dm_partners.indexOf(channel.direct_partner_id); |
|
|
|
if (index > -1) { |
|
|
|
pinned_dm_partners.splice(index, 1); |
|
|
|
bus.update_option('bus_presence_partner_ids', pinned_dm_partners); |
|
|
|
} |
|
|
|
} |
|
|
|
channels = _.without(channels, channel); |
|
|
|
delete channel_defs[channel.id]; |
|
|
|
} |
|
|
|
|
|
|
|
function get_channel_cache (channel, domain) { |
|
|
|
var stringified_domain = JSON.stringify(domain || []); |
|
|
|
if (!channel.cache[stringified_domain]) { |
|
|
|
channel.cache[stringified_domain] = { |
|
|
|
all_history_loaded: false, |
|
|
|
loaded: false, |
|
|
|
messages: [] |
|
|
|
messages: [], |
|
|
|
}; |
|
|
|
} |
|
|
|
return channel.cache[stringified_domain]; |
|
|
|
} |
|
|
|
|
|
|
|
function invalidate_caches(channel_ids) { |
|
|
|
_.each(channel_ids, function (channel_id) { |
|
|
|
var channel = chat_manager.get_channel(channel_id); |
|
|
|
if (channel) { |
|
|
|
channel.cache = { '[]': channel.cache['[]']}; |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function add_to_cache(message, domain) { |
|
|
|
_.each(message.channel_ids, function (channel_id) { |
|
|
|
var channel = chat_manager.get_channel(channel_id); |
|
|
@ -259,6 +405,15 @@ function add_to_cache(message, domain) { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function remove_message_from_channel (channel_id, message) { |
|
|
|
message.channel_ids = _.without(message.channel_ids, channel_id); |
|
|
|
var channel = _.findWhere(channels, { id: channel_id }); |
|
|
|
_.each(channel.cache, function (cache) { |
|
|
|
cache.messages = _.without(cache.messages, message); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// options: domain, load_more
|
|
|
|
function fetch_from_channel (channel, options) { |
|
|
|
options = options || {}; |
|
|
|
var domain = |
|
|
@ -290,6 +445,31 @@ function fetch_from_channel (channel, options) { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// options: force_fetch
|
|
|
|
function fetch_document_messages (ids, options) { |
|
|
|
var loaded_msgs = _.filter(messages, function (message) { |
|
|
|
return _.contains(ids, message.id); |
|
|
|
}); |
|
|
|
var loaded_msg_ids = _.pluck(loaded_msgs, 'id'); |
|
|
|
|
|
|
|
options = options || {}; |
|
|
|
if (options.force_fetch || _.difference(ids.slice(0, LIMIT), loaded_msg_ids).length) { |
|
|
|
var ids_to_load = _.difference(ids, loaded_msg_ids).slice(0, LIMIT); |
|
|
|
|
|
|
|
return MessageModel.call('message_format', [ids_to_load]).then(function (msgs) { |
|
|
|
var processed_msgs = []; |
|
|
|
_.each(msgs, function (msg) { |
|
|
|
processed_msgs.push(add_message(msg, {silent: true})); |
|
|
|
}); |
|
|
|
return _.sortBy(loaded_msgs.concat(processed_msgs), function (msg) { |
|
|
|
return msg.date; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
return $.when(loaded_msgs); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function update_channel_unread_counter (channel, counter) { |
|
|
|
if (channel.unread_counter > 0 && counter === 0) { |
|
|
|
unread_conversation_counter = Math.max(0, unread_conversation_counter-1); |
|
|
@ -303,12 +483,249 @@ function update_channel_unread_counter (channel, counter) { |
|
|
|
chat_manager.bus.trigger("update_channel_unread_counter", channel); |
|
|
|
} |
|
|
|
|
|
|
|
var channel_seen = _.throttle(function (channel) { |
|
|
|
return ChannelModel.call('channel_seen', [[channel.id]], {}, {shadow: true}); |
|
|
|
}, 3000); |
|
|
|
|
|
|
|
// Notification handlers
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
function on_notification (notifications) { |
|
|
|
// sometimes, the web client receives unsubscribe notification and an extra
|
|
|
|
// notification on that channel. This is then followed by an attempt to
|
|
|
|
// rejoin the channel that we just left. The next few lines remove the
|
|
|
|
// extra notification to prevent that situation to occur.
|
|
|
|
var unsubscribed_notif = _.find(notifications, function (notif) { |
|
|
|
return notif[1].info === "unsubscribe"; |
|
|
|
}); |
|
|
|
if (unsubscribed_notif) { |
|
|
|
notifications = _.reject(notifications, function (notif) { |
|
|
|
return notif[0][1] === "mail.channel" && notif[0][2] === unsubscribed_notif[1].id; |
|
|
|
}); |
|
|
|
} |
|
|
|
_.each(notifications, function (notification) { |
|
|
|
var model = notification[0][1]; |
|
|
|
if (model === 'ir.needaction') { |
|
|
|
// new message in the inbox
|
|
|
|
on_needaction_notification(notification[1]); |
|
|
|
} else if (model === 'mail.channel') { |
|
|
|
// new message in a channel
|
|
|
|
on_channel_notification(notification[1]); |
|
|
|
} else if (model === 'res.partner') { |
|
|
|
// channel joined/left, message marked as read/(un)starred, chat open/closed
|
|
|
|
on_partner_notification(notification[1]); |
|
|
|
} else if (model === 'bus.presence') { |
|
|
|
// update presence of users
|
|
|
|
on_presence_notification(notification[1]); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function on_needaction_notification (message) { |
|
|
|
message = add_message(message, { |
|
|
|
channel_id: 'channel_inbox', |
|
|
|
show_notification: true, |
|
|
|
increment_unread: true, |
|
|
|
}); |
|
|
|
invalidate_caches(message.channel_ids); |
|
|
|
needaction_counter++; |
|
|
|
_.each(message.channel_ids, function (channel_id) { |
|
|
|
var channel = chat_manager.get_channel(channel_id); |
|
|
|
if (channel) { |
|
|
|
channel.needaction_counter++; |
|
|
|
} |
|
|
|
}); |
|
|
|
chat_manager.bus.trigger('update_needaction', needaction_counter); |
|
|
|
} |
|
|
|
|
|
|
|
function on_channel_notification (message) { |
|
|
|
var def; |
|
|
|
var channel_already_in_cache = true; |
|
|
|
if (message.channel_ids.length === 1) { |
|
|
|
channel_already_in_cache = !!chat_manager.get_channel(message.channel_ids[0]); |
|
|
|
def = chat_manager.join_channel(message.channel_ids[0], {autoswitch: false}); |
|
|
|
} else { |
|
|
|
def = $.when(); |
|
|
|
} |
|
|
|
def.then(function () { |
|
|
|
// don't increment unread if channel wasn't in cache yet as its unread counter has just been fetched
|
|
|
|
add_message(message, { show_notification: true, increment_unread: channel_already_in_cache }); |
|
|
|
invalidate_caches(message.channel_ids); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function on_partner_notification (data) { |
|
|
|
if (data.info === "unsubscribe") { |
|
|
|
remove_channel(chat_manager.get_channel(data.id)); |
|
|
|
chat_manager.bus.trigger("unsubscribe_from_channel", data.id); |
|
|
|
} else if (data.type === 'toggle_star') { |
|
|
|
on_toggle_star_notification(data); |
|
|
|
} else if (data.type === 'mark_as_read') { |
|
|
|
on_mark_as_read_notification(data); |
|
|
|
} else if (data.type === 'mark_as_unread') { |
|
|
|
on_mark_as_unread_notification(data); |
|
|
|
} else if (data.info === 'channel_seen') { |
|
|
|
on_channel_seen_notification(data); |
|
|
|
} else { |
|
|
|
on_chat_session_notification(data); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function on_toggle_star_notification (data) { |
|
|
|
_.each(data.message_ids, function (msg_id) { |
|
|
|
var message = _.findWhere(messages, { id: msg_id }); |
|
|
|
if (message) { |
|
|
|
invalidate_caches(message.channel_ids); |
|
|
|
message.is_starred = data.starred; |
|
|
|
if (!message.is_starred) { |
|
|
|
remove_message_from_channel("channel_starred", message); |
|
|
|
} else { |
|
|
|
add_to_cache(message, []); |
|
|
|
var channel_starred = chat_manager.get_channel('channel_starred'); |
|
|
|
channel_starred.cache = _.pick(channel_starred.cache, "[]"); |
|
|
|
} |
|
|
|
chat_manager.bus.trigger('update_message', message); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function on_mark_as_read_notification (data) { |
|
|
|
_.each(data.message_ids, function (msg_id) { |
|
|
|
var message = _.findWhere(messages, { id: msg_id }); |
|
|
|
if (message) { |
|
|
|
invalidate_caches(message.channel_ids); |
|
|
|
remove_message_from_channel("channel_inbox", message); |
|
|
|
chat_manager.bus.trigger('update_message', message); |
|
|
|
} |
|
|
|
}); |
|
|
|
if (data.channel_ids) { |
|
|
|
_.each(data.channel_ids, function (channel_id) { |
|
|
|
var channel = chat_manager.get_channel(channel_id); |
|
|
|
if (channel) { |
|
|
|
channel.needaction_counter = Math.max(channel.needaction_counter - data.message_ids.length, 0); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { // if no channel_ids specified, this is a 'mark all read' in the inbox
|
|
|
|
_.each(channels, function (channel) { |
|
|
|
channel.needaction_counter = 0; |
|
|
|
}); |
|
|
|
} |
|
|
|
needaction_counter = Math.max(needaction_counter - data.message_ids.length, 0); |
|
|
|
chat_manager.bus.trigger('update_needaction', needaction_counter); |
|
|
|
} |
|
|
|
|
|
|
|
function on_mark_as_unread_notification (data) { |
|
|
|
_.each(data.message_ids, function (message_id) { |
|
|
|
var message = _.findWhere(messages, { id: message_id }); |
|
|
|
if (message) { |
|
|
|
invalidate_caches(message.channel_ids); |
|
|
|
add_channel_to_message(message, 'channel_inbox'); |
|
|
|
add_to_cache(message, []); |
|
|
|
} |
|
|
|
}); |
|
|
|
var channel_inbox = chat_manager.get_channel('channel_inbox'); |
|
|
|
channel_inbox.cache = _.pick(channel_inbox.cache, "[]"); |
|
|
|
|
|
|
|
_.each(data.channel_ids, function (channel_id) { |
|
|
|
var channel = chat_manager.get_channel(channel_id); |
|
|
|
if (channel) { |
|
|
|
channel.needaction_counter += data.message_ids.length; |
|
|
|
} |
|
|
|
}); |
|
|
|
needaction_counter += data.message_ids.length; |
|
|
|
chat_manager.bus.trigger('update_needaction', needaction_counter); |
|
|
|
} |
|
|
|
|
|
|
|
function on_channel_seen_notification (data) { |
|
|
|
var channel = chat_manager.get_channel(data.id); |
|
|
|
if (channel) { |
|
|
|
channel.last_seen_message_id = data.last_message_id; |
|
|
|
if (channel.unread_counter) { |
|
|
|
update_channel_unread_counter(channel, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function on_chat_session_notification (chat_session) { |
|
|
|
var channel; |
|
|
|
if ((chat_session.channel_type === "channel") && (chat_session.state === "open")) { |
|
|
|
add_channel(chat_session, {autoswitch: false}); |
|
|
|
if (!chat_session.is_minimized && chat_session.info !== 'creation') { |
|
|
|
web_client.do_notify(_t("Invitation"), _t("You have been invited to: ") + chat_session.name); |
|
|
|
} |
|
|
|
} |
|
|
|
// partner specific change (open a detached window for example)
|
|
|
|
if ((chat_session.state === "open") || (chat_session.state === "folded")) { |
|
|
|
channel = chat_session.is_minimized && chat_manager.get_channel(chat_session.id); |
|
|
|
if (channel) { |
|
|
|
channel.is_detached = true; |
|
|
|
channel.is_folded = (chat_session.state === "folded"); |
|
|
|
chat_manager.bus.trigger("open_chat", channel); |
|
|
|
} |
|
|
|
} else if (chat_session.state === "closed") { |
|
|
|
channel = chat_manager.get_channel(chat_session.id); |
|
|
|
if (channel) { |
|
|
|
channel.is_detached = false; |
|
|
|
chat_manager.bus.trigger("close_chat", channel, {keep_open_if_unread: true}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function on_presence_notification (data) { |
|
|
|
var dm = chat_manager.get_dm_from_partner_id(data.id); |
|
|
|
if (dm) { |
|
|
|
dm.status = data.im_status; |
|
|
|
chat_manager.bus.trigger('update_dm_presence', dm); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Public interface
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// these two functions are exposed for extensibility purposes and shouldn't be called by other modules
|
|
|
|
chat_manager.make_message = make_message; |
|
|
|
chat_manager.make_channel = make_channel; |
|
|
|
|
|
|
|
chat_manager.get_channel = function (id) { |
|
|
|
return _.findWhere(channels, {id: id}); |
|
|
|
chat_manager.post_message = function (data, options) { |
|
|
|
options = options || {}; |
|
|
|
var msg = { |
|
|
|
partner_ids: data.partner_ids, |
|
|
|
body: _.str.trim(data.content), |
|
|
|
attachment_ids: data.attachment_ids, |
|
|
|
}; |
|
|
|
if ('subject' in data) { |
|
|
|
msg.subject = data.subject; |
|
|
|
} |
|
|
|
if ('channel_id' in options) { |
|
|
|
// post a message in a channel
|
|
|
|
return ChannelModel.call('message_post', [options.channel_id], _.extend(msg, { |
|
|
|
message_type: 'comment', |
|
|
|
content_subtype: 'html', |
|
|
|
subtype: 'mail.mt_comment', |
|
|
|
})); |
|
|
|
} |
|
|
|
if ('model' in options && 'res_id' in options) { |
|
|
|
// post a message in a chatter
|
|
|
|
_.extend(msg, { |
|
|
|
content_subtype: data.content_subtype, |
|
|
|
context: data.context, |
|
|
|
message_type: data.message_type, |
|
|
|
subtype: data.subtype, |
|
|
|
subtype_id: data.subtype_id, |
|
|
|
}); |
|
|
|
|
|
|
|
var model = new Model(options.model); |
|
|
|
return model.call('message_post', [options.res_id], msg).then(function (msg_id) { |
|
|
|
return MessageModel.call('message_format', [msg_id]).then(function (msgs) { |
|
|
|
msgs[0].model = options.model; |
|
|
|
msgs[0].res_id = options.res_id; |
|
|
|
add_message(msgs[0]); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_message = function (id) { |
|
|
|
return _.findWhere(messages, {id: id}); |
|
|
|
}; |
|
|
|
chat_manager.get_messages = function (options) { |
|
|
|
var channel; |
|
|
|
|
|
|
@ -343,12 +760,35 @@ chat_manager.get_messages = function (options) { |
|
|
|
}); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.toggle_star_status = function (message_id) { |
|
|
|
var msg = _.findWhere(messages, { id: message_id }); |
|
|
|
|
|
|
|
return MessageModel.call('set_message_starred', [[message_id], !msg.is_starred]); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.unstar_all = function () { |
|
|
|
return MessageModel.call('unstar_all', [[]], {}); |
|
|
|
}; |
|
|
|
chat_manager.mark_as_read = function (message_ids) { |
|
|
|
var ids = _.filter(message_ids, function (id) { |
|
|
|
var message = _.findWhere(messages, {id: id}); |
|
|
|
// If too many messages, not all are fetched, and some might not be found
|
|
|
|
return !message || message.is_needaction; |
|
|
|
}); |
|
|
|
if (ids.length) { |
|
|
|
return MessageModel.call('set_message_done', [ids]); |
|
|
|
} else { |
|
|
|
return $.when(); |
|
|
|
} |
|
|
|
}; |
|
|
|
chat_manager.mark_all_as_read = function (channel, domain) { |
|
|
|
if ((channel.id === "channel_inbox" && needaction_counter) || (channel && channel.needaction_counter)) { |
|
|
|
return MessageModel.call('mark_all_as_read', [], {channel_ids: channel.id !== "channel_inbox" ? [channel.id] : [], domain: domain}); |
|
|
|
} |
|
|
|
return $.when(); |
|
|
|
}; |
|
|
|
chat_manager.undo_mark_as_read = function (message_ids, channel) { |
|
|
|
return MessageModel.call('mark_as_unread', [message_ids, [channel.id]]); |
|
|
|
}; |
|
|
|
chat_manager.mark_channel_as_seen = function (channel) { |
|
|
|
if (channel.unread_counter > 0 && channel.type !== 'static') { |
|
|
|
update_channel_unread_counter(channel, 0); |
|
|
@ -356,18 +796,236 @@ chat_manager.mark_channel_as_seen = function (channel) { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.mark_all_as_read = function (channel, domain) { |
|
|
|
if ((channel.id === "channel_inbox" && needaction_counter) || (channel && channel.needaction_counter)) { |
|
|
|
return MessageModel.call('mark_all_as_read', [], {channel_ids: channel.id !== "channel_inbox" ? [channel.id] : [], domain: domain}); |
|
|
|
chat_manager.get_channels = function () { |
|
|
|
return _.clone(channels); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_channel = function (id) { |
|
|
|
return _.findWhere(channels, {id: id}); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_dm_from_partner_id = function (partner_id) { |
|
|
|
return _.findWhere(channels, {direct_partner_id: partner_id}); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.all_history_loaded = function (channel, domain) { |
|
|
|
return get_channel_cache(channel, domain).all_history_loaded; |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_mention_partner_suggestions = function (channel) { |
|
|
|
if (!channel) { |
|
|
|
return mention_partner_suggestions; |
|
|
|
} |
|
|
|
return $.when(); |
|
|
|
if (!channel.members_deferred) { |
|
|
|
channel.members_deferred = ChannelModel |
|
|
|
.call("channel_fetch_listeners", [channel.uuid], {}, {shadow: true}) |
|
|
|
.then(function (members) { |
|
|
|
var suggestions = []; |
|
|
|
_.each(mention_partner_suggestions, function (partners) { |
|
|
|
suggestions.push(_.filter(partners, function (partner) { |
|
|
|
return !_.findWhere(members, { id: partner.id }); |
|
|
|
})); |
|
|
|
}); |
|
|
|
|
|
|
|
return [members]; |
|
|
|
}); |
|
|
|
} |
|
|
|
return channel.members_deferred; |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_emojis = function() { |
|
|
|
return emojis; |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_needaction_counter = function () { |
|
|
|
return needaction_counter; |
|
|
|
}; |
|
|
|
chat_manager.get_chat_unread_counter = function () { |
|
|
|
return chat_unread_counter; |
|
|
|
}; |
|
|
|
chat_manager.get_unread_conversation_counter = function () { |
|
|
|
return unread_conversation_counter; |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_last_seen_message = function (channel) { |
|
|
|
if (channel.last_seen_message_id) { |
|
|
|
var messages = channel.cache['[]'].messages; |
|
|
|
var msg = _.findWhere(messages, {id: channel.last_seen_message_id}); |
|
|
|
if (msg) { |
|
|
|
var i = _.sortedIndex(messages, msg, 'id') + 1; |
|
|
|
while (i < messages.length && (messages[i].is_author || messages[i].is_system_notification)) { |
|
|
|
msg = messages[i]; |
|
|
|
i++; |
|
|
|
} |
|
|
|
return msg; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_discuss_ids = function () { |
|
|
|
return discuss_ids; |
|
|
|
} |
|
|
|
|
|
|
|
chat_manager.detach_channel = function (channel) { |
|
|
|
return ChannelModel.call("channel_minimize", [channel.uuid, true], {}, {shadow: true}); |
|
|
|
}; |
|
|
|
chat_manager.remove_chatter_messages = function (model) { |
|
|
|
messages = _.reject(messages, function (message) { |
|
|
|
return message.channel_ids.length === 0 && message.model === model; |
|
|
|
}); |
|
|
|
}; |
|
|
|
chat_manager.bus = new core.Bus(); |
|
|
|
|
|
|
|
chat_manager.create_channel = function (name, type) { |
|
|
|
var method = type === "dm" ? "channel_get" : "channel_create"; |
|
|
|
var args = type === "dm" ? [[name]] : [name, type]; |
|
|
|
|
|
|
|
return ChannelModel |
|
|
|
.call(method, args) |
|
|
|
.then(add_channel); |
|
|
|
}; |
|
|
|
chat_manager.join_channel = function (channel_id, options) { |
|
|
|
if (channel_id in channel_defs) { |
|
|
|
// prevents concurrent calls to channel_join_and_get_info
|
|
|
|
return channel_defs[channel_id]; |
|
|
|
} |
|
|
|
var channel = this.get_channel(channel_id); |
|
|
|
if (channel) { |
|
|
|
// channel already joined
|
|
|
|
channel_defs[channel_id] = $.when(channel); |
|
|
|
} else { |
|
|
|
channel_defs[channel_id] = ChannelModel |
|
|
|
.call('channel_join_and_get_info', [[channel_id]]) |
|
|
|
.then(function (result) { |
|
|
|
return add_channel(result, options); |
|
|
|
}); |
|
|
|
} |
|
|
|
return channel_defs[channel_id]; |
|
|
|
}; |
|
|
|
chat_manager.open_and_detach_dm = function (partner_id) { |
|
|
|
return ChannelModel.call('channel_get_and_minimize', [[partner_id]]).then(add_channel); |
|
|
|
}; |
|
|
|
chat_manager.open_channel = function (channel) { |
|
|
|
chat_manager.bus.trigger(client_action_open ? 'open_channel' : 'detach_channel', channel); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.unsubscribe = function (channel) { |
|
|
|
var def; |
|
|
|
if (_.contains(['public', 'private'], channel.type)) { |
|
|
|
def = ChannelModel.call('action_unfollow', [[channel.id]]); |
|
|
|
} else { |
|
|
|
def = ChannelModel.call('channel_pin', [channel.uuid, false]); |
|
|
|
} |
|
|
|
return def.then(function () { |
|
|
|
remove_channel(channel); |
|
|
|
}); |
|
|
|
}; |
|
|
|
chat_manager.close_chat_session = function (channel_id) { |
|
|
|
var channel = this.get_channel(channel_id); |
|
|
|
ChannelModel.call("channel_fold", [], {uuid : channel.uuid, state : "closed"}, {shadow: true}); |
|
|
|
}; |
|
|
|
chat_manager.fold_channel = function (channel_id, folded) { |
|
|
|
var args = { |
|
|
|
uuid: this.get_channel(channel_id).uuid, |
|
|
|
}; |
|
|
|
if (_.isBoolean(folded)) { |
|
|
|
args.state = folded ? 'folded' : 'open'; |
|
|
|
} |
|
|
|
return ChannelModel.call("channel_fold", [], args, {shadow: true}); |
|
|
|
}; |
|
|
|
/** |
|
|
|
* Special redirection handling for given model and id |
|
|
|
* |
|
|
|
* If the model is res.partner, and there is a user associated with this |
|
|
|
* partner which isn't the current user, open the DM with this user. |
|
|
|
* Otherwhise, open the record's form view, if this is not the current user's. |
|
|
|
*/ |
|
|
|
chat_manager.redirect = function (res_model, res_id, dm_redirection_callback) { |
|
|
|
var self = this; |
|
|
|
var redirect_to_document = function (res_model, res_id, view_id) { |
|
|
|
web_client.do_action({ |
|
|
|
type:'ir.actions.act_window', |
|
|
|
view_type: 'form', |
|
|
|
view_mode: 'form', |
|
|
|
res_model: res_model, |
|
|
|
views: [[view_id || false, 'form']], |
|
|
|
res_id: res_id, |
|
|
|
}); |
|
|
|
}; |
|
|
|
if (res_model === "res.partner") { |
|
|
|
var domain = [["partner_id", "=", res_id]]; |
|
|
|
UserModel.call("search", [domain]).then(function (user_ids) { |
|
|
|
if (user_ids.length && user_ids[0] !== session.uid) { |
|
|
|
self.create_channel(res_id, 'dm').then(dm_redirection_callback || function () {}); |
|
|
|
} else if (!user_ids.length) { |
|
|
|
redirect_to_document(res_model, res_id); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
new Model(res_model).call('get_formview_id', [res_id, session.context]).then(function (view_id) { |
|
|
|
redirect_to_document(res_model, res_id, view_id); |
|
|
|
}); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.get_channels_preview = function (channels) { |
|
|
|
var channels_preview = _.map(channels, function (channel) { |
|
|
|
var info = _.pick(channel, 'id', 'is_chat', 'name', 'status', 'unread_counter'); |
|
|
|
info.last_message = _.last(channel.cache['[]'].messages); |
|
|
|
if (!info.is_chat) { |
|
|
|
info.image_src = '/web/image/mail.channel/'+channel.id+'/image_small'; |
|
|
|
} else if (channel.direct_partner_id) { |
|
|
|
info.image_src = '/web/image/res.partner/'+channel.direct_partner_id+'/image_small'; |
|
|
|
} else { |
|
|
|
info.image_src = '/mail/static/src/img/smiley/avatar.jpg'; |
|
|
|
} |
|
|
|
return info; |
|
|
|
}); |
|
|
|
var missing_channels = _.where(channels_preview, {last_message: undefined}); |
|
|
|
if (!channels_preview_def) { |
|
|
|
if (missing_channels.length) { |
|
|
|
var missing_channel_ids = _.pluck(missing_channels, 'id'); |
|
|
|
channels_preview_def = ChannelModel.call('channel_fetch_preview', [missing_channel_ids], {}, {shadow: true}); |
|
|
|
} else { |
|
|
|
channels_preview_def = $.when(); |
|
|
|
} |
|
|
|
} |
|
|
|
return channels_preview_def.then(function (channels) { |
|
|
|
_.each(missing_channels, function (channel_preview) { |
|
|
|
var channel = _.findWhere(channels, {id: channel_preview.id}); |
|
|
|
if (channel) { |
|
|
|
channel_preview.last_message = add_message(channel.last_message); |
|
|
|
} |
|
|
|
}); |
|
|
|
return _.filter(channels_preview, function (channel) { |
|
|
|
return channel.last_message; // remove empty channels
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
chat_manager.get_message_body_preview = function (message_body) { |
|
|
|
return parse_and_transform(message_body, inline); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.search_partner = function (search_val, limit) { |
|
|
|
return PartnerModel.call('im_search', [search_val, limit || 20], {}, {shadow: true}).then(function(result) { |
|
|
|
var values = []; |
|
|
|
_.each(result, function(user) { |
|
|
|
var escaped_name = _.escape(user.name); |
|
|
|
values.push(_.extend(user, { |
|
|
|
'value': escaped_name, |
|
|
|
'label': escaped_name, |
|
|
|
})); |
|
|
|
}); |
|
|
|
return values; |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
chat_manager.send_native_notification = send_native_notification; |
|
|
|
|
|
|
|
chat_manager.bus.on('client_action_open', null, function (open) { |
|
|
|
client_action_open = open; |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Initialization
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
function init () { |
|
|
@ -408,19 +1066,19 @@ function init () { |
|
|
|
var load_menu_id = ir_model.call("xmlid_to_res_id", ["mail.mail_channel_menu_root_chat"], {}, {shadow: true}); |
|
|
|
var load_action_id = ir_model.call("xmlid_to_res_id", ["mail.mail_channel_action_client_chat"], {}, {shadow: true}); |
|
|
|
|
|
|
|
// bus.on('notification', null, on_notification);
|
|
|
|
bus.on('notification', null, on_notification); |
|
|
|
|
|
|
|
return $.when(load_menu_id, load_action_id, load_channels, load_emojis).then(function (menu_id, action_id) { |
|
|
|
discuss_ids = { |
|
|
|
menu_id: menu_id, |
|
|
|
action_id: action_id |
|
|
|
action_id: action_id, |
|
|
|
}; |
|
|
|
bus.start_polling(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
chat_manager.is_ready = init(); |
|
|
|
console.log('q2w'); |
|
|
|
return chat_manager; |
|
|
|
|
|
|
|
}); |