[IMP] mail: im_status for guests

task-2883466

closes odoo/odoo#97076

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Didier (did)
2022-08-08 21:02:21 +02:00
parent 98f2115967
commit 633f58f8a4
12 changed files with 80 additions and 13 deletions
+3 -1
View File
@@ -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):
+7
View File
@@ -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
@@ -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({
+17 -1
View File
@@ -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."""
@@ -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();
},
@@ -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();
},
},
+11
View File
@@ -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(),
@@ -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();
},
},
+17 -7
View File
@@ -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
@@ -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);
@@ -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') {
+7
View File
@@ -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,
})],
})],
},