odoo.define('im_livechat/static/tests/helpers/mock_server.js', function (require) { 'use strict'; require('mail.MockServer'); // ensure mail overrides are applied first const MockServer = require('web.MockServer'); MockServer.include({ //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** * @override */ async _performRpc(route, args) { if (route === '/im_livechat/get_session') { const channel_id = args.channel_id; const anonymous_name = args.anonymous_name; const previous_operator_id = args.previous_operator_id; const context = args.context; return this._mockRouteImLivechatGetSession(channel_id, anonymous_name, previous_operator_id, context); } if (route === '/im_livechat/notify_typing') { const uuid = args.uuid; const is_typing = args.is_typing; const context = args.context; return this._mockRouteImLivechatNotifyTyping(uuid, is_typing, context); } return this._super(...arguments); }, //-------------------------------------------------------------------------- // Private Mocked Routes //-------------------------------------------------------------------------- /** * Simulates the `/im_livechat/get_session` route. * * @private * @param {integer} channel_id * @param {string} anonymous_name * @param {integer} [previous_operator_id] * @param {Object} [context={}] * @returns {Object} */ _mockRouteImLivechatGetSession(channel_id, anonymous_name, previous_operator_id, context = {}) { let user_id; let country_id; if ('mockedUserId' in context) { // can be falsy to simulate not being logged in user_id = context.mockedUserId; } else { user_id = this.currentUserId; } // don't use the anonymous name if the user is logged in if (user_id) { const user = this._getRecords('res.users', [['id', '=', user_id]])[0]; country_id = user.country_id; } else { // simulate geoip const countryCode = context.mockedCountryCode; const country = this._getRecords('res.country', [['code', '=', countryCode]])[0]; if (country) { country_id = country.id; anonymous_name = anonymous_name + ' (' + country.name + ')'; } } return this._mockImLivechatChannel_openLivechatMailChannel(channel_id, anonymous_name, previous_operator_id, user_id, country_id); }, /** * Simulates the `/im_livechat/notify_typing` route. * * @private * @param {string} uuid * @param {boolean} is_typing * @param {Object} [context] */ _mockRouteImLivechatNotifyTyping(uuid, is_typing, context) { const mailChannel = this._getRecords('mail.channel', [['uuid', '=', uuid]])[0]; this._mockMailChannelNotifyTyping([mailChannel.id], is_typing, context); }, /** * @override */ _mockRouteMailInitMessaging() { const initMessaging = this._super(...arguments); const livechats = this._getRecords('mail.channel', [ ['channel_type', '=', 'livechat'], ['is_pinned', '=', true], ['members', 'in', this.currentPartnerId], ]); initMessaging.channel_slots.channel_livechat = this._mockMailChannelChannelInfo( livechats.map(channel => channel.id) ); return initMessaging; }, //-------------------------------------------------------------------------- // Private Mocked Methods //-------------------------------------------------------------------------- /** * Simulates `_channel_get_livechat_visitor_info` on `mail.channel`. * * @private * @param {integer[]} ids * @returns {Object} */ _mockMailChannel_ChannelGetLivechatVisitorInfo(ids) { const id = ids[0]; // ensure_one const mailChannel = this._getRecords('mail.channel', [['id', '=', id]])[0]; // remove active test to ensure public partner is taken into account let members = this._getRecords( 'res.partner', [['id', 'in', mailChannel.members]], { active_test: false }, ); members = members.filter(member => member.id !== mailChannel.livechat_operator_id); if (members.length === 0 && mailChannel.livechat_operator_id) { // operator probably testing the livechat with his own user members = [mailChannel.livechat_operator_id]; } if (members.length > 0 && members[0].id !== this.publicPartnerId) { // legit non-public partner const country = this._getRecords('res.country', [['id', '=', members[0].country_id]])[0]; return { 'country': country ? [country.id, country.name] : false, 'id': members[0].id, 'name': members[0].name, }; } return { 'country': false, 'id': false, 'name': mailChannel.anonymous_name || "Visitor", }; }, /** * @override */ _mockMailChannelChannelInfo(ids, extra_info) { const channelInfos = this._super(...arguments); for (const channelInfo of channelInfos) { const channel = this._getRecords('mail.channel', [['id', '=', channelInfo.id]])[0]; // add the last message date if (channel.channel_type === 'livechat') { // add the operator id if (channel.livechat_operator_id) { const operator = this._getRecords('res.partner', [['id', '=', channel.livechat_operator_id]])[0]; // livechat_username ignored for simplicity channelInfo.operator_pid = [operator.id, operator.display_name.replace(',', '')]; } // add the anonymous or partner name channelInfo.livechat_visitor = this._mockMailChannel_ChannelGetLivechatVisitorInfo([channel.id]); } } return channelInfos; }, /** * Simulates `_get_available_users` on `im_livechat.channel`. * * @private * @param {integer} id * @returns {Object} */ _mockImLivechatChannel_getAvailableUsers(id) { const livechatChannel = this._getRecords('im_livechat.channel', [['id', '=', id]])[0]; const users = this._getRecords('res.users', [['id', 'in', livechatChannel.user_ids]]); return users.filter(user => user.im_status === 'online'); }, /** * Simulates `_get_livechat_mail_channel_vals` on `im_livechat.channel`. * * @private * @param {integer} id * @returns {Object} */ _mockImLivechatChannel_getLivechatMailChannelVals(id, anonymous_name, operator, user_id, country_id) { // partner to add to the mail.channel const operator_partner_id = operator.partner_id; const members = [[4, operator_partner_id]]; let visitor_user; if (user_id) { const visitor_user = this._getRecords('res.users', [['id', '=', user_id]])[0]; if (visitor_user && visitor_user.active) { // valid session user (not public) members.push([4, visitor_user.partner_id.id]); } } else { // for simplicity of not having mocked channel.partner, add public partner here members.push([4, this.publicPartnerId]); } const membersName = [ visitor_user ? visitor_user.display_name : anonymous_name, operator.livechat_username ? operator.livechat_username : operator.name, ]; return { // Limitation of mocked models not having channel.partner: is_pinned // is not supposed to be false for the visitor but must be false for // the operator (writing on channel_partner_ids does not trigger the // defaults that would set it to true) and here operator and visitor // can't be differentiated in that regard. 'is_pinned': false, 'members': members, // channel_partner_ids 'livechat_active': true, 'livechat_operator_id': operator_partner_id, 'livechat_channel_id': id, 'anonymous_name': user_id ? false : anonymous_name, 'country_id': country_id, 'channel_type': 'livechat', 'name': membersName.join(' '), 'public': 'private', 'mass_mailing': false, // email_send }; }, /** * Simulates `_get_random_operator` on `im_livechat.channel`. * Simplified mock implementation: returns the first available operator. * * @private * @param {integer} id * @returns {Object} */ _mockImLivechatChannel_getRandomOperator(id) { const availableUsers = this._mockImLivechatChannel_getAvailableUsers(id); return availableUsers[0]; }, /** * Simulates `_open_livechat_mail_channel` on `im_livechat.channel`. * * @private * @param {integer} id * @param {string} anonymous_name * @param {integer} [previous_operator_id] * @param {integer} [user_id] * @param {integer} [country_id] * @returns {Object} */ _mockImLivechatChannel_openLivechatMailChannel(id, anonymous_name, previous_operator_id, user_id, country_id) { let operator; if (previous_operator_id) { const availableUsers = this._mockImLivechatChannel_getAvailableUsers(id); operator = availableUsers.find(user => user.partner_id === previous_operator_id); } if (!operator) { operator = this._mockImLivechatChannel_getRandomOperator(id); } if (!operator) { // no one available return false; } // create the session, and add the link with the given channel const mailChannelVals = this._mockImLivechatChannel_getLivechatMailChannelVals(id, anonymous_name, operator, user_id, country_id); const mailChannelId = this._mockCreate('mail.channel', mailChannelVals); this._mockMailChannel_broadcast([mailChannelId], [operator.partner_id]); return this._mockMailChannelChannelInfo([mailChannelId])[0]; }, }); });