[FIX] mail, im_livechat: allow to reopen closed chat in discuss

task-2346862

closes odoo/odoo#60859

X-original-commit: 063aa1deccdd6b53d1ab7de68921c95ecf60581c
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Xavier Dubuc
2020-10-27 17:14:00 +00:00
committed by Sébastien Theys
parent 6f8d9ab39b
commit 454ecb46c9
7 changed files with 104 additions and 54 deletions
@@ -26,7 +26,7 @@ registerInstancePatchModel('mail.messaging_initializer', 'im_livechat/static/src
// flux specific: channels received at init have to be
// considered pinned. task-2284357
if (!channel.isPinned) {
channel.update({ isPendingPinned: true });
channel.pin();
}
}
},
+10 -4
View File
@@ -264,8 +264,15 @@ class Channel(models.Model):
return values
def _subscribe_users(self):
to_create = []
for mail_channel in self:
mail_channel.write({'channel_partner_ids': [(4, pid) for pid in mail_channel.mapped('group_ids').mapped('users').mapped('partner_id').ids]})
partners_to_add = mail_channel.group_ids.users.partner_id - mail_channel.channel_partner_ids
to_create += [{
'channel_id': mail_channel.id,
'partner_id': partner.id,
} for partner in partners_to_add]
self.env['mail.channel.partner'].create(to_create)
def action_follow(self):
self.ensure_one()
@@ -672,6 +679,7 @@ class Channel(models.Model):
# pin up the channel for the current partner
if pin:
self.env['mail.channel.partner'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', channel.id)]).write({'is_pinned': True})
channel._broadcast(self.env.user.partner_id.ids)
else:
# create a new one
channel = self.create({
@@ -681,7 +689,6 @@ class Channel(models.Model):
'email_send': False,
'name': ', '.join(self.env['res.partner'].sudo().browse(partners_to).mapped('name')),
})
# broadcast the channel header to the other partner (not me)
channel._broadcast(partners_to)
return channel.channel_info()[0]
@@ -735,8 +742,7 @@ class Channel(models.Model):
self.ensure_one()
channel_partners = self.env['mail.channel.partner'].search(
[('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', self.id)])
if not pinned:
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', self.env.user.partner_id.id), self.channel_info('unsubscribe')[0])
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', self.env.user.partner_id.id), self.channel_info('unsubscribe' if not pinned else False)[0])
if channel_partners:
channel_partners.write({'is_pinned': pinned})
@@ -93,7 +93,7 @@ QUnit.test('sidebar: pinned channel 3: open pinned channel and unpin it', async
assert.deepEqual(args.args[0], [20],
"The right id is sent to the server to remove"
);
assert.strictEqual(args.args[1], 'leave',
assert.strictEqual(args.kwargs.command, 'leave',
"The right command is sent to the server"
);
}
@@ -169,7 +169,7 @@ function factory(dependencies) {
// flux specific: channels received at init have to be
// considered pinned. task-2284357
if (!channel.isPinned) {
channel.update({ isPendingPinned: true });
channel.pin();
}
}
}
@@ -205,7 +205,7 @@ function factory(dependencies) {
))[0];
}
if (!channel.isPinned) {
channel.update({ isPendingPinned: true });
channel.pin();
}
const message = this.env.models['mail.message'].insert(convertedData);
+87 -45
View File
@@ -341,7 +341,6 @@ function factory(dependencies) {
return channels;
}
/**
* Performs the `channel_seen` RPC on `mail.channel`.
*
@@ -361,6 +360,25 @@ function factory(dependencies) {
}, { shadow: true });
}
/**
* Performs the `channel_pin` RPC on `mail.channel`.
*
* @static
* @param {Object} param0
* @param {boolean} [param0.pinned=false]
* @param {string} param0.uuid
*/
static async performRpcChannelPin({ pinned = false, uuid }) {
return this.env.services.rpc({
model: 'mail.channel',
method: 'channel_pin',
kwargs: {
uuid,
pinned,
},
}, { shadow: true });
}
/**
* Performs the `channel_create` RPC on `mail.channel`.
*
@@ -452,6 +470,25 @@ function factory(dependencies) {
);
}
/**
* Performs the `execute_command` RPC on `mail.channel`.
*
* @static
* @param {Object} param0
* @param {string} param0.command the command to execute
* @param {integer[]} param0.ids list of id of channels
*/
static async performRpcExecuteCommand({ command, ids }) {
return this.env.services.rpc({
model: 'mail.channel',
method: 'execute_command',
args: [ids],
kwargs: {
command,
}
});
}
/**
* Performs RPC on the route `/mail/get_suggested_recipients`.
*
@@ -633,23 +670,17 @@ function factory(dependencies) {
*
* Only makes sense if isPendingPinned is set to the desired value.
*/
notifyPinStateToServer() {
// method is called from _updateAfter so it cannot be async
async notifyPinStateToServer() {
if (this.isPendingPinned) {
this.env.services.rpc({
model: 'mail.channel',
method: 'channel_pin',
kwargs: {
uuid: this.uuid,
pinned: true,
},
}, { shadow: true });
await this.env.models['mail.thread'].performRpcChannelPin({
pinned: true,
uuid: this.uuid,
});
} else {
this.env.services.rpc({
model: 'mail.channel',
method: 'execute_command',
args: [[this.id], 'leave']
}, { shadow: true });
await this.env.models['mail.thread'].performRpcExecuteCommand({
command: 'leave',
ids: [this.id],
});
}
}
@@ -700,6 +731,14 @@ function factory(dependencies) {
});
}
/**
* Pin this thread and notify server of the change.
*/
async pin() {
this.update({ isPendingPinned: true });
await this.notifyPinStateToServer();
}
/**
* Open a dialog to add channels as followers.
*/
@@ -867,6 +906,14 @@ function factory(dependencies) {
await this.async(() => currentPartnerFollower.remove());
}
/**
* Unpin this thread and notify server of the change.
*/
async unpin() {
this.update({ isPendingPinned: false });
await this.notifyPinStateToServer();
}
/**
* Called when current partner has explicitly stopped inserting some
* input in composer. Useful to notify current partner has currently
@@ -921,7 +968,7 @@ function factory(dependencies) {
*/
unsubscribe() {
this.env.messaging.chatWindowManager.closeThread(this);
this.update({ isPendingPinned: false });
this.unpin();
}
//----------------------------------------------------------------------
@@ -1296,6 +1343,19 @@ function factory(dependencies) {
this._currentPartnerLastNotifiedIsTyping = isTyping;
}
/**
* Handles change of pinned state coming from the server. Useful to
* clear pending state once server acknowledged the change.
*
* @private
* @see isPendingPinned
*/
_onIsServerPinnedChanged() {
if (this.isServerPinned === this.isPendingPinned) {
this.update({ isPendingPinned: clear() });
}
}
/**
* Handles change of fold state coming from the server. Useful to
* synchronize corresponding chat window.
@@ -1350,34 +1410,6 @@ function factory(dependencies) {
});
}
/**
* @override
*/
_updateAfter(previous) {
if (this.model !== 'mail.channel') {
// pin state only makes sense on channels
return;
}
if (
this.isPendingPinned !== undefined &&
previous.isPendingPinned !== this.isPendingPinned
) {
this.notifyPinStateToServer();
}
if (this.isServerPinned === this.isPendingPinned) {
this.update({ isPendingPinned: clear() });
}
}
/**
* @override
*/
_updateBefore() {
return {
isPendingPinned: this.isPendingPinned,
};
}
//----------------------------------------------------------------------
// Handlers
//----------------------------------------------------------------------
@@ -1701,6 +1733,16 @@ function factory(dependencies) {
compute: '_computeNeedactionMessages',
dependencies: ['messages'],
}),
/**
* Not a real field, used to trigger `_onIsServerPinnedChanged` when one of
* the dependencies changes.
*/
onIsServerPinnedChanged: attr({
compute: '_onIsServerPinnedChanged',
dependencies: [
'isServerPinned',
],
}),
/**
* Not a real field, used to trigger `_onServerFoldStateChanged` when one of
* the dependencies changes.
+3 -1
View File
@@ -113,7 +113,9 @@ function factory(dependencies) {
thread.model === 'mail.channel' &&
thread.public === 'private'
);
if (!chat) {
if (!chat ||!chat.isPinned) {
// if chat is not pinned then it has to be pinned client-side
// and server-side, which is a side effect of following rpc
chat = await this.async(() =>
this.env.models['mail.thread'].performRpcCreateChat({
partnerIds: [this.partner.id],