From ec93077b8de2c3b0663672aa655c0d9037c3e8aa Mon Sep 17 00:00:00 2001 From: Maryam Kia Date: Tue, 18 Apr 2023 10:05:05 +0000 Subject: [PATCH] [IMP] mail: Edited label on edited message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By this commit, If a user edits the message body or changes the message attachments, the edited label in the blob, shows the last edit Info. Task-2664848 closes odoo/odoo#117896 Related: odoo/enterprise#40208 Signed-off-by: Alexandre Kühn (aku) --- addons/im_livechat/tests/test_message.py | 2 ++ addons/mail/controllers/attachment.py | 8 +++--- addons/mail/models/discuss/discuss_channel.py | 8 +++++- addons/mail/models/ir_attachment.py | 6 ++-- addons/mail/models/mail_message.py | 18 ++++++------ addons/mail/models/mail_thread.py | 1 + addons/mail/models/res_partner.py | 1 + addons/mail/static/src/core/message_model.js | 28 +++++++++++++++---- .../mail/static/src/core/messaging_service.js | 8 +++++- addons/mail/static/src/core_ui/message.scss | 4 +++ addons/mail/static/src/core_ui/message.xml | 6 ++-- 11 files changed, 66 insertions(+), 24 deletions(-) diff --git a/addons/im_livechat/tests/test_message.py b/addons/im_livechat/tests/test_message.py index 3f2be35f710..b50a22d3ae9 100644 --- a/addons/im_livechat/tests/test_message.py +++ b/addons/im_livechat/tests/test_message.py @@ -53,6 +53,8 @@ class TestImLivechatMessage(TransactionCase): }, 'body': message.body, 'date': message.date, + 'write_date': message.write_date, + 'create_date': message.create_date, 'guestAuthor': [('clear',)], 'history_partner_ids': [], 'id': message.id, diff --git a/addons/mail/controllers/attachment.py b/addons/mail/controllers/attachment.py index c49eba10bd0..8fc5f7cd6e5 100644 --- a/addons/mail/controllers/attachment.py +++ b/addons/mail/controllers/attachment.py @@ -49,19 +49,19 @@ class AttachmentController(http.Controller): @http.route("/mail/attachment/delete", methods=["POST"], type="json", auth="public") def mail_attachment_delete(self, attachment_id, access_token=None): attachment_sudo = request.env["ir.attachment"].browse(int(attachment_id)).sudo().exists() + guest = request.env["mail.guest"]._get_guest_from_request(request) + message_sudo = guest.env["mail.message"].sudo().search([("attachment_ids", "in", attachment_sudo.ids)], limit=1) if not attachment_sudo: target = request.env.user.partner_id request.env["bus.bus"]._sendone(target, "ir.attachment/delete", {"id": attachment_id}) return if not request.env.user.share: # Check through standard access rights/rules for internal users. - attachment_sudo.sudo(False)._delete_and_notify() + attachment_sudo.sudo(False)._delete_and_notify(message_sudo) return # For non-internal users 2 cases are supported: # - Either the attachment is linked to a message: verify the request is made by the author of the message (portal user or guest). # - Either a valid access token is given: also verify the message is pending (because unfortunately in portal a token is also provided to guest for viewing others' attachments). - guest = request.env["mail.guest"]._get_guest_from_request(request) - message_sudo = guest.env["mail.message"].sudo().search([("attachment_ids", "in", attachment_sudo.ids)], limit=1) if message_sudo: if not message_sudo.is_current_user_or_guest_author: raise NotFound() @@ -74,4 +74,4 @@ class AttachmentController(http.Controller): raise NotFound() if attachment_sudo.res_model != "mail.compose.message" or attachment_sudo.res_id != 0: raise NotFound() - attachment_sudo._delete_and_notify() + attachment_sudo._delete_and_notify(message_sudo) diff --git a/addons/mail/models/discuss/discuss_channel.py b/addons/mail/models/discuss/discuss_channel.py index 212385e3c09..eaf88aaede6 100644 --- a/addons/mail/models/discuss/discuss_channel.py +++ b/addons/mail/models/discuss/discuss_channel.py @@ -703,7 +703,13 @@ class Channel(models.Model): ]) if not message_to_update: return - message_to_update.write({'pinned_at': fields.datetime.now() if pinned else False}) + message_to_update.flush_recordset(['pinned_at']) + # Use SQL because by calling write method, write_date is going to be updated, but we don't want pin/unpin + # a message changes the write_date + self.env.cr.execute("UPDATE mail_message SET pinned_at=%s WHERE id=%s", + (fields.datetime.now() if pinned else None, message_to_update.id)) + message_to_update.invalidate_recordset(['pinned_at']) + self.env['bus.bus']._sendone(self, 'mail.record/insert', { 'Message': { 'id': message_id, diff --git a/addons/mail/models/ir_attachment.py b/addons/mail/models/ir_attachment.py index d76de0e0bbd..8d9b2855d97 100644 --- a/addons/mail/models/ir_attachment.py +++ b/addons/mail/models/ir_attachment.py @@ -38,9 +38,11 @@ class IrAttachment(models.Model): with contextlib.suppress(AccessError): related_record.message_main_attachment_id = self - def _delete_and_notify(self): + def _delete_and_notify(self, message=None): + if message: + message.write({}) # to make sure write_date on the message is updated self.env['bus.bus']._sendmany((attachment._bus_notification_target(), 'ir.attachment/delete', { - 'id': attachment.id, + 'id': attachment.id, 'message': {'id': message.id, 'write_date': message.write_date} if message else {} }) for attachment in self) self.unlink() diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 21d953ac509..129e6b0603e 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -796,12 +796,11 @@ class Message(models.Model): @api.model def unstar_all(self): """ Unstar messages for the current partner. """ - partner_id = self.env.user.partner_id.id + partner = self.env.user.partner_id - starred_messages = self.search([('starred_partner_ids', 'in', partner_id)]) - starred_messages.write({'starred_partner_ids': [Command.unlink(partner_id)]}) - - self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.message/toggle_star', { + starred_messages = self.search([('starred_partner_ids', 'in', partner.id)]) + partner.starred_message_ids -= starred_messages + self.env['bus.bus']._sendone(partner, 'mail.message/toggle_star', { 'message_ids': starred_messages.ids, 'starred': False, }) @@ -813,12 +812,13 @@ class Message(models.Model): # a user should always be able to star a message they can read self.check_access_rule('read') starred = not self.starred + partner = self.env.user.partner_id if starred: - self.sudo().write({'starred_partner_ids': [Command.link(self.env.user.partner_id.id)]}) + partner.starred_message_ids |= self else: - self.sudo().write({'starred_partner_ids': [Command.unlink(self.env.user.partner_id.id)]}) + partner.starred_message_ids -= self - self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.message/toggle_star', { + self.env['bus.bus']._sendone(partner, 'mail.message/toggle_star', { 'message_ids': [self.id], 'starred': starred, }) @@ -913,6 +913,8 @@ class Message(models.Model): 'messageReactionGroups': reaction_groups, 'pinned_at': message_sudo.pinned_at, 'record_name': record_name, + 'create_date': message_sudo.create_date, + 'write_date': message_sudo.write_date, }) return vals_list diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 82f9c500322..f93cc834a54 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -4062,6 +4062,7 @@ class MailThread(models.AbstractModel): 'id': message.id, 'body': message.body, 'attachment_ids': message.attachment_ids._attachment_format(), + 'write_date': message.write_date, } }) diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index bf9b9f7b1f5..9498233757e 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -23,6 +23,7 @@ class Partner(models.Model): # tracked field used for chatter logging purposes # we need this to be readable inline as tracking messages use inline HTML nodes contact_address_inline = fields.Char(compute='_compute_contact_address_inline', string='Inlined Complete Address', tracking=True) + starred_message_ids = fields.Many2many('mail.message', 'mail_message_res_partner_starred_rel') @api.depends('contact_address') def _compute_contact_address_inline(self): diff --git a/addons/mail/static/src/core/message_model.js b/addons/mail/static/src/core/message_model.js index fcffa09117d..8183f873e20 100644 --- a/addons/mail/static/src/core/message_model.js +++ b/addons/mail/static/src/core/message_model.js @@ -8,6 +8,7 @@ import { _t } from "@web/core/l10n/translation"; import { url } from "@web/core/utils/urls"; import { deserializeDateTime } from "@web/core/l10n/dates"; import { createLocalId } from "../utils/misc"; +import { omit } from "@web/core/utils/objects"; const { DateTime } = luxon; @@ -66,6 +67,10 @@ export class Message { notificationType; /** @type {string} */ pinned_at; + /** @type {string} */ + create_date; + /** @type {string} */ + write_date; /** * We exclude the milliseconds because datetime string from the server don't @@ -171,11 +176,12 @@ export class Message { return `${url("/web")}#model=${this.resModel}&id=${this.id}`; } - get isBodyEmpty() { - return ( - !this.body || - ["", "

