From 633f58f8a45c6bd3e17487a50d1502bb85c6886e Mon Sep 17 00:00:00 2001 From: "Didier (did)" Date: Fri, 29 Jul 2022 11:25:02 +0000 Subject: [PATCH] [IMP] mail: im_status for guests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit task-2883466 closes odoo/odoo#97076 Signed-off-by: Sébastien Theys (seb) --- addons/bus/controllers/main.py | 4 +++- addons/mail/controllers/bus.py | 7 ++++++ addons/mail/models/mail_channel_member.py | 1 + addons/mail/models/mail_guest.py | 18 +++++++++++++- .../mail/static/src/models/channel_member.js | 4 ++-- .../static/src/models/channel_member_view.js | 3 +++ addons/mail/static/src/models/guest.js | 11 +++++++++ addons/mail/static/src/models/message_view.js | 3 +++ addons/mail/static/src/models/messaging.js | 24 +++++++++++++------ .../src/models/persona_im_status_icon_view.js | 7 +++++- .../mail/static/tests/helpers/mock_server.js | 4 +++- addons/mail/tests/test_rtc.py | 7 ++++++ 12 files changed, 80 insertions(+), 13 deletions(-) diff --git a/addons/bus/controllers/main.py b/addons/bus/controllers/main.py index 5f7c08e1433..8786e9fa441 100644 --- a/addons/bus/controllers/main.py +++ b/addons/bus/controllers/main.py @@ -36,7 +36,9 @@ class BusController(Controller): @route('/longpolling/im_status', type="json", auth="user") def im_status(self, partner_ids): - return request.env['res.partner'].with_context(active_test=False).search([('id', 'in', partner_ids)]).read(['im_status']) + return { + 'partners': request.env['res.partner'].with_context(active_test=False).search([('id', 'in', partner_ids)]).read(['im_status']) + } @route('/longpolling/health', type='http', auth='none', save_session=False) def health(self): diff --git a/addons/mail/controllers/bus.py b/addons/mail/controllers/bus.py index be962261606..058bc4d39a3 100644 --- a/addons/mail/controllers/bus.py +++ b/addons/mail/controllers/bus.py @@ -70,3 +70,10 @@ class MailChatController(BusController): return [] else: return channel._channel_fetch_message(last_id, limit) + + @route('/longpolling/im_status', type="json", auth="user") + def im_status(self, partner_ids, guest_ids=None): + im_status = super().im_status(partner_ids) + if guest_ids: + im_status['guests'] = request.env['mail.guest'].sudo().with_context(active_test=False).search([('id', 'in', guest_ids)]).read(['im_status']) + return im_status diff --git a/addons/mail/models/mail_channel_member.py b/addons/mail/models/mail_channel_member.py index 5ddf80ad4f8..ebb14e563b6 100644 --- a/addons/mail/models/mail_channel_member.py +++ b/addons/mail/models/mail_channel_member.py @@ -136,6 +136,7 @@ class ChannelMember(models.Model): 'guest': [('insert-and-replace', { 'id': member.guest_id.id, 'name': member.guest_id.name, + 'im_status': member.guest_id.im_status, })], } members_formatted_data.append({ diff --git a/addons/mail/models/mail_guest.py b/addons/mail/models/mail_guest.py index 3722346e772..ae43fe3078e 100644 --- a/addons/mail/models/mail_guest.py +++ b/addons/mail/models/mail_guest.py @@ -8,7 +8,7 @@ from odoo.tools import consteq from odoo import _, api, fields, models from odoo.addons.base.models.res_partner import _tz_get from odoo.exceptions import UserError - +from odoo.addons.bus.models.bus_presence import AWAY_TIMER, DISCONNECTION_TIMER class MailGuest(models.Model): _name = 'mail.guest' @@ -28,6 +28,22 @@ class MailGuest(models.Model): lang = fields.Selection(string="Language", selection=_lang_get) timezone = fields.Selection(string="Timezone", selection=_tz_get) channel_ids = fields.Many2many(string="Channels", comodel_name='mail.channel', relation='mail_channel_member', column1='guest_id', column2='channel_id', copy=False) + im_status = fields.Char('IM Status', compute='_compute_im_status') + + def _compute_im_status(self): + self.env.cr.execute(""" + SELECT + guest_id as id, + CASE WHEN age(now() AT TIME ZONE 'UTC', last_poll) > interval %s THEN 'offline' + WHEN age(now() AT TIME ZONE 'UTC', last_presence) > interval %s THEN 'away' + ELSE 'online' + END as status + FROM bus_presence + WHERE guest_id IN %s + """, ("%s seconds" % DISCONNECTION_TIMER, "%s seconds" % AWAY_TIMER, tuple(self.ids))) + res = dict(((status['id'], status['status']) for status in self.env.cr.dictfetchall())) + for guest in self: + guest.im_status = res.get(guest.id, 'offline') def _get_guest_from_context(self): """Returns the current guest record from the context, if applicable.""" diff --git a/addons/mail/static/src/models/channel_member.js b/addons/mail/static/src/models/channel_member.js index e76c9497ece..434e329c33d 100644 --- a/addons/mail/static/src/models/channel_member.js +++ b/addons/mail/static/src/models/channel_member.js @@ -30,7 +30,7 @@ registerModel({ return !this.persona.partner.isOnline ? replace(this.channel) : clear(); } if (this.persona.guest) { - return replace(this.channel); + return !this.persona.guest.isOnline ? replace(this.channel) : clear(); } return clear(); }, @@ -43,7 +43,7 @@ registerModel({ return this.persona.partner.isOnline ? replace(this.channel) : clear(); } if (this.persona.guest) { - return clear(); + return this.persona.guest.isOnline ? replace(this.channel) : clear(); } return clear(); }, diff --git a/addons/mail/static/src/models/channel_member_view.js b/addons/mail/static/src/models/channel_member_view.js index 0232229cefc..c763ed98c90 100644 --- a/addons/mail/static/src/models/channel_member_view.js +++ b/addons/mail/static/src/models/channel_member_view.js @@ -39,6 +39,9 @@ registerModel({ * @returns {FieldCommand} */ _computePersonaImStatusIconView() { + if (this.channelMember.persona.guest && this.channelMember.persona.guest.im_status) { + return insertAndReplace(); + } return this.channelMember.persona.partner && this.channelMember.persona.partner.isImStatusSet ? insertAndReplace() : clear(); }, }, diff --git a/addons/mail/static/src/models/guest.js b/addons/mail/static/src/models/guest.js index 442f43a80b1..08c0c8cb76c 100644 --- a/addons/mail/static/src/models/guest.js +++ b/addons/mail/static/src/models/guest.js @@ -31,6 +31,13 @@ registerModel({ _computeAvatarUrl() { return `/web/image/mail.guest/${this.id}/avatar_128?unique=${this.name}`; }, + /** + * @private + * @returns {boolean} + */ + _computeIsOnline() { + return ['online', 'away'].includes(this.im_status); + }, }, fields: { authoredMessages: many('Message', { @@ -43,6 +50,10 @@ registerModel({ required: true, readonly: true, }), + im_status: attr(), + isOnline: attr({ + compute: '_computeIsOnline', + }), name: attr(), persona: one('Persona', { default: insertAndReplace(), diff --git a/addons/mail/static/src/models/message_view.js b/addons/mail/static/src/models/message_view.js index 55cd29f7442..28dcbf6d0c1 100644 --- a/addons/mail/static/src/models/message_view.js +++ b/addons/mail/static/src/models/message_view.js @@ -415,6 +415,9 @@ registerModel({ * @returns {FieldCommand} */ _computePersonaImStatusIconView() { + if (this.message.guestAuthor && this.message.guestAuthor.im_status) { + return insertAndReplace(); + } return this.message.author && this.message.author.isImStatusSet ? insertAndReplace() : clear(); }, }, diff --git a/addons/mail/static/src/models/messaging.js b/addons/mail/static/src/models/messaging.js index f1f6b222791..21d3348ee10 100644 --- a/addons/mail/static/src/models/messaging.js +++ b/addons/mail/static/src/models/messaging.js @@ -215,13 +215,23 @@ registerModel({ if (partnerIds.length === 0) { return; } - const dataList = await this.messaging.rpc({ - route: '/longpolling/im_status', - params: { - partner_ids: partnerIds, - }, - }, { shadow: true }); - this.models['Partner'].insert(dataList); + const guestIds = []; + for (const guest of this.models['Guest'].all()) { + guestIds.push(guest.id); + } + if (partnerIds.length !== 0 || guestIds.length !== 0) { + const dataList = await this.messaging.rpc({ + route: '/longpolling/im_status', + params: { + partner_ids: partnerIds, + guest_ids: guestIds, + }, + }, { shadow: true }); + this.models['Partner'].insert(dataList.partners); + if (dataList.guests) { + this.models['Guest'].insert(dataList.guests); + } + } }, /** * @private diff --git a/addons/mail/static/src/models/persona_im_status_icon_view.js b/addons/mail/static/src/models/persona_im_status_icon_view.js index b4a6fe169d5..08bbaf32652 100644 --- a/addons/mail/static/src/models/persona_im_status_icon_view.js +++ b/addons/mail/static/src/models/persona_im_status_icon_view.js @@ -31,7 +31,12 @@ registerModel({ return replace(this.composerSuggestionViewOwner.suggestable.partner.persona); } if (this.messageViewOwner) { - return replace(this.messageViewOwner.message.author.persona); + if (this.messageViewOwner.message.author) { + return replace(this.messageViewOwner.message.author.persona); + } + if (this.messageViewOwner.message.guestAuthor) { + return replace(this.messageViewOwner.message.guestAuthor.persona); + } } if (this.notificationRequestViewOwner) { return replace(this.messaging.partnerRoot.persona); diff --git a/addons/mail/static/tests/helpers/mock_server.js b/addons/mail/static/tests/helpers/mock_server.js index 568df1cb6e4..d8b4a840e62 100644 --- a/addons/mail/static/tests/helpers/mock_server.js +++ b/addons/mail/static/tests/helpers/mock_server.js @@ -71,7 +71,9 @@ patch(MockServer.prototype, 'mail', { // routes if (route === '/longpolling/im_status') { const { partner_ids } = args; - return this.pyEnv['res.partner'].searchRead([['id', 'in', partner_ids]], { context: { 'active_test': false }, fields: ['im_status'] }); + return { + 'partners': this.pyEnv['res.partner'].searchRead([['id', 'in', partner_ids]], { context: { 'active_test': false }, fields: ['im_status'] }) + }; } if (route === '/mail/message/post') { if (args.thread_model === 'mail.channel') { diff --git a/addons/mail/tests/test_rtc.py b/addons/mail/tests/test_rtc.py index 069853cb9e0..691ee23a975 100644 --- a/addons/mail/tests/test_rtc.py +++ b/addons/mail/tests/test_rtc.py @@ -270,6 +270,7 @@ class TestChannelInternals(MailCommon): 'guest': [('insert-and-replace', { 'id': channel_member_test_guest.guest_id.id, 'name': channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], }, @@ -299,6 +300,7 @@ class TestChannelInternals(MailCommon): 'guest': [('insert-and-replace', { 'id': channel_member_test_guest.guest_id.id, 'name': channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], }, @@ -404,6 +406,7 @@ class TestChannelInternals(MailCommon): 'guest': [('insert-and-replace', { 'id': channel_member_test_guest.guest_id.id, 'name': channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], }])], @@ -423,6 +426,7 @@ class TestChannelInternals(MailCommon): "guest": [("insert-and-replace", { "id": channel_member_test_guest.guest_id.id, "name": channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], })], @@ -510,6 +514,7 @@ class TestChannelInternals(MailCommon): 'guest': [('insert-and-replace', { 'id': channel_member_test_guest.guest_id.id, 'name': channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], }])], @@ -584,6 +589,7 @@ class TestChannelInternals(MailCommon): 'guest': [('insert-and-replace', { 'id': channel_member_test_guest.guest_id.id, 'name': channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], }, @@ -704,6 +710,7 @@ class TestChannelInternals(MailCommon): 'guest': [('insert-and-replace', { 'id': channel_member_test_guest.guest_id.id, 'name': channel_member_test_guest.guest_id.name, + 'im_status': channel_member_test_guest.guest_id.im_status, })], })], },