[FIX] mail: do not show new messages separator for own messages
Also fix compute of local counter in some specific situations. task-2341740 closes odoo/odoo#58866 X-original-commit: 0df66708defd0fcb288979b1431d8180831e43d3 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
committed by
Alexandre Kühn
parent
52dfe6a4e1
commit
607ac6e912
@@ -385,6 +385,13 @@ class Channel(models.Model):
|
||||
})
|
||||
return message
|
||||
|
||||
def _message_post_after_hook(self, message, msg_vals):
|
||||
"""
|
||||
Automatically set the message posted by the current user as seen for himself.
|
||||
"""
|
||||
self._set_last_seen_message(message)
|
||||
return super()._message_post_after_hook(message=message, msg_vals=msg_vals)
|
||||
|
||||
def _alias_get_error_message(self, message, message_dict, alias):
|
||||
if alias.alias_contact == 'followers' and self.ids:
|
||||
author = self.env['res.partner'].browse(message_dict.get('author_id', False))
|
||||
@@ -744,21 +751,7 @@ class Channel(models.Model):
|
||||
if not last_message:
|
||||
return
|
||||
|
||||
channel_partner_domain = expression.AND([
|
||||
[('channel_id', 'in', self.ids)],
|
||||
[('partner_id', '=', self.env.user.partner_id.id)],
|
||||
expression.OR([
|
||||
[('seen_message_id', '=', False)],
|
||||
[('seen_message_id', '<', last_message.id)]
|
||||
])
|
||||
])
|
||||
channel_partner = self.env['mail.channel.partner'].search(channel_partner_domain, limit=1)
|
||||
if not channel_partner:
|
||||
return
|
||||
channel_partner.write({
|
||||
'fetched_message_id': last_message.id,
|
||||
'seen_message_id': last_message.id,
|
||||
})
|
||||
self._set_last_seen_message(last_message)
|
||||
|
||||
data = {
|
||||
'info': 'channel_seen',
|
||||
@@ -772,6 +765,25 @@ class Channel(models.Model):
|
||||
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', self.env.user.partner_id.id), data)
|
||||
return last_message.id
|
||||
|
||||
def _set_last_seen_message(self, last_message):
|
||||
"""
|
||||
Set last seen message of `self` channels for the current user.
|
||||
:param last_message: the message to set as last seen message
|
||||
"""
|
||||
channel_partner_domain = expression.AND([
|
||||
[('channel_id', 'in', self.ids)],
|
||||
[('partner_id', '=', self.env.user.partner_id.id)],
|
||||
expression.OR([
|
||||
[('seen_message_id', '=', False)],
|
||||
[('seen_message_id', '<', last_message.id)]
|
||||
])
|
||||
])
|
||||
channel_partner = self.env['mail.channel.partner'].search(channel_partner_domain)
|
||||
channel_partner.write({
|
||||
'fetched_message_id': last_message.id,
|
||||
'seen_message_id': last_message.id,
|
||||
})
|
||||
|
||||
def channel_fetched(self):
|
||||
""" Broadcast the channel_fetched notification to channel members
|
||||
:param channel_ids : list of channel id that has been fetched by current user
|
||||
|
||||
@@ -3211,20 +3211,20 @@ QUnit.test('mark channel as seen on last message visible [REQUIRE FOCUS]', async
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
`.o_DiscussSidebar_item[data-thread-local-id="${
|
||||
this.env.models['mail.thread'].find(thread =>
|
||||
thread.id === 10 &&
|
||||
thread.model === 'mail.channel'
|
||||
).localId
|
||||
this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 10,
|
||||
model: 'mail.channel',
|
||||
}).localId
|
||||
}"]`,
|
||||
"should have discuss sidebar item with the channel"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector(`
|
||||
.o_DiscussSidebar_item[data-thread-local-id="${
|
||||
this.env.models['mail.thread'].find(thread =>
|
||||
thread.id === 10 &&
|
||||
thread.model === 'mail.channel'
|
||||
).localId
|
||||
this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 10,
|
||||
model: 'mail.channel',
|
||||
}).localId
|
||||
}"]
|
||||
`),
|
||||
'o-unread',
|
||||
@@ -3234,20 +3234,20 @@ QUnit.test('mark channel as seen on last message visible [REQUIRE FOCUS]', async
|
||||
await afterNextRender(() =>
|
||||
document.querySelector(`
|
||||
.o_DiscussSidebar_item[data-thread-local-id="${
|
||||
this.env.models['mail.thread'].find(thread =>
|
||||
thread.id === 10 &&
|
||||
thread.model === 'mail.channel'
|
||||
).localId
|
||||
this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 10,
|
||||
model: 'mail.channel',
|
||||
}).localId
|
||||
}"]
|
||||
`).click()
|
||||
);
|
||||
assert.doesNotHaveClass(
|
||||
document.querySelector(`
|
||||
.o_DiscussSidebar_item[data-thread-local-id="${
|
||||
this.env.models['mail.thread'].find(thread =>
|
||||
thread.id === 10 &&
|
||||
thread.model === 'mail.channel'
|
||||
).localId
|
||||
this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 10,
|
||||
model: 'mail.channel',
|
||||
}).localId
|
||||
}"]
|
||||
`),
|
||||
'o-unread',
|
||||
|
||||
+1
-4
@@ -411,10 +411,7 @@ function factory(dependencies) {
|
||||
} else if (type === 'author') {
|
||||
return this._handleNotificationPartnerAuthor(data);
|
||||
} else if (info === 'channel_seen') {
|
||||
return this._handleNotificationChannelSeen(data.channel_id, {
|
||||
last_message_id: data.last_message_id,
|
||||
partner_id: this.env.messaging.currentPartner.id,
|
||||
});
|
||||
return this._handleNotificationChannelSeen(data.channel_id, data);
|
||||
} else if (type === 'deletion') {
|
||||
return this._handleNotificationPartnerDeletion(data);
|
||||
} else if (type === 'message_notification_update') {
|
||||
|
||||
@@ -1108,6 +1108,11 @@ function factory(dependencies) {
|
||||
if (!this.lastSeenByCurrentPartnerMessageId) {
|
||||
return this.serverMessageUnreadCounter;
|
||||
}
|
||||
// if server knows more messages than the client knows then we just
|
||||
// need to trust him
|
||||
if (this.serverLastMessageId > this.lastSeenByCurrentPartnerMessageId) {
|
||||
return this.serverMessageUnreadCounter;
|
||||
}
|
||||
const firstMessage = this.orderedMessages[0];
|
||||
// if the lastSeenByCurrentPartnerMessageId is not known (not fetched), then we
|
||||
// need to rely on server value to determine the amount of unread
|
||||
@@ -1115,15 +1120,15 @@ function factory(dependencies) {
|
||||
// serverMessageUnreadCounter
|
||||
if (this.lastSeenByCurrentPartnerMessageId < firstMessage.id) {
|
||||
const fetchedNotSeenMessages = this.orderedMessages.filter(message =>
|
||||
message.id > this.serverLastMessageId
|
||||
message.id > this.serverLastMessageId && message.author !== this.env.messaging.currentPartner
|
||||
);
|
||||
return this.serverMessageUnreadCounter + fetchedNotSeenMessages.length;
|
||||
}
|
||||
// lastSeenByCurrentPartnerMessageId is a known message,
|
||||
// then we can forget serverMessageUnreadCounter
|
||||
const maxId = Math.max(this.serverLastMessageId, this.lastSeenByCurrentPartnerMessageId);
|
||||
const maxId = this.lastSeenByCurrentPartnerMessageId;
|
||||
return this.orderedMessages.reduce(
|
||||
(acc, message) => acc + (message.id > maxId ? 1 : 0),
|
||||
(acc, message) => acc + ((message.id > maxId && message.author !== this.env.messaging.currentPartner) ? 1 : 0),
|
||||
0
|
||||
);
|
||||
}
|
||||
@@ -1544,6 +1549,7 @@ function factory(dependencies) {
|
||||
dependencies: [
|
||||
'lastMessage',
|
||||
'lastSeenByCurrentPartnerMessageId',
|
||||
'messagingCurrentPartner',
|
||||
'orderedMessages',
|
||||
'serverLastMessageId',
|
||||
'serverMessageUnreadCounter',
|
||||
|
||||
@@ -795,24 +795,21 @@ MockServer.include({
|
||||
if (!channel_id) {
|
||||
throw new Error('Should only be one channel in channel_seen mock params');
|
||||
}
|
||||
const channel = this._getRecords('mail.channel', [['id', '=', channel_id]])[0];
|
||||
const messagesBeforeGivenLastMessage = this._getRecords('mail.message', [
|
||||
['channel_ids', 'in', [channel_id]],
|
||||
['id', '<=', last_message_id]
|
||||
['channel_ids', 'in', [channel.id]],
|
||||
['id', '<=', last_message_id],
|
||||
]);
|
||||
if (!messagesBeforeGivenLastMessage || messagesBeforeGivenLastMessage.length === 0) {
|
||||
return;
|
||||
}
|
||||
const channel = this._getRecords('mail.channel', [['id', '=', channel_id]])[0];
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
if (channel.seen_message_id && channel.seen_message_id >= last_message_id) {
|
||||
return;
|
||||
}
|
||||
this._mockWrite('mail.channel', [[channel.id], {
|
||||
fetched_message_id: last_message_id,
|
||||
seen_message_id: last_message_id,
|
||||
}]);
|
||||
this._mockMailChannel_SetLastSeenMessage([channel.id], last_message_id);
|
||||
|
||||
// Send notification
|
||||
const payload = {
|
||||
@@ -960,6 +957,9 @@ MockServer.include({
|
||||
}),
|
||||
context,
|
||||
);
|
||||
if (kwargs.author_id === this.currentPartnerId) {
|
||||
this._mockMailChannel_SetLastSeenMessage([channel.id], messageId);
|
||||
}
|
||||
return messageId;
|
||||
},
|
||||
/**
|
||||
@@ -1018,6 +1018,19 @@ MockServer.include({
|
||||
}
|
||||
return partnerInfos;
|
||||
},
|
||||
/**
|
||||
* Simulates the `_set_last_seen_message` method of `mail.channel`.
|
||||
*
|
||||
* @private
|
||||
* @param {integer[]} ids
|
||||
* @param {integer} message_id
|
||||
*/
|
||||
_mockMailChannel_SetLastSeenMessage(ids, message_id) {
|
||||
this._mockWrite('mail.channel', [ids, {
|
||||
fetched_message_id: message_id,
|
||||
seen_message_id: message_id,
|
||||
}]);
|
||||
},
|
||||
/**
|
||||
* Simulates `mark_all_as_read` on `mail.message`.
|
||||
*
|
||||
@@ -1210,20 +1223,13 @@ MockServer.include({
|
||||
this._widget.call('bus_service', 'trigger', 'notification', [notification]);
|
||||
} else if (decision === 'accept') {
|
||||
// simulate notification back (new accepted message in channel)
|
||||
const messages = _.filter(model.records, function (rec) {
|
||||
return _.contains(messageIDs, rec.id);
|
||||
});
|
||||
|
||||
const notifications = [];
|
||||
_.each(messages, function (message) {
|
||||
const dbName = undefined; // useless for tests
|
||||
const messageData = message;
|
||||
message.moderation_status = 'accepted';
|
||||
const metaData = [dbName, 'mail.channel', message.res_id];
|
||||
const notification = [metaData, messageData];
|
||||
notifications.push(notification);
|
||||
});
|
||||
this._widget.call('bus_service', 'trigger', 'notification', notifications);
|
||||
const messages = this._getRecords('mail.message', [['id', 'in', messageIDs]]);
|
||||
for (const message of messages) {
|
||||
this._mockWrite('mail.message', [[message.id], {
|
||||
moderation_status: 'accepted',
|
||||
}]);
|
||||
this._mockMailThread_NotifyThread(model, message.channel_ids, message.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -1513,7 +1519,7 @@ MockServer.include({
|
||||
});
|
||||
delete values.subtype_xmlid;
|
||||
const messageId = this._mockCreate('mail.message', values);
|
||||
this._mockMailThread_NotifyThread(model, ids, messageId, values);
|
||||
this._mockMailThread_NotifyThread(model, ids, messageId);
|
||||
return messageId;
|
||||
},
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user