", "


", "


"].includes(this.body.replace(/\s/g, "")) - ); + get editDate() { + return this.write_date !== this.create_date ? this.write_date : false; + } + + get hasTextContent() { + return (this.editDate && this.attachments.length) || !this.isBodyEmpty; } get isEmpty() { @@ -186,6 +192,12 @@ export class Message { !this.subtypeDescription ); } + get isBodyEmpty() { + return ( + !this.body || + ["", "

", "


", "


"].includes(this.body.replace(/\s/g, "")) + ); + } /** * Determines if the link preview is actually the main content of the @@ -231,4 +243,10 @@ export class Message { } return luxon.DateTime.fromISO(new Date(this.pinned_at).toISOString()); } + + get editDatetimeHuge() { + return deserializeDateTime(this.editDate).toLocaleString( + omit(DateTime.DATETIME_HUGE, "timeZoneName") + ); + } } diff --git a/addons/mail/static/src/core/messaging_service.js b/addons/mail/static/src/core/messaging_service.js index 6d53c7ec59c..cab53c98dfd 100644 --- a/addons/mail/static/src/core/messaging_service.js +++ b/addons/mail/static/src/core/messaging_service.js @@ -469,7 +469,13 @@ export class Messaging { break; case "ir.attachment/delete": { - const attachment = this.store.attachments[notif.payload.id]; + const { id: attachmentId, message: messageData } = notif.payload; + if (messageData) { + this.messageService.insert({ + ...messageData, + }); + } + const attachment = this.store.attachments[attachmentId]; if (!attachment) { return; } diff --git a/addons/mail/static/src/core_ui/message.scss b/addons/mail/static/src/core_ui/message.scss index 1fb8cc098f5..06b7edf02df 100644 --- a/addons/mail/static/src/core_ui/message.scss +++ b/addons/mail/static/src/core_ui/message.scss @@ -18,6 +18,10 @@ .o-mail-Message-body > p { margin-bottom: 0; + + &:last-of-type { + display: inline-block; + } } .o-mail-Message-body { diff --git a/addons/mail/static/src/core_ui/message.xml b/addons/mail/static/src/core_ui/message.xml index 7bb56cd3048..590ac0758aa 100644 --- a/addons/mail/static/src/core_ui/message.xml +++ b/addons/mail/static/src/core_ui/message.xml @@ -92,8 +92,8 @@ 'ps-2': env.inChatWindow and isAlignedRight and state.isEditing, }" > -
- +
+
Subject: + (edited)
-