[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:
@@ -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):
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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,
|
||||
})],
|
||||
})],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user