From 44f86cf52a918c66ce3f12eddc71c2239d1fa714 Mon Sep 17 00:00:00 2001 From: "Didier (did)" Date: Tue, 16 Apr 2024 14:35:11 +0200 Subject: [PATCH] [IMP] mail: avoid broadcasting partner lists and tracking values Before this PR, `_message_format` function always included data that were only relevant to the logged user. It also `leak partner_ids`. This PR condition the `needaction_partner_ids`, `history_partner_ids`, `starredPersonas` and `trackingValues` values to a new param. This allows us to control when those data should be sent to the user. PR enterprise: https://github.com/odoo/enterprise/pull/61353 --- addons/im_livechat/controllers/chatbot.py | 6 ++-- addons/im_livechat/models/mail_message.py | 4 +-- addons/im_livechat/tests/test_message.py | 2 +- addons/mail/controllers/discuss/channel.py | 6 ++-- addons/mail/controllers/mailbox.py | 4 +-- addons/mail/controllers/thread.py | 6 ++-- addons/mail/models/mail_message.py | 21 +++++------ addons/mail/models/mail_thread.py | 2 +- .../static/tests/discuss_app/discuss.test.js | 4 +-- .../messaging_menu/messaging_menu.test.js | 2 +- .../tests/mock_server/mail_mock_server.js | 26 ++++++++++---- .../mock_models/discuss_channel.js | 2 +- .../mock_server/mock_models/mail_message.js | 36 ++++++++++--------- .../mock_server/mock_models/mail_thread.js | 2 +- .../mail/static/tests/thread/thread.test.js | 2 +- addons/rating/models/mail_message.py | 4 +-- addons/sms/models/mail_message.py | 4 +-- addons/test_mail/tests/test_mail_message.py | 6 ++-- .../tests/test_mail_thread_internals.py | 6 ++-- addons/test_mail/tests/test_message_track.py | 8 ++--- addons/test_mail/tests/test_performance.py | 8 ++--- 21 files changed, 88 insertions(+), 73 deletions(-) diff --git a/addons/im_livechat/controllers/chatbot.py b/addons/im_livechat/controllers/chatbot.py index f25f18a5853f7..92dec5b841383 100644 --- a/addons/im_livechat/controllers/chatbot.py +++ b/addons/im_livechat/controllers/chatbot.py @@ -15,7 +15,7 @@ def chatbot_restart(self, channel_id, chatbot_script_id): if not discuss_channel or not chatbot.exists(): return None chatbot_language = self._get_chatbot_language() - return discuss_channel.with_context(lang=chatbot_language)._chatbot_restart(chatbot)._message_format()[0] + return discuss_channel.with_context(lang=chatbot_language)._chatbot_restart(chatbot)._message_format(for_current_user=True)[0] @http.route("/chatbot/answer/save", type="json", auth="public") @add_guest_to_context @@ -73,7 +73,7 @@ def chatbot_trigger_step(self, channel_id, chatbot_script_id=None): 'message': plaintext2html(next_step.message) if not is_html_empty(next_step.message) else False, 'type': next_step.step_type, }, - 'message': posted_message._message_format()[0] if posted_message else None, + 'message': posted_message._message_format(for_current_user=True)[0] if posted_message else None, 'operatorFound': next_step.step_type == 'forward_operator' and len( discuss_channel.channel_member_ids) > 2, } @@ -98,7 +98,7 @@ def chatbot_validate_email(self, channel_id): result = chatbot._validate_email(user_answer.body, discuss_channel) if result['posted_message']: - result['posted_message'] = result['posted_message']._message_format()[0] + result['posted_message'] = result['posted_message']._message_format(for_current_user=True)[0] return result diff --git a/addons/im_livechat/models/mail_message.py b/addons/im_livechat/models/mail_message.py index bce56fd573bb9..e202565969c82 100644 --- a/addons/im_livechat/models/mail_message.py +++ b/addons/im_livechat/models/mail_message.py @@ -21,7 +21,7 @@ def _compute_parent_body(self): for message in self: message.parent_body = message.parent_id.body if message.parent_id else False - def _message_format(self, format_reply=True, msg_vals=None): + def _message_format(self, format_reply=True, msg_vals=None, for_current_user=False): """Override to remove email_from and to return the livechat username if applicable. A third param is added to the author_id tuple in this case to be able to differentiate it from the normal name in client code. @@ -31,7 +31,7 @@ def _message_format(self, format_reply=True, msg_vals=None): This allows the frontend display to include the additional features (e.g: Show additional buttons with the available answers for this step). """ - vals_list = super()._message_format(format_reply=format_reply, msg_vals=msg_vals) + vals_list = super()._message_format(format_reply=format_reply, msg_vals=msg_vals, for_current_user=for_current_user) for vals in vals_list: message_sudo = self.browse(vals['id']).sudo().with_prefetch(self.ids) discuss_channel = self.env['discuss.channel'].browse(message_sudo.res_id) if message_sudo.model == 'discuss.channel' else self.env['discuss.channel'] diff --git a/addons/im_livechat/tests/test_message.py b/addons/im_livechat/tests/test_message.py index fdadce70dce8e..ef8f067ca6b36 100644 --- a/addons/im_livechat/tests/test_message.py +++ b/addons/im_livechat/tests/test_message.py @@ -66,7 +66,7 @@ def test_message_format(self): % (record_rating.rating_image_url, record_rating.rating, record_rating.feedback), rating_id=record_rating.id, ) - self.assertEqual(message._message_format(), [{ + self.assertEqual(message._message_format(for_current_user=True), [{ 'attachments': [], 'author': { 'id': self.users[1].partner_id.id, diff --git a/addons/mail/controllers/discuss/channel.py b/addons/mail/controllers/discuss/channel.py index bb90b2d863c0d..71d88826945df 100644 --- a/addons/mail/controllers/discuss/channel.py +++ b/addons/mail/controllers/discuss/channel.py @@ -19,7 +19,7 @@ def _process_request_for_all(self, store, **kwargs): # fetch channels data before messages to benefit from prefetching (channel info might # prefetch a lot of data that message format could use) store.add({"Thread": channels._channel_info()}) - store.add({"Message": channels._get_last_messages()._message_format()}) + store.add({"Message": channels._get_last_messages()._message_format(for_current_user=True)}) class ChannelController(http.Controller): @@ -62,7 +62,7 @@ def discuss_channel_messages(self, channel_id, search_term=None, before=None, af ) if not request.env.user._is_public() and not around: res["messages"].set_message_done() - return {**res, "messages": res["messages"]._message_format()} + return {**res, "messages": res["messages"]._message_format(for_current_user=True)} @http.route("/discuss/channel/pinned_messages", methods=["POST"], type="json", auth="public") @add_guest_to_context @@ -70,7 +70,7 @@ def discuss_channel_pins(self, channel_id): channel = request.env["discuss.channel"].search([("id", "=", channel_id)]) if not channel: raise NotFound() - return channel.pinned_message_ids.sorted(key="pinned_at", reverse=True)._message_format() + return channel.pinned_message_ids.sorted(key="pinned_at", reverse=True)._message_format(for_current_user=True) @http.route("/discuss/channel/mute", methods=["POST"], type="json", auth="user") def discuss_channel_mute(self, channel_id, minutes): diff --git a/addons/mail/controllers/mailbox.py b/addons/mail/controllers/mailbox.py index 40dc6d58268d8..a9e7dcd1a5453 100644 --- a/addons/mail/controllers/mailbox.py +++ b/addons/mail/controllers/mailbox.py @@ -16,10 +16,10 @@ def discuss_inbox_messages(self, search_term=None, before=None, after=None, limi def discuss_history_messages(self, search_term=None, before=None, after=None, limit=30, around=None): domain = [("needaction", "=", False)] res = request.env["mail.message"]._message_fetch(domain, search_term=search_term, before=before, after=after, around=around, limit=limit) - return {**res, "messages": res["messages"]._message_format()} + return {**res, "messages": res["messages"]._message_format(for_current_user=True)} @http.route("/mail/starred/messages", methods=["POST"], type="json", auth="user") def discuss_starred_messages(self, search_term=None, before=None, after=None, limit=30, around=None): domain = [("starred_partner_ids", "in", [request.env.user.partner_id.id])] res = request.env["mail.message"]._message_fetch(domain, search_term=search_term, before=before, after=after, around=around, limit=limit) - return {**res, "messages": res["messages"]._message_format()} + return {**res, "messages": res["messages"]._message_format(for_current_user=True)} diff --git a/addons/mail/controllers/thread.py b/addons/mail/controllers/thread.py index 528128c3ad380..6d31c52a8705b 100644 --- a/addons/mail/controllers/thread.py +++ b/addons/mail/controllers/thread.py @@ -25,7 +25,7 @@ def mail_thread_messages(self, thread_model, thread_id, search_term=None, before res = request.env["mail.message"]._message_fetch(domain, search_term=search_term, before=before, after=after, around=around, limit=limit) if not request.env.user._is_public(): res["messages"].set_message_done() - return {**res, "messages": res["messages"]._message_format()} + return {**res, "messages": res["messages"]._message_format(for_current_user=True)} @http.route("/mail/partner/from_email", methods=["POST"], type="json", auth="user") def mail_thread_partner_from_email(self, emails, additional_values=None): @@ -107,7 +107,7 @@ def mail_message_post(self, thread_model, thread_id, post_data, context=None, ** post_data["partner_ids"] = list(set((post_data.get("partner_ids", [])) + new_partners)) message_data = thread.message_post( **{key: value for key, value in post_data.items() if key in self._get_allowed_message_post_params()} - )._message_format()[0] + )._message_format(for_current_user=True)[0] if "temporary_id" in request.context: message_data["temporary_id"] = request.context["temporary_id"] return message_data @@ -126,4 +126,4 @@ def mail_message_update_content(self, message_id, body, attachment_ids, attachme guest.env[message_sudo.model].browse([message_sudo.res_id])._message_update_content( message_sudo, body, attachment_ids=attachment_ids, partner_ids=partner_ids ) - return message_sudo._message_format()[0] + return message_sudo._message_format(for_current_user=True)[0] diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 519bd0ab9e84f..8c95e7c366521 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -897,7 +897,7 @@ def _record_by_message(self): record_by_message[message] = self.env[message.model].browse(message.res_id).with_prefetch(record_ids_by_model_name[message.model]) return record_by_message - def _message_format(self, format_reply=True, msg_vals=None): + def _message_format(self, format_reply=True, msg_vals=None, for_current_user=False): """ Get the message values in the format for web client. Since message values can be broadcasted, computed fields MUST NOT BE READ and broadcasted. @@ -995,11 +995,6 @@ def _message_format(self, format_reply=True, msg_vals=None): 'personas': [{'id': guest.id, 'name': guest.name, 'type': "guest"} for guest in reactions.guest_id] + [{'id': partner.id, 'name': partner.name, 'type': "partner"} for partner in reactions.partner_id], 'message': {'id': message_sudo.id}, } for content, reactions in reactions_per_content.items()] - allowed_tracking_ids = message_sudo.tracking_value_ids._filter_tracked_field_access(self.env) - displayed_tracking_ids = allowed_tracking_ids - if record and hasattr(record, '_track_filter_for_display'): - displayed_tracking_ids = record._track_filter_for_display(displayed_tracking_ids) - notifs = message_sudo.notification_ids.filtered("res_partner_id") vals.update(message_sudo._message_format_extras(format_reply)) vals.pop("starred_partner_ids", None) vals.update({ @@ -1007,15 +1002,12 @@ def _message_format(self, format_reply=True, msg_vals=None): 'default_subject': default_subject, 'notifications': message_sudo.notification_ids._filtered_for_web_client()._notification_format(), 'attachments': sorted(message_sudo.attachment_ids._attachment_format(), key=lambda a: a["id"]), - 'trackingValues': displayed_tracking_ids._tracking_value_format(), 'linkPreviews': message_sudo.link_preview_ids.filtered(lambda preview: not preview.is_hidden)._link_preview_format(), 'reactions': reaction_groups, 'pinned_at': message_sudo.pinned_at, 'record_name': record_name, 'create_date': message_sudo.create_date, 'write_date': message_sudo.write_date, - "needaction_partner_ids": notifs.filtered(lambda n: not n.is_read).res_partner_id.ids, - "starredPersonas": [{"id": partner_id, "type": "partner"} for partner_id in message_sudo.starred_partner_ids.ids], "is_note": message_sudo.subtype_id.id == note_id, "is_discussion": message_sudo.subtype_id.id == com_id, "subtype_description": message_sudo.subtype_id.description, @@ -1029,6 +1021,15 @@ def _message_format(self, format_reply=True, msg_vals=None): if self.env[message_sudo.model]._original_module: thread["module_icon"] = modules.module.get_module_icon(self.env[message_sudo.model]._original_module) vals["thread"] = thread + if for_current_user: + notifs = message_sudo.notification_ids.filtered("res_partner_id") + allowed_tracking_ids = message_sudo.tracking_value_ids._filter_tracked_field_access(self.env) + displayed_tracking_ids = allowed_tracking_ids + if record and hasattr(record, '_track_filter_for_display'): + displayed_tracking_ids = record._track_filter_for_display(displayed_tracking_ids) + vals["needaction_partner_ids"] = notifs.filtered(lambda n: not n.is_read).res_partner_id.ids + vals["starredPersonas"] = [{"id": partner_id, "type": "partner"} for partner_id in message_sudo.starred_partner_ids.ids] + vals["trackingValues"] = displayed_tracking_ids._tracking_value_format() return vals_list def _message_format_extras(self, format_reply): @@ -1120,7 +1121,7 @@ def _message_format_personalize(self, partner_id, messages_formatted=None, forma :return: list of messages_formatted personalized for the partner """ if not messages_formatted: - messages_formatted = self._message_format(format_reply=format_reply, msg_vals=msg_vals) + messages_formatted = self._message_format(format_reply=format_reply, msg_vals=msg_vals, for_current_user=True) self._message_format_personalized_prepare(messages_formatted, [partner_id]) for vals in messages_formatted: # set value for user being a follower, fallback to False if not prepared diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index a882f059d196e..f3c87c3b5a1ac 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -3170,7 +3170,7 @@ def _notify_thread_by_inbox(self, message, recipients_data, msg_vals=False, **kw MailMessage = self.env['mail.message'] messages_format_prepared = MailMessage._message_format_personalized_prepare( - message._message_format(msg_vals=msg_vals), partner_ids=inbox_pids) + message._message_format(msg_vals=msg_vals, for_current_user=True), partner_ids=inbox_pids) for partner_id in inbox_pids: bus_notifications.append( (self.env['res.partner'].browse(partner_id), diff --git a/addons/mail/static/tests/discuss_app/discuss.test.js b/addons/mail/static/tests/discuss_app/discuss.test.js index 136ce54f9375c..c339ffa7d8079 100644 --- a/addons/mail/static/tests/discuss_app/discuss.test.js +++ b/addons/mail/static/tests/discuss_app/discuss.test.js @@ -453,7 +453,7 @@ test("receive new needaction messages", async () => { notification_type: "inbox", res_partner_id: serverState.partnerId, }); - const [message1] = pyEnv["mail.message"]._message_format(messageId_1); + const [message1] = pyEnv["mail.message"]._message_format(messageId_1, true); const [partner] = pyEnv["res.partner"].read(serverState.partnerId); pyEnv["bus.bus"]._sendone(partner, "mail.message/inbox", message1); await contains("button", { text: "Inbox", contains: [".badge", { text: "1" }] }); @@ -474,7 +474,7 @@ test("receive new needaction messages", async () => { notification_type: "inbox", res_partner_id: serverState.partnerId, }); - const [message2] = pyEnv["mail.message"]._message_format(messageId_2); + const [message2] = pyEnv["mail.message"]._message_format(messageId_2, true); pyEnv["bus.bus"]._sendone(partner, "mail.message/inbox", message2); await contains("button", { text: "Inbox", contains: [".badge", { text: "2" }] }); await contains(".o-mail-Message", { count: 2 }); diff --git a/addons/mail/static/tests/messaging_menu/messaging_menu.test.js b/addons/mail/static/tests/messaging_menu/messaging_menu.test.js index 0aa18bb3140aa..6cbc37bae6a6a 100644 --- a/addons/mail/static/tests/messaging_menu/messaging_menu.test.js +++ b/addons/mail/static/tests/messaging_menu/messaging_menu.test.js @@ -1079,7 +1079,7 @@ test("messaging menu should show new needaction messages from chatter", async () notification_type: "inbox", res_partner_id: serverState.partnerId, }); - const [formattedMessage] = pyEnv["mail.message"]._message_format(messageId); + const [formattedMessage] = pyEnv["mail.message"]._message_format(messageId, true); const [partner] = pyEnv["res.partner"].read(serverState.partnerId); pyEnv["bus.bus"]._sendone(partner, "mail.message/inbox", formattedMessage); await contains(".o-mail-NotificationItem-text", { text: "Frodo Baggins: @Mitchel Admin" }); diff --git a/addons/mail/static/tests/mock_server/mail_mock_server.js b/addons/mail/static/tests/mock_server/mail_mock_server.js index 18b960865d271..2f8d6e4cc8248 100644 --- a/addons/mail/static/tests/mock_server/mail_mock_server.js +++ b/addons/mail/static/tests/mock_server/mail_mock_server.js @@ -339,7 +339,10 @@ async function discuss_channel_messages(request) { } return { ...res, - messages: MailMessage._message_format(res.messages.map((message) => message.id)), + messages: MailMessage._message_format( + res.messages.map((message) => message.id), + true + ), }; } @@ -408,7 +411,7 @@ async function discuss_channel_pins(request) { ["res_id", "=", channel_id], ["pinned_at", "!=", false], ]); - return MailMessage._message_format(messageIds); + return MailMessage._message_format(messageIds, true); } registerRoute("/discuss/channel/set_last_seen_message", discuss_channel_mark_as_seen); @@ -450,7 +453,8 @@ async function discuss_history_messages(request) { return { ...res, messages: MailMessage._message_format( - messagesWithNotification.map((message) => message.id) + messagesWithNotification.map((message) => message.id), + true ), }; } @@ -631,7 +635,7 @@ async function mail_message_update_content(request) { pinned_at: message.pinned_at, }, }); - return MailMessage._message_format([message_id])[0]; + return MailMessage._message_format([message_id], true)[0]; } registerRoute("/discuss/channel/:cid/partner/:pid/avatar_128", partnerAvatar128); @@ -727,7 +731,10 @@ async function discuss_starred_messages(request) { const res = MailMessage._message_fetch(domain, search_term, before, after, false, limit); return { ...res, - messages: MailMessage._message_format(res.messages.map((message) => message.id)), + messages: MailMessage._message_format( + res.messages.map((message) => message.id), + true + ), }; } @@ -758,7 +765,10 @@ async function mail_thread_messages(request) { MailMessage.set_message_done(res.messages.map((message) => message.id)); return { ...res, - messages: MailMessage._message_format(res.messages.map((message) => message.id)), + messages: MailMessage._message_format( + res.messages.map((message) => message.id), + true + ), }; } @@ -870,7 +880,9 @@ async function processRequest(request) { } return lastMessage; }, channelMessages[0]); - return lastMessage ? MailMessage._message_format([lastMessage.id])[0] : false; + return lastMessage + ? MailMessage._message_format([lastMessage.id], true)[0] + : false; }) .filter((lastMessage) => lastMessage), Thread: DiscussChannel._channel_info(channels.map((channel) => channel.id)), diff --git a/addons/mail/static/tests/mock_server/mock_models/discuss_channel.js b/addons/mail/static/tests/mock_server/mock_models/discuss_channel.js index bb850a79f2d9e..1be837a5d5628 100644 --- a/addons/mail/static/tests/mock_server/mock_models/discuss_channel.js +++ b/addons/mail/static/tests/mock_server/mock_models/discuss_channel.js @@ -318,7 +318,7 @@ export class DiscussChannel extends models.ServerModel { return { id: channel.id, last_message: lastMessage - ? MailMessage._message_format([lastMessage.id])[0] + ? MailMessage._message_format([lastMessage.id], true)[0] : false, }; }) diff --git a/addons/mail/static/tests/mock_server/mock_models/mail_message.js b/addons/mail/static/tests/mock_server/mock_models/mail_message.js index 55b3460e48918..107e376dd1d6f 100644 --- a/addons/mail/static/tests/mock_server/mock_models/mail_message.js +++ b/addons/mail/static/tests/mock_server/mock_models/mail_message.js @@ -67,7 +67,7 @@ export class MailMessage extends models.ServerModel { } /** @param {number[]} ids */ - _message_format(ids) { + _message_format(ids, for_current_user=false) { /** @type {import("mock_models").IrAttachment} */ const IrAttachment = this.env["ir.attachment"]; /** @type {import("mock_models").MailGuest} */ @@ -111,23 +111,12 @@ export class MailMessage extends models.ServerModel { const allNotifications = MailNotification._filter([ ["mail_message_id", "=", message.id], ]); - const historyPartnerIds = allNotifications - .filter((notification) => notification.is_read) - .map((notification) => notification.res_partner_id); - const needactionPartnerIds = allNotifications - .filter((notification) => !notification.is_read) - .map((notification) => notification.res_partner_id); let notifications = MailNotification._filtered_for_web_client( allNotifications.map((notification) => notification.id) ); notifications = MailNotification._notification_format( notifications.map((notification) => notification.id) ); - const trackingValues = MailTrackingValue._filter([ - ["id", "in", message.tracking_value_ids], - ]); - const formattedTrackingValues = - MailTrackingValue._tracking_value_format(trackingValues); const partners = ResPartner._filter([["id", "in", message.partner_ids]]); const linkPreviews = MailLinkPreview._filter([["id", "in", message.link_preview_ids]]); const linkPreviewsFormatted = linkPreviews.map((linkPreview) => @@ -170,7 +159,6 @@ export class MailMessage extends models.ServerModel { ...message, attachments: formattedAttachments, author, - history_partner_ids: historyPartnerIds, default_subject: message.model && message.res_id && @@ -180,7 +168,6 @@ export class MailMessage extends models.ServerModel { ).get(message.res_id), linkPreviews: linkPreviewsFormatted, reactions: reactionGroups, - needaction_partner_ids: needactionPartnerIds, notifications, parentMessage: message.parent_id ? this._message_format([message.parent_id])[0] @@ -188,8 +175,6 @@ export class MailMessage extends models.ServerModel { recipients: partners.map((p) => ({ id: p.id, name: p.name, type: "partner" })), record_name: thread && (thread.name !== undefined ? thread.name : thread.display_name), - starredPersonas: message.starred_partner_ids.map((id) => ({ id, type: "partner" })), - trackingValues: formattedTrackingValues, pinned_at: message.pinned_at, }; delete response.author_id; @@ -214,6 +199,23 @@ export class MailMessage extends models.ServerModel { } Object.assign(response, { thread }); } + if (for_current_user) { + const needactionPartnerIds = allNotifications + .filter((notification) => !notification.is_read) + .map((notification) => notification.res_partner_id); + response["needaction_partner_ids"] = needactionPartnerIds; + const historyPartnerIds = allNotifications + .filter((notification) => notification.is_read) + .map((notification) => notification.res_partner_id); + response["history_partner_ids"] = historyPartnerIds; + response["starredPersonas"] = message.starred_partner_ids.map((id) => ({ id, type: "partner" })); + const trackingValues = MailTrackingValue._filter([ + ["id", "in", message.tracking_value_ids], + ]); + const formattedTrackingValues = + MailTrackingValue._tracking_value_format(trackingValues); + response["trackingValues"] = formattedTrackingValues; + } return response; }); } @@ -469,7 +471,7 @@ export class MailMessage extends models.ServerModel { /** @type {import("mock_models").MailFollowers} */ const MailFollowers = this.env["mail.followers"]; - const messages = this._message_format(ids); + const messages = this._message_format(ids, true); messages.forEach((message) => { if (message.model && message.res_id) { const follower = MailFollowers._filter([ diff --git a/addons/mail/static/tests/mock_server/mock_models/mail_thread.js b/addons/mail/static/tests/mock_server/mock_models/mail_thread.js index 188d3c852b77f..de9f495c13789 100644 --- a/addons/mail/static/tests/mock_server/mock_models/mail_thread.js +++ b/addons/mail/static/tests/mock_server/mock_models/mail_thread.js @@ -113,7 +113,7 @@ export class MailThread extends models.ServerModel { } MailThread._notify_thread.call(this, ids, messageId, kwargs.context?.temporary_id); return { - ...MailMessage._message_format([messageId])[0], + ...MailMessage._message_format([messageId], true)[0], temporary_id: kwargs.context?.temporary_id, }; } diff --git a/addons/mail/static/tests/thread/thread.test.js b/addons/mail/static/tests/thread/thread.test.js index 85c51a21586b2..b19941e278001 100644 --- a/addons/mail/static/tests/thread/thread.test.js +++ b/addons/mail/static/tests/thread/thread.test.js @@ -921,7 +921,7 @@ test("Opening thread with needaction messages should mark all messages of thread res_partner_id: serverState.partnerId, }); // simulate receiving a new needaction message - const [formattedMessage] = pyEnv["mail.message"]._message_format(messageId); + const [formattedMessage] = pyEnv["mail.message"]._message_format(messageId, true); const [partner] = pyEnv["res.partner"].read(serverState.partnerId); pyEnv["bus.bus"]._sendone(partner, "mail.message/inbox", formattedMessage); await contains("button", { text: "Inbox", contains: [".badge", { text: "1" }] }); diff --git a/addons/rating/models/mail_message.py b/addons/rating/models/mail_message.py index e8c6eaa175097..ed7d66d3598e3 100644 --- a/addons/rating/models/mail_message.py +++ b/addons/rating/models/mail_message.py @@ -26,8 +26,8 @@ def _search_rating_value(self, operator, operand): ]) return [('id', 'in', ratings.mapped('message_id').ids)] - def _message_format(self, format_reply=True, msg_vals=None): - message_values = super()._message_format(format_reply=format_reply, msg_vals=msg_vals) + def _message_format(self, format_reply=True, msg_vals=None, for_current_user=False): + message_values = super()._message_format(format_reply=format_reply, msg_vals=msg_vals, for_current_user=for_current_user) rating_mixin_messages = self.filtered(lambda message: message.model and message.res_id diff --git a/addons/sms/models/mail_message.py b/addons/sms/models/mail_message.py index e22fab7422dd5..1a73f5b478a47 100644 --- a/addons/sms/models/mail_message.py +++ b/addons/sms/models/mail_message.py @@ -33,13 +33,13 @@ def _search_has_sms_error(self, operator, operand): return ['&', ('notification_ids.notification_status', '=', 'exception'), ('notification_ids.notification_type', '=', 'sms')] raise NotImplementedError() - def _message_format(self, format_reply=True, msg_vals=None): + def _message_format(self, format_reply=True, msg_vals=None, for_current_user=False): """ Override in order to retrieves data about SMS (recipient name and SMS status) TDE FIXME: clean the overall message_format thingy """ - message_values = super()._message_format(format_reply=format_reply, msg_vals=msg_vals) + message_values = super()._message_format(format_reply=format_reply, msg_vals=msg_vals, for_current_user=for_current_user) all_sms_notifications = self.env['mail.notification'].sudo().search([ ('mail_message_id', 'in', [r['id'] for r in message_values]), ('notification_type', '=', 'sms') diff --git a/addons/test_mail/tests/test_mail_message.py b/addons/test_mail/tests/test_mail_message.py index 19412d4b2a9cd..5e4789f917e17 100644 --- a/addons/test_mail/tests/test_mail_message.py +++ b/addons/test_mail/tests/test_mail_message.py @@ -104,10 +104,10 @@ def test_mail_message_format(self): } for record in [record1, record2]]) for message, record in zip(messages, [record1, record2]): with self.subTest(record=record): - formatted = message._message_format()[0] + formatted = message._message_format(for_current_user=True)[0] self.assertEqual(formatted['record_name'], record.name) record.write({'name': 'Just Test'}) - formatted = message._message_format()[0] + formatted = message._message_format(for_current_user=True)[0] self.assertEqual(formatted['record_name'], 'Just Test') @mute_logger('odoo.models.unlink') @@ -127,7 +127,7 @@ def test_mail_message_format_access(self): # message_format. self.env.flush_all() self.env.invalidate_all() - res = message.with_user(self.user_employee)._message_format() + res = message.with_user(self.user_employee)._message_format(for_current_user=True) self.assertEqual(res[0].get('record_name'), 'Test1') def test_mail_message_values_body_base64_image(self): diff --git a/addons/test_mail/tests/test_mail_thread_internals.py b/addons/test_mail/tests/test_mail_thread_internals.py index 25d6fcea9a057..3a54b022d6fba 100644 --- a/addons/test_mail/tests/test_mail_thread_internals.py +++ b/addons/test_mail/tests/test_mail_thread_internals.py @@ -448,7 +448,7 @@ def test_unlink_notification_message(self): ) with self.assertRaises(exceptions.AccessError): - notification_msg.with_env(self.env)._message_format() + notification_msg.with_env(self.env)._message_format(for_current_user=True) channel_message = self.env['mail.message'].sudo().search([('model', '=', 'discuss.channel'), ('res_id', 'in', channel.ids)]) self.assertEqual(len(channel_message), 1, "Test message should have been posted") @@ -476,12 +476,12 @@ def test_message_format(self): 'record_name': 'Not used in message_format', 'res_id': test_record.id, }) - formatted = message._message_format()[0] + formatted = message._message_format(for_current_user=True)[0] self.assertEqual(formatted['default_subject'], test_record.name) self.assertEqual(formatted['record_name'], test_record.name) test_record.write({'name': 'Just Test'}) - formatted = message._message_format()[0] + formatted = message._message_format(for_current_user=True)[0] self.assertEqual(formatted['default_subject'], 'Just Test') self.assertEqual(formatted['record_name'], 'Just Test') diff --git a/addons/test_mail/tests/test_message_track.py b/addons/test_mail/tests/test_message_track.py index 392c0f236c8bc..21a73f488f7fa 100644 --- a/addons/test_mail/tests/test_message_track.py +++ b/addons/test_mail/tests/test_message_track.py @@ -100,14 +100,14 @@ def test_message_track_filter_for_display(self): ) # first record: tracking value should be hidden message_0 = records[0].message_ids[0] - formatted = message_0._message_format()[0] + formatted = message_0._message_format(for_current_user=True)[0] self.assertEqual(formatted['trackingValues'], [], 'Hidden values should not be formatted') mail_render = records[0]._notify_by_email_prepare_rendering_context(message_0, {}) self.assertEqual(mail_render['tracking_values'], []) # second record: all values displayed message_1 = records[1].message_ids[0] - formatted = message_1._message_format()[0] + formatted = message_1._message_format(for_current_user=True)[0] self.assertEqual(len(formatted['trackingValues']), 1) self.assertDictEqual( formatted['trackingValues'][0], @@ -686,8 +686,8 @@ def test_track_groups(self): self.record.sudo().write({'email_from': 'X'}) self.flush_tracking() - msg_emp = self.record.message_ids._message_format() - msg_sudo = self.record.sudo().message_ids._message_format() + msg_emp = self.record.message_ids._message_format(for_current_user=True) + msg_sudo = self.record.sudo().message_ids._message_format(for_current_user=True) tracking_values = self.env['mail.tracking.value'].search([('mail_message_id', '=', self.record.message_ids[0].id)]) formattedTrackingValues = [{ 'changedField': 'Email From', diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index 728fbc68d6cca..df2a7ad28b018 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -1269,7 +1269,7 @@ def test_message_format_multi(self): messages_all = self.messages_all.with_env(self.env) with self.assertQueryCount(employee=26): - res = messages_all._message_format() + res = messages_all._message_format(for_current_user=True) self.assertEqual(len(res), 2*2) for message in res: @@ -1282,7 +1282,7 @@ def test_message_format_single(self): message = self.messages_all[0].with_env(self.env) with self.assertQueryCount(employee=23): - res = message._message_format() + res = message._message_format(for_current_user=True) self.assertEqual(len(res), 1) self.assertEqual(len(res[0]['attachments']), 2) @@ -1303,14 +1303,14 @@ def test_message_format_group_thread_name_by_model(self): } for record in records]) with self.assertQueryCount(employee=7): - res = messages._message_format() + res = messages._message_format(for_current_user=True) self.assertEqual(len(res), 6) self.env.flush_all() self.env.invalidate_all() with self.assertQueryCount(employee=15): - res = messages._message_format() + res = messages._message_format(for_current_user=True) self.assertEqual(len(res), 6)