From 07048871af591efcc9a46d0792d2729d33fcf4bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Wed, 29 Dec 2021 15:43:31 +0000 Subject: [PATCH] [FIX] mail, im_livechat, *: restore usage of livechat user name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * = website_livechat Prevents from leaking unnecessary information to livechat clients. opw-2453956 closes odoo/odoo#82026 X-original-commit: 5ec191d288d5b44f78cd1f6980c47bb64cfd9bd1 Signed-off-by: Alexandre Kühn (aku) Signed-off-by: Sébastien Theys (seb) --- addons/im_livechat/data/mail_data.xml | 2 +- addons/im_livechat/models/__init__.py | 1 + addons/im_livechat/models/mail_channel.py | 37 +++++++++++----- addons/im_livechat/models/mail_message.py | 21 +++++++++ addons/im_livechat/models/res_partner.py | 35 ++++----------- .../static/src/models/message/message.js | 26 +++++++++++ .../messaging_notification_handler.js | 15 +++++-- .../static/src/models/partner/partner.js | 28 +++++++++++- .../static/src/models/thread/thread.js | 9 ++++ .../tests/test_get_mail_channel.py | 44 +++++++++++++++++-- addons/mail/models/mail_channel.py | 21 ++++++--- .../static/src/components/message/message.xml | 7 ++- .../message_seen_indicator.js | 18 +++++--- .../message_reaction_group.js | 7 ++- .../mail/static/src/models/partner/partner.js | 9 ++++ .../mail/static/src/models/thread/thread.js | 19 +++++--- .../tests/test_performance.py | 34 +++++--------- addons/website_livechat/models/website.py | 3 +- 18 files changed, 247 insertions(+), 89 deletions(-) create mode 100644 addons/im_livechat/models/mail_message.py create mode 100644 addons/im_livechat/static/src/models/message/message.js diff --git a/addons/im_livechat/data/mail_data.xml b/addons/im_livechat/data/mail_data.xml index 9c8468cac6f..29d1c5e2032 100644 --- a/addons/im_livechat/data/mail_data.xml +++ b/addons/im_livechat/data/mail_data.xml @@ -32,7 +32,7 @@
Hello,
Here's a copy of your conversation with - , on the + , on the
diff --git a/addons/im_livechat/models/__init__.py b/addons/im_livechat/models/__init__.py index 65478d25ced..6abd12e36f4 100644 --- a/addons/im_livechat/models/__init__.py +++ b/addons/im_livechat/models/__init__.py @@ -5,6 +5,7 @@ from . import res_partner from . import im_livechat_channel from . import mail_channel from . import mail_channel_partner +from . import mail_message from . import res_users_settings from . import rating from . import digest diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py index 78584bbfccf..b6f6d1f7b64 100644 --- a/addons/im_livechat/models/mail_channel.py +++ b/addons/im_livechat/models/mail_channel.py @@ -35,10 +35,7 @@ class MailChannel(models.Model): clicking on livechat button). So when the anonymous person is sending its FIRST message, the channel header should be added to the notification, since the user cannot be listining to the channel. """ - livechat_channels = self.filtered(lambda x: x.channel_type == 'livechat') - other_channels = self.filtered(lambda x: x.channel_type != 'livechat') - notifications = super(MailChannel, livechat_channels)._channel_message_notifications(message.with_context(im_livechat_use_username=True)) + \ - super(MailChannel, other_channels)._channel_message_notifications(message, message_format) + notifications = super()._channel_message_notifications(message=message, message_format=message_format) for channel in self: # add uuid for private livechat channels to allow anonymous to listen if channel.channel_type == 'livechat' and channel.public == 'private': @@ -50,11 +47,6 @@ class MailChannel(models.Model): notifications = self._channel_channel_notifications(unpinned_channel_partner.mapped('partner_id').ids) + notifications return notifications - def _channel_fetch_message(self, last_id=False, limit=20): - """ Override to add the context of the livechat username.""" - channel = self.with_context(im_livechat_use_username=True) if self.channel_type == 'livechat' else self - return super(MailChannel, channel)._channel_fetch_message(last_id=last_id, limit=limit) - def channel_info(self): """ Extends the channel header by adding the livechat operator and the 'anonymous' profile :rtype : list(dict) @@ -66,12 +58,33 @@ class MailChannel(models.Model): if channel.channel_type == 'livechat': # add the operator id if channel.livechat_operator_id: - res = channel.livechat_operator_id.with_context(im_livechat_use_username=True).name_get()[0] - channel_infos_dict[channel.id]['operator_pid'] = (res[0], res[1].replace(',', '')) + display_name = channel.livechat_operator_id.user_livechat_username or channel.livechat_operator_id.display_name + channel_infos_dict[channel.id]['operator_pid'] = (channel.livechat_operator_id.id, display_name.replace(',', '')) # add the anonymous or partner name channel_infos_dict[channel.id]['livechat_visitor'] = channel._channel_get_livechat_visitor_info() return list(channel_infos_dict.values()) + def _channel_info_format_member(self, partner, partner_info): + """Override to remove sensitive information in livechat.""" + if self.channel_type == 'livechat': + return { + 'active': partner.active, + 'id': partner.id, + 'name': partner.user_livechat_username or partner.name, # for API compatibility in stable + 'email': False, # for API compatibility in stable + 'im_status': False, # for API compatibility in stable + 'livechat_username': partner.user_livechat_username, + } + return super()._channel_info_format_member(partner=partner, partner_info=partner_info) + + def _notify_typing_partner_data(self): + """Override to remove name and return livechat username if applicable.""" + data = super()._notify_typing_partner_data() + if self.channel_type == 'livechat' and self.env.user.partner_id.user_livechat_username: + data['partner_name'] = self.env.user.partner_id.user_livechat_username # for API compatibility in stable + data['livechat_username'] = self.env.user.partner_id.user_livechat_username + return data + def _channel_get_livechat_visitor_info(self): self.ensure_one() # remove active test to ensure public partner is taken into account @@ -171,7 +184,7 @@ class MailChannel(models.Model): mail_body = template._render(render_context, engine='ir.qweb', minimal_qcontext=True) mail_body = self.env['mail.render.mixin']._replace_local_links(mail_body) mail = self.env['mail.mail'].sudo().create({ - 'subject': _('Conversation with %s', self.livechat_operator_id.name), + 'subject': _('Conversation with %s', self.livechat_operator_id.user_livechat_username or self.livechat_operator_id.name), 'email_from': company.catchall_formatted or company.email_formatted, 'author_id': self.env.user.partner_id.id, 'email_to': email, diff --git a/addons/im_livechat/models/mail_message.py b/addons/im_livechat/models/mail_message.py new file mode 100644 index 00000000000..3e1d1f27993 --- /dev/null +++ b/addons/im_livechat/models/mail_message.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +class MailMessage(models.Model): + _inherit = 'mail.message' + + def _message_format(self, fnames, format_reply=True): + """Override to remove email_from and to return the livechat username if applicable. + A third param is added to the author_id tuple in this case to be able to differentiate it + from the normal name in client code.""" + vals_list = super()._message_format(fnames=fnames, format_reply=format_reply) + for vals in vals_list: + message_sudo = self.browse(vals['id']).sudo().with_prefetch(self.ids) + if message_sudo.model == 'mail.channel' and self.env['mail.channel'].browse(message_sudo.res_id).channel_type == 'livechat': + vals.pop('email_from') + if message_sudo.author_id.user_livechat_username: + vals['author_id'] = (message_sudo.author_id.id, message_sudo.author_id.user_livechat_username, message_sudo.author_id.user_livechat_username) + return vals_list diff --git a/addons/im_livechat/models/res_partner.py b/addons/im_livechat/models/res_partner.py index df2e7a0a493..b3b85cf898f 100644 --- a/addons/im_livechat/models/res_partner.py +++ b/addons/im_livechat/models/res_partner.py @@ -1,38 +1,14 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import models +from odoo import api, models, fields class Partners(models.Model): - """ Update of res.partners class - - override name_get to take into account the livechat username - """ + """Update of res.partner class to take into account the livechat username.""" _inherit = 'res.partner' - def name_get(self): - if self.env.context.get('im_livechat_use_username'): - # process the ones with livechat username - users_with_livechatname = self.env['res.users'].search([('partner_id', 'in', self.ids), ('livechat_username', '!=', False)]) - map_with_livechatname = {} - for user in users_with_livechatname: - map_with_livechatname[user.partner_id.id] = user.livechat_username - - # process the ones without livecaht username - partner_without_livechatname = self - users_with_livechatname.mapped('partner_id') - no_livechatname_name_get = super(Partners, partner_without_livechatname).name_get() - map_without_livechatname = dict(no_livechatname_name_get) - - # restore order - result = [] - for partner in self: - name = map_with_livechatname.get(partner.id) - if not name: - name = map_without_livechatname.get(partner.id) - result.append((partner.id, name)) - else: - result = super(Partners, self).name_get() - return result + user_livechat_username = fields.Char(compute='_compute_user_livechat_username') def _get_channels_as_member(self): channels = super()._get_channels_as_member() @@ -44,3 +20,8 @@ class Partners(models.Model): ])), ]) return channels + + @api.depends('user_ids.livechat_username') + def _compute_user_livechat_username(self): + for partner in self: + partner.user_livechat_username = next(iter(partner.user_ids.mapped('livechat_username')), False) diff --git a/addons/im_livechat/static/src/models/message/message.js b/addons/im_livechat/static/src/models/message/message.js new file mode 100644 index 00000000000..071f2db36ef --- /dev/null +++ b/addons/im_livechat/static/src/models/message/message.js @@ -0,0 +1,26 @@ +/** @odoo-module **/ + +import { patchModelMethods } from '@mail/model/model_core'; +import { insertAndReplace } from '@mail/model/model_field_command'; +// ensure the model definition is loaded before the patch +import '@mail/models/message/message'; + +patchModelMethods('Message', { + /** + * @override + */ + convertData(data) { + const data2 = this._super(data); + if ('author_id' in data) { + if (data.author_id[2]) { + // flux specific for livechat, a 3rd param is livechat_username + // and means 2nd param (display_name) should be ignored + data2.author = insertAndReplace({ + id: data.author_id[0], + livechat_username: data.author_id[2], + }); + } + } + return data2; + }, +}); diff --git a/addons/im_livechat/static/src/models/messaging_notification_handler/messaging_notification_handler.js b/addons/im_livechat/static/src/models/messaging_notification_handler/messaging_notification_handler.js index bcf44370f1f..31bdda1c8d9 100644 --- a/addons/im_livechat/static/src/models/messaging_notification_handler/messaging_notification_handler.js +++ b/addons/im_livechat/static/src/models/messaging_notification_handler/messaging_notification_handler.js @@ -21,7 +21,7 @@ patchRecordMethods('MessagingNotificationHandler', { /** * @override */ - _handleNotificationChannelPartnerTypingStatus({ channel_id, is_typing, partner_id, partner_name }) { + _handleNotificationChannelPartnerTypingStatus({ channel_id, is_typing, livechat_username, partner_id, partner_name }) { const channel = this.messaging.models['Thread'].findFromIdentifyingData({ id: channel_id, model: 'mail.channel', @@ -40,11 +40,20 @@ patchRecordMethods('MessagingNotificationHandler', { partnerId = partner_id; partnerName = partner_name; } - this._super({ + const data = { channel_id, is_typing, partner_id: partnerId, partner_name: partnerName, - }); + }; + if (livechat_username) { + // flux specific, livechat_username is returned instead of name for livechat channels + delete data.partner_name; // value still present for API compatibility in stable + this.models['Partner'].insert({ + id: partnerId, + livechat_username: livechat_username, + }); + } + this._super(data); }, }); diff --git a/addons/im_livechat/static/src/models/partner/partner.js b/addons/im_livechat/static/src/models/partner/partner.js index 664ba0ed06c..db724b865c4 100644 --- a/addons/im_livechat/static/src/models/partner/partner.js +++ b/addons/im_livechat/static/src/models/partner/partner.js @@ -1,6 +1,8 @@ /** @odoo-module **/ -import { addModelMethods } from '@mail/model/model_core'; +import { addFields, addModelMethods, patchModelMethods } from '@mail/model/model_core'; +import { attr } from '@mail/model/model_field'; + // ensure that the model definition is loaded before the patch import '@mail/models/partner/partner'; @@ -14,3 +16,27 @@ addModelMethods('Partner', { }, }); +patchModelMethods('Partner', { + convertData(data) { + const data2 = this._super(data); + if ('livechat_username' in data) { + // flux specific, if livechat username is present it means `name`, + // `email` and `im_status` contain `false` even though their value + // might actually exist. Remove them from data2 to avoid overwriting + // existing value (that could be known through other means). + delete data2.name; + delete data2.email; + delete data2.im_status; + data2.livechat_username = data.livechat_username; + } + return data2; + }, +}); + +addFields('Partner', { + /** + * States the specific name of this partner in the context of livechat. + * Either a string or undefined. + */ + livechat_username: attr(), +}); diff --git a/addons/im_livechat/static/src/models/thread/thread.js b/addons/im_livechat/static/src/models/thread/thread.js index 8c20a97a34c..78f6e5e9bed 100644 --- a/addons/im_livechat/static/src/models/thread/thread.js +++ b/addons/im_livechat/static/src/models/thread/thread.js @@ -77,6 +77,15 @@ patchModelMethods('Thread', { }); patchRecordMethods('Thread', { + /** + * @override + */ + getMemberName(partner) { + if (this.channel_type === 'livechat' && partner.livechat_username) { + return partner.livechat_username; + } + return this._super(partner); + }, /** * @override */ diff --git a/addons/im_livechat/tests/test_get_mail_channel.py b/addons/im_livechat/tests/test_get_mail_channel.py index aa48d8dabbc..9d3571b478d 100644 --- a/addons/im_livechat/tests/test_get_mail_channel.py +++ b/addons/im_livechat/tests/test_get_mail_channel.py @@ -9,7 +9,8 @@ class TestGetMailChannel(TransactionCase): super(TestGetMailChannel, self).setUp() self.operators = self.env['res.users'].create([{ 'name': 'Michel', - 'login': 'michel' + 'login': 'michel', + 'livechat_username': "Michel Operator", }, { 'name': 'Paul', 'login': 'paul' @@ -58,12 +59,30 @@ class TestGetMailChannel(TransactionCase): test_user = self.env['res.users'].create({'name': 'Roger', 'login': 'roger', 'country_id': belgium.id}) # ensure visitor info are correct with anonymous - channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='Visitor 22', country_id=belgium.id) + operator = self.operators[0] + channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='Visitor 22', previous_operator_id=operator.partner_id.id, country_id=belgium.id) visitor_info = channel_info['livechat_visitor'] self.assertFalse(visitor_info['id']) self.assertEqual(visitor_info['name'], "Visitor 22") self.assertEqual(visitor_info['country'], (20, "Belgium")) + # ensure member info are hidden (in particular email and real name when livechat username is present) + self.assertEqual(sorted(channel_info['members'], key=lambda m: m['id']), sorted([{ + 'active': True, + 'email': False, + 'id': operator.partner_id.id, + 'im_status': False, + 'livechat_username': 'Michel Operator', + 'name': 'Michel Operator', + }, { + 'active': False, + 'email': False, + 'id': public_user.partner_id.id, + 'im_status': False, + 'livechat_username': False, + 'name': 'Public user', + }], key=lambda m: m['id'])) + # ensure visitor info are correct with real user channel_info = self.livechat_channel.with_user(test_user)._open_livechat_mail_channel(anonymous_name='whatever', user_id=test_user.id) visitor_info = channel_info['livechat_visitor'] @@ -74,7 +93,7 @@ class TestGetMailChannel(TransactionCase): # ensure visitor info are correct when operator is testing himself operator = self.operators[0] channel_info = self.livechat_channel.with_user(operator)._open_livechat_mail_channel(anonymous_name='whatever', previous_operator_id=operator.partner_id.id, user_id=operator.id) - self.assertEqual(channel_info['operator_pid'], (operator.partner_id.id, "Michel")) + self.assertEqual(channel_info['operator_pid'], (operator.partner_id.id, "Michel Operator")) visitor_info = channel_info['livechat_visitor'] self.assertEqual(visitor_info['id'], operator.partner_id.id) self.assertEqual(visitor_info['name'], "Michel") @@ -100,3 +119,22 @@ class TestGetMailChannel(TransactionCase): self.env['mail.channel'].browse(channel_info['id']).message_post(body='cc') self.assertTrue(operator_channel_partner.is_pinned, "channel should be pinned for operator after visitor sent a message") self.assertIn(channel_info['id'], operator_channel_partner.partner_id._get_channels_as_member().ids, "channel should be fetched by operator on new page") + + def test_operator_livechat_username(self): + """Ensures the operator livechat_username is returned by `_channel_fetch_message`, which is + the method called by the public route displaying chat history.""" + public_user = self.env.ref('base.public_user') + operator = self.operators[0] + operator.write({ + 'email': 'michel@example.com', + 'livechat_username': 'Michel at your service', + }) + channel_info = self.livechat_channel.with_user(public_user)._open_livechat_mail_channel(anonymous_name='whatever') + channel = self.env['mail.channel'].browse(channel_info['id']) + channel.with_user(operator).message_post(body='Hello', message_type='comment', subtype_xmlid='mail.mt_comment') + message_formats = channel.with_user(public_user)._channel_fetch_message() + self.assertEqual(len(message_formats), 1) + self.assertEqual(message_formats[0]['author_id'][0], operator.partner_id.id) + self.assertEqual(message_formats[0]['author_id'][1], operator.livechat_username) + self.assertEqual(message_formats[0]['author_id'][2], operator.livechat_username) + self.assertFalse(message_formats[0].get('email_from'), "should not send email_from to livechat user") diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index cdcbeccae3d..7706f88d367 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -771,7 +771,7 @@ class Channel(models.Model): # avoid sending potentially a lot of members for big channels # exclude chat and other small channels from this optimization because they are # assumed to be smaller and it's important to know the member list for them - info['members'] = sorted(list(partner_format_by_partner[member.partner_id] for member in members_by_channel[channel] if member.partner_id), key=lambda p: p['id']) + info['members'] = sorted(list(channel._channel_info_format_member(member.partner_id, partner_format_by_partner[member.partner_id]) for member in members_by_channel[channel] if member.partner_id), key=lambda p: p['id']) info['seen_partners_info'] = sorted([{ 'id': cp.id, 'partner_id': cp.partner_id.id, @@ -789,6 +789,11 @@ class Channel(models.Model): channel_infos.append(info) return channel_infos + def _channel_info_format_member(self, partner, partner_info): + """Returns member information in the context of self channel.""" + self.ensure_one() + return partner_info + def _channel_fetch_message(self, last_id=False, limit=20): """ Return message values of the current channel. :param last_id : last message id to start the research @@ -1002,16 +1007,22 @@ class Channel(models.Model): """ notifications = [] for channel in self: - data = { + data = dict({ 'channel_id': channel.id, 'is_typing': is_typing, - 'partner_id': self.env.user.partner_id.id, - 'partner_name': self.env.user.partner_id.name, - } + }, **channel._notify_typing_partner_data()) notifications.append([channel, 'mail.channel.partner/typing_status', data]) # notify backend users notifications.append([channel.uuid, 'mail.channel.partner/typing_status', data]) # notify frontend users self.env['bus.bus']._sendmany(notifications) + def _notify_typing_partner_data(self): + """Returns typing partner data for self channel.""" + self.ensure_one() + return { + 'partner_id': self.env.user.partner_id.id, + 'partner_name': self.env.user.partner_id.name, + } + @api.model def channel_search_to_join(self, name=None, domain=None): """ Return the channel info of the channel the current partner can join diff --git a/addons/mail/static/src/components/message/message.xml b/addons/mail/static/src/components/message/message.xml index 2610dc6aa5f..a7725b26029 100644 --- a/addons/mail/static/src/components/message/message.xml +++ b/addons/mail/static/src/components/message/message.xml @@ -59,7 +59,12 @@
- + + + + + +
diff --git a/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js index 32e9cef5253..78ccd282c71 100644 --- a/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js +++ b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js @@ -21,9 +21,12 @@ export class MessageSeenIndicator extends Component { return this.env._t("Seen by Everyone"); } if (this.messageSeenIndicator.hasSomeoneSeen) { - const partnersThatHaveSeen = this.messageSeenIndicator.partnersThatHaveSeen.map( - partner => partner.name - ); + const partnersThatHaveSeen = this.messageSeenIndicator.partnersThatHaveSeen.map(partner => { + if (this.message.originThread) { + return this.message.originThread.getMemberName(partner); + } + return partner.nameOrDisplayName; + }); if (partnersThatHaveSeen.length === 1) { return _.str.sprintf( this.env._t("Seen by %s"), @@ -47,9 +50,12 @@ export class MessageSeenIndicator extends Component { return this.env._t("Received by Everyone"); } if (this.messageSeenIndicator.hasSomeoneFetched) { - const partnersThatHaveFetched = this.messageSeenIndicator.partnersThatHaveFetched.map( - partner => partner.name - ); + const partnersThatHaveFetched = this.messageSeenIndicator.partnersThatHaveFetched.map(partner => { + if (this.message.originThread) { + return this.message.originThread.getMemberName(partner); + } + return partner.nameOrDisplayName; + }); if (partnersThatHaveFetched.length === 1) { return _.str.sprintf( this.env._t("Received by %s"), diff --git a/addons/mail/static/src/models/message_reaction_group/message_reaction_group.js b/addons/mail/static/src/models/message_reaction_group/message_reaction_group.js index 014c9444149..382ea92abfa 100644 --- a/addons/mail/static/src/models/message_reaction_group/message_reaction_group.js +++ b/addons/mail/static/src/models/message_reaction_group/message_reaction_group.js @@ -55,7 +55,12 @@ registerModel({ 1: secondUser, 2: thirdUser, } = [ - ...this.partners.map(partner => partner.nameOrDisplayName), + ...this.partners.map(partner => { + if (this.message.originThread) { + return this.message.originThread.getMemberName(partner); + } + return partner.nameOrDisplayName; + }), ...this.guests.map(guest => guest.name), ]; switch (length) { diff --git a/addons/mail/static/src/models/partner/partner.js b/addons/mail/static/src/models/partner/partner.js index 3f506898fca..d370bd5fe9f 100644 --- a/addons/mail/static/src/models/partner/partner.js +++ b/addons/mail/static/src/models/partner/partner.js @@ -410,6 +410,15 @@ registerModel({ compute: '_computeAvatarUrl', }), country: many2one('Country'), + /** + * Deprecated. + * States the `display_name` of this partner, as returned by the server. + * The value of this field is unreliable (notably its value depends on + * context on which it was received) therefore it should only be used as + * a default if the actual `name` is missing (@see `nameOrDisplayName`). + * And if a specific name format is required, it should be computed from + * relevant fields instead. + */ display_name: attr({ compute: '_computeDisplayName', default: "", diff --git a/addons/mail/static/src/models/thread/thread.js b/addons/mail/static/src/models/thread/thread.js index 0d4b52415eb..8d42b27f3ea 100644 --- a/addons/mail/static/src/models/thread/thread.js +++ b/addons/mail/static/src/models/thread/thread.js @@ -792,6 +792,15 @@ registerModel({ this.endCall(); } }, + /** + * Returns the name of the given partner in the context of this thread. + * + * @param {mail.partner} partner + * @returns {string} + */ + getMemberName(partner) { + return partner.nameOrDisplayName; + }, /** * Returns the text that identifies this thread in a mention. * @@ -1679,20 +1688,20 @@ registerModel({ if (this.orderedOtherTypingMembers.length === 1) { return _.str.sprintf( this.env._t("%s is typing..."), - this.orderedOtherTypingMembers[0].nameOrDisplayName + this.getMemberName(this.orderedOtherTypingMembers[0]) ); } if (this.orderedOtherTypingMembers.length === 2) { return _.str.sprintf( this.env._t("%s and %s are typing..."), - this.orderedOtherTypingMembers[0].nameOrDisplayName, - this.orderedOtherTypingMembers[1].nameOrDisplayName + this.getMemberName(this.orderedOtherTypingMembers[0]), + this.getMemberName(this.orderedOtherTypingMembers[1]) ); } return _.str.sprintf( this.env._t("%s, %s and more are typing..."), - this.orderedOtherTypingMembers[0].nameOrDisplayName, - this.orderedOtherTypingMembers[1].nameOrDisplayName + this.getMemberName(this.orderedOtherTypingMembers[0]), + this.getMemberName(this.orderedOtherTypingMembers[1]) ); }, /** diff --git a/addons/test_discuss_full/tests/test_performance.py b/addons/test_discuss_full/tests/test_performance.py index 32b540b21c0..7a3fb437f69 100644 --- a/addons/test_discuss_full/tests/test_performance.py +++ b/addons/test_discuss_full/tests/test_performance.py @@ -620,25 +620,19 @@ class TestDiscussFullPerformance(TransactionCase): 'members': [ { 'active': True, - 'display_name': 'Ernest Employee', - 'email': 'e.e@example.com', + 'email': False, 'id': self.users[0].partner_id.id, - 'im_status': 'leave_offline', - 'is_internal_user': True, + 'im_status': False, + 'livechat_username': False, 'name': 'Ernest Employee', - 'out_of_office_date_end': self.leaves.filtered(lambda l: l.employee_id.user_id == self.users[0]).date_to.strftime(DEFAULT_SERVER_DATE_FORMAT), - 'user_id': self.users[0].id, }, { 'active': True, - 'display_name': 'test1', - 'email': 'test1@example.com', + 'email': False, 'id': self.users[1].partner_id.id, - 'im_status': 'leave_offline', - 'is_internal_user': True, + 'im_status': False, + 'livechat_username': False, 'name': 'test1', - 'out_of_office_date_end': self.leaves.filtered(lambda l: l.employee_id.user_id == self.users[1]).date_to.strftime(DEFAULT_SERVER_DATE_FORMAT), - 'user_id': self.users[1].id, }, ], 'message_needaction_counter': 0, @@ -689,25 +683,19 @@ class TestDiscussFullPerformance(TransactionCase): 'members': [ { 'active': False, - 'display_name': 'Public user', 'email': False, 'id': self.env.ref('base.public_partner').id, - 'im_status': 'im_partner', - 'is_internal_user': False, + 'im_status': False, + 'livechat_username': False, 'name': 'Public user', - 'out_of_office_date_end': False, - 'user_id': False, }, { 'active': True, - 'display_name': 'Ernest Employee', - 'email': 'e.e@example.com', + 'email': False, 'id': self.users[0].partner_id.id, - 'im_status': 'leave_offline', - 'is_internal_user': True, + 'im_status': False, + 'livechat_username': False, 'name': 'Ernest Employee', - 'out_of_office_date_end': self.leaves.filtered(lambda l: l.employee_id.user_id == self.users[0]).date_to.strftime(DEFAULT_SERVER_DATE_FORMAT), - 'user_id': self.users[0].id, }, ], 'message_needaction_counter': 0, diff --git a/addons/website_livechat/models/website.py b/addons/website_livechat/models/website.py index 6bfe620a094..93e669c481a 100644 --- a/addons/website_livechat/models/website.py +++ b/addons/website_livechat/models/website.py @@ -49,7 +49,8 @@ class Website(models.Model): "id": chat_request_channel.id, "operator_pid": [ chat_request_channel.livechat_operator_id.id, - chat_request_channel.livechat_operator_id.display_name + chat_request_channel.livechat_operator_id.user_livechat_username or chat_request_channel.livechat_operator_id.display_name, + chat_request_channel.livechat_operator_id.user_livechat_username, ], "name": chat_request_channel.name, "uuid": chat_request_channel.uuid,