*: bus, hr_holidays. The `/bus/im_status` route polls the server every minute in order for the user im_status to be up to date. This commit removes this poll by sending the im_status on the bus when updating the current user presence. Moreover, before [1], the user bus presence was updated on each poll. When the user didn't poll for 50 seconds, we assumed the user was disconnected. Since [1], the bus presence is updated each 30 seconds by the `im_status` service. This is too frequent: there is no need to update the user presence so often. In order not to overhelm the server with unnecessary requests, the update presence interval as well as the delay to be considered disconnected have been updated: the former from 30 to 60 seconds, the later from 55 to 65 seconds (assuming that a user that has missed an update presence tick is disconnected). [1]: odoo/odoo@a5623d2 closes odoo/odoo#100249 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
231 lines
8.0 KiB
JavaScript
231 lines
8.0 KiB
JavaScript
/** @odoo-module **/
|
|
|
|
import { registerModel } from '@mail/model/model_core';
|
|
import { insert } from '@mail/model/model_field_command';
|
|
|
|
registerModel({
|
|
name: 'MessagingInitializer',
|
|
recordMethods: {
|
|
/**
|
|
* @returns {Object}
|
|
*/
|
|
async performInitRpc() {
|
|
return await this.messaging.rpc({
|
|
route: '/mail/init_messaging',
|
|
}, { shadow: true });
|
|
},
|
|
/**
|
|
* Fetch messaging data initially to populate the store specifically for
|
|
* the current user. This includes pinned channels for instance.
|
|
*/
|
|
async start() {
|
|
this.messaging.device.start();
|
|
const discuss = this.messaging.discuss;
|
|
const data = await this.performInitRpc();
|
|
if (!this.exists()) {
|
|
return;
|
|
}
|
|
await this._init(data);
|
|
if (!this.exists()) {
|
|
return;
|
|
}
|
|
if (discuss.discussView) {
|
|
discuss.openInitThread();
|
|
}
|
|
if (this.messaging.currentUser) {
|
|
this.messaging.updateImStatusRegistration();
|
|
this._loadMessageFailures();
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {Object} param0
|
|
* @param {Object[]} param0.channels
|
|
* @param {Object} param0.currentGuest
|
|
* @param {Object} param0.current_partner
|
|
* @param {integer} param0.current_user_id
|
|
* @param {Object} param0.current_user_settings
|
|
* @param {boolean} [param0.hasLinkPreviewFeature]
|
|
* @param {integer} [param0.internalUserGroupId]
|
|
* @param {integer} [param0.needaction_inbox_counter=0]
|
|
* @param {Object} param0.partner_root
|
|
* @param {Object[]} [param0.shortcodes=[]]
|
|
* @param {integer} [param0.starred_counter=0]
|
|
*/
|
|
async _init({
|
|
channels,
|
|
commands = [],
|
|
companyName,
|
|
current_partner,
|
|
currentGuest,
|
|
current_user_id,
|
|
current_user_settings,
|
|
hasLinkPreviewFeature,
|
|
internalUserGroupId,
|
|
menu_id,
|
|
needaction_inbox_counter = 0,
|
|
partner_root,
|
|
shortcodes = [],
|
|
starred_counter = 0,
|
|
}) {
|
|
const discuss = this.messaging.discuss;
|
|
// partners first because the rest of the code relies on them
|
|
this._initPartners({
|
|
currentGuest,
|
|
current_partner,
|
|
current_user_id,
|
|
partner_root,
|
|
});
|
|
// mailboxes after partners and before other initializers that might
|
|
// manipulate threads or messages
|
|
this._initMailboxes({
|
|
needaction_inbox_counter,
|
|
starred_counter,
|
|
});
|
|
// init mail user settings
|
|
if (current_user_settings) {
|
|
this.messaging.models['res.users.settings'].insert(current_user_settings);
|
|
}
|
|
// various suggestions in no particular order
|
|
this._initCannedResponses(shortcodes);
|
|
// FIXME: guests should have (at least some) commands available
|
|
if (!this.messaging.isCurrentUserGuest) {
|
|
this._initCommands();
|
|
}
|
|
// channels when the rest of messaging is ready
|
|
if (channels) {
|
|
await this._initChannels(channels);
|
|
}
|
|
if (!this.exists()) {
|
|
return;
|
|
}
|
|
discuss.update({ menu_id });
|
|
// company related data
|
|
this.messaging.update({ companyName, hasLinkPreviewFeature, internalUserGroupId });
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {Object[]} cannedResponsesData
|
|
*/
|
|
_initCannedResponses(cannedResponsesData) {
|
|
this.messaging.update({
|
|
cannedResponses: insert(cannedResponsesData),
|
|
});
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {Object[]} channelsData
|
|
*/
|
|
async _initChannels(channelsData) {
|
|
return this.messaging.executeGracefully(channelsData.map(channelData => () => {
|
|
if (!this.exists()) {
|
|
return;
|
|
}
|
|
const convertedData = this.messaging.models['Thread'].convertData(channelData);
|
|
const channel = this.messaging.models['Thread'].insert(
|
|
Object.assign({ model: 'mail.channel' }, convertedData)
|
|
);
|
|
// flux specific: channels received at init have to be
|
|
// considered pinned. task-2284357
|
|
if (!channel.isPinned) {
|
|
channel.pin();
|
|
}
|
|
}));
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
_initCommands() {
|
|
this.messaging.update({
|
|
commands: insert([
|
|
{
|
|
help: this.env._t("Show a helper message"),
|
|
methodName: 'execute_command_help',
|
|
name: "help",
|
|
},
|
|
{
|
|
help: this.env._t("Leave this channel"),
|
|
methodName: 'execute_command_leave',
|
|
name: "leave",
|
|
},
|
|
{
|
|
channel_types: ['channel', 'chat', 'group'],
|
|
help: this.env._t("List users in the current channel"),
|
|
methodName: 'execute_command_who',
|
|
name: "who",
|
|
}
|
|
]),
|
|
});
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {Object} param0
|
|
* @param {integer} param0.needaction_inbox_counter
|
|
* @param {integer} param0.starred_counter
|
|
*/
|
|
_initMailboxes({
|
|
needaction_inbox_counter,
|
|
starred_counter,
|
|
}) {
|
|
this.messaging.inbox.update({ counter: needaction_inbox_counter });
|
|
this.messaging.starred.update({ counter: starred_counter });
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {Object[]} mailFailuresData
|
|
*/
|
|
async _initMailFailures(mailFailuresData) {
|
|
await this.messaging.executeGracefully(mailFailuresData.map(messageData => () => {
|
|
if (!this.exists()) {
|
|
return;
|
|
}
|
|
const message = this.messaging.models['Message'].insert(
|
|
this.messaging.models['Message'].convertData(messageData)
|
|
);
|
|
// implicit: failures are sent by the server at initialization
|
|
// only if the current partner is author of the message
|
|
if (!message.author && this.messaging.currentPartner) {
|
|
message.update({ author: this.messaging.currentPartner });
|
|
}
|
|
}));
|
|
},
|
|
/**
|
|
* @private
|
|
* @param {Object} currentGuest
|
|
* @param {Object} current_partner
|
|
* @param {integer} current_user_id
|
|
* @param {Object} partner_root
|
|
*/
|
|
_initPartners({
|
|
currentGuest,
|
|
current_partner,
|
|
current_user_id: currentUserId,
|
|
partner_root,
|
|
}) {
|
|
if (currentGuest) {
|
|
this.messaging.update({ currentGuest: insert(currentGuest) });
|
|
}
|
|
if (current_partner) {
|
|
this.messaging.update({
|
|
currentPartner: current_partner,
|
|
currentUser: insert({ id: currentUserId }),
|
|
});
|
|
}
|
|
if (partner_root) {
|
|
this.messaging.update({
|
|
partnerRoot: partner_root,
|
|
});
|
|
}
|
|
},
|
|
/**
|
|
* @private
|
|
*/
|
|
async _loadMessageFailures() {
|
|
const data = await this.messaging.rpc({
|
|
route: '/mail/load_message_failures',
|
|
}, { shadow: true });
|
|
this._initMailFailures(data);
|
|
},
|
|
},
|
|
});
|