From 632dc0cb1995a1980f1479eab7ec9b6ca40552c9 Mon Sep 17 00:00:00 2001 From: payen000 Date: Mon, 4 Sep 2023 13:28:09 -0700 Subject: [PATCH] [MIG] mail_tracking: Completed migration to 16.0 The following changes were implemented: 1 - Added Failed Message component and related components to reuse the Message component when rendering failed messages. This allows us to dispose of the messagefailed JS model altogether, since failed messages are now just regular messages that were marked as failed. 2 - Added Owl reactivity to failed message actions so that browser does not have to be reloaded each time a message is marked as reviewed or resent. 3 - Fixed 'Retry' and 'Set as reviewed' flows for failed messages. 4 - Fixed `Failed sent messages` filter on models by overriding `get_view` instead of `_fields_view_get` 5 - Refactored folder structure to more closely resemble the `mail` module's folder structure. 6 - Refactored module to utilize `Command` as a means to create, write, etc. instead of `[0, ...]`, `[4, ...]`. 7 - Fixed and added unit tests. 8 - Removed dead/unused code from previous version. --- mail_tracking/__manifest__.py | 41 ++- mail_tracking/controllers/discuss.py | 18 +- mail_tracking/controllers/main.py | 25 -- mail_tracking/demo/demo.xml | 28 +- mail_tracking/models/mail_message.py | 6 +- mail_tracking/models/mail_thread.py | 10 +- mail_tracking/models/mail_tracking_email.py | 2 +- mail_tracking/readme/CONTRIBUTORS.rst | 3 + .../failed_message_storage.esm.js | 21 ++ .../static/src/components/discuss/discuss.xml | 227 ++++++++++++ .../discuss_sidebar_mailbox.esm.js | 16 + .../discuss_sidebar_mailbox.xml | 34 ++ .../failed_message/failed_message.esm.js | 11 + .../failed_message/failed_message.scss | 14 + .../failed_message/failed_message.xml | 57 +++ .../failed_message_list.esm.js | 14 + .../failed_message_list.xml | 70 ++++ .../src/components/message/message.esm.js | 71 ++++ .../message/message.scss} | 0 .../message_list/message_list.esm.js | 12 + .../components/thread_view/thread_view.scss | 5 + .../components/thread_view/thread_view.xml | 18 + .../static/src/css/failed_message.scss | 348 ------------------ .../js/failed_message/mail_failed_box.esm.js | 57 --- .../src/js/failed_message/thread.esm.js | 58 --- mail_tracking/static/src/js/message.esm.js | 55 --- .../static/src/js/models/chatter.esm.js | 28 -- .../static/src/js/models/mail_tracking.esm.js | 36 -- .../static/src/js/models/message.esm.js | 22 -- .../src/js/models/message_failed.esm.js | 52 --- .../static/src/js/models/message_view.esm.js | 50 --- .../js/models/messaging_initializer.esm.js | 17 - .../static/src/js/models/thread_cache.esm.js | 16 - .../static/src/models/chatter.esm.js | 17 + .../discuss_sidebar_mailbox_view.esm.js | 12 +- .../src/{js => }/models/discuss_view.esm.js | 4 +- .../static/src/{js => }/models/mailbox.esm.js | 12 +- .../static/src/models/message.esm.js | 64 ++++ .../src/models/message_list_view.esm.js | 33 ++ .../src/models/message_list_view_item.esm.js | 15 + .../static/src/models/message_view.esm.js | 12 + .../src/{js => }/models/messaging.esm.js | 2 +- .../src/models/messaging_initializer.esm.js | 17 + .../static/src/{js => }/models/thread.esm.js | 17 +- .../static/src/xml/failed_message/common.xml | 23 -- .../static/src/xml/failed_message/discuss.xml | 65 ---- .../static/src/xml/failed_message/thread.xml | 128 ------- .../static/src/xml/mail_tracking.xml | 116 ------ mail_tracking/tests/test_mail_tracking.py | 107 ++++-- .../views/mail_tracking_email_view.xml | 2 +- 50 files changed, 898 insertions(+), 1190 deletions(-) create mode 100644 mail_tracking/static/src/client_actions/failed_message_storage.esm.js create mode 100644 mail_tracking/static/src/components/discuss/discuss.xml create mode 100644 mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.esm.js create mode 100644 mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.xml create mode 100644 mail_tracking/static/src/components/failed_message/failed_message.esm.js create mode 100644 mail_tracking/static/src/components/failed_message/failed_message.scss create mode 100644 mail_tracking/static/src/components/failed_message/failed_message.xml create mode 100644 mail_tracking/static/src/components/failed_message_list/failed_message_list.esm.js create mode 100644 mail_tracking/static/src/components/failed_message_list/failed_message_list.xml create mode 100644 mail_tracking/static/src/components/message/message.esm.js rename mail_tracking/static/src/{css/mail_tracking.scss => components/message/message.scss} (100%) create mode 100644 mail_tracking/static/src/components/message_list/message_list.esm.js create mode 100644 mail_tracking/static/src/components/thread_view/thread_view.scss create mode 100644 mail_tracking/static/src/components/thread_view/thread_view.xml delete mode 100644 mail_tracking/static/src/css/failed_message.scss delete mode 100644 mail_tracking/static/src/js/failed_message/mail_failed_box.esm.js delete mode 100644 mail_tracking/static/src/js/failed_message/thread.esm.js delete mode 100644 mail_tracking/static/src/js/message.esm.js delete mode 100644 mail_tracking/static/src/js/models/chatter.esm.js delete mode 100644 mail_tracking/static/src/js/models/mail_tracking.esm.js delete mode 100644 mail_tracking/static/src/js/models/message.esm.js delete mode 100644 mail_tracking/static/src/js/models/message_failed.esm.js delete mode 100644 mail_tracking/static/src/js/models/message_view.esm.js delete mode 100644 mail_tracking/static/src/js/models/messaging_initializer.esm.js delete mode 100644 mail_tracking/static/src/js/models/thread_cache.esm.js create mode 100644 mail_tracking/static/src/models/chatter.esm.js rename mail_tracking/static/src/{js => }/models/discuss_sidebar_mailbox_view.esm.js (51%) rename mail_tracking/static/src/{js => }/models/discuss_view.esm.js (65%) rename mail_tracking/static/src/{js => }/models/mailbox.esm.js (82%) create mode 100644 mail_tracking/static/src/models/message.esm.js create mode 100644 mail_tracking/static/src/models/message_list_view.esm.js create mode 100644 mail_tracking/static/src/models/message_list_view_item.esm.js create mode 100644 mail_tracking/static/src/models/message_view.esm.js rename mail_tracking/static/src/{js => }/models/messaging.esm.js (85%) create mode 100644 mail_tracking/static/src/models/messaging_initializer.esm.js rename mail_tracking/static/src/{js => }/models/thread.esm.js (62%) delete mode 100644 mail_tracking/static/src/xml/failed_message/common.xml delete mode 100644 mail_tracking/static/src/xml/failed_message/discuss.xml delete mode 100644 mail_tracking/static/src/xml/failed_message/thread.xml delete mode 100644 mail_tracking/static/src/xml/mail_tracking.xml diff --git a/mail_tracking/__manifest__.py b/mail_tracking/__manifest__.py index a2a3a3f7b8..73e8e05bdc 100644 --- a/mail_tracking/__manifest__.py +++ b/mail_tracking/__manifest__.py @@ -25,23 +25,32 @@ "views/res_partner_view.xml", ], "assets": { - "mail.assets_messaging": [ - "mail_tracking/static/src/js/models/*.js", - ], "web.assets_backend": [ - "mail_tracking/static/src/xml/mail_tracking.xml", - "mail_tracking/static/src/css/mail_tracking.scss", - "mail_tracking/static/src/css/failed_message.scss", - "mail_tracking/static/src/js/message.esm.js", - "mail_tracking/static/src/js/failed_message/mail_failed_box.esm.js", - "mail_tracking/static/src/js/models/thread.esm.js", - "mail_tracking/static/src/xml/mail_tracking.xml", - "mail_tracking/static/src/xml/failed_message/common.xml", - "mail_tracking/static/src/xml/failed_message/thread.xml", - "mail_tracking/static/src/xml/failed_message/discuss.xml", - ], - "web.assets_frontend": [ - "mail_tracking/static/src/css/failed_message.scss", + "mail_tracking/static/src/client_actions/failed_message_storage.esm.js", + "mail_tracking/static/src/models/chatter.esm.js", + "mail_tracking/static/src/models/discuss_sidebar_mailbox_view.esm.js", + "mail_tracking/static/src/models/discuss_view.esm.js", + "mail_tracking/static/src/models/mailbox.esm.js", + "mail_tracking/static/src/models/message_list_view_item.esm.js", + "mail_tracking/static/src/models/message_list_view.esm.js", + "mail_tracking/static/src/models/message_view.esm.js", + "mail_tracking/static/src/models/message.esm.js", + "mail_tracking/static/src/models/messaging_initializer.esm.js", + "mail_tracking/static/src/models/messaging.esm.js", + "mail_tracking/static/src/models/thread.esm.js", + "mail_tracking/static/src/components/discuss/discuss.xml", + "mail_tracking/static/src/components/message/message.esm.js", + "mail_tracking/static/src/components/message/message.scss", + "mail_tracking/static/src/components/message_list/message_list.esm.js", + "mail_tracking/static/src/components/failed_message/failed_message.xml", + "mail_tracking/static/src/components/failed_message/failed_message.esm.js", + "mail_tracking/static/src/components/failed_message/failed_message.scss", + "mail_tracking/static/src/components/failed_message_list/failed_message_list.xml", + "mail_tracking/static/src/components/failed_message_list/failed_message_list.esm.js", # noqa: B950 + "mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.xml", # noqa: B950 + "mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.esm.js", # noqa: B950 + "mail_tracking/static/src/components/thread_view/thread_view.xml", + "mail_tracking/static/src/components/thread_view/thread_view.scss", ], }, "demo": ["demo/demo.xml"], diff --git a/mail_tracking/controllers/discuss.py b/mail_tracking/controllers/discuss.py index 8a5652d24b..b41a993416 100644 --- a/mail_tracking/controllers/discuss.py +++ b/mail_tracking/controllers/discuss.py @@ -6,9 +6,9 @@ class MailTrackingDiscussController(DiscussController): @http.route() - def mail_init_messaging(self): + def mail_init_messaging(self, **kwargs): """Route used to initial values of Discuss app""" - values = super().mail_init_messaging() + values = super().mail_init_messaging(**kwargs) values.update( {"failed_counter": http.request.env["mail.message"].get_failed_count()} ) @@ -16,9 +16,13 @@ def mail_init_messaging(self): @http.route("/mail/failed/messages", methods=["POST"], type="json", auth="user") def discuss_failed_messages(self, max_id=None, min_id=None, limit=30, **kwargs): - return http.request.env["mail.message"]._message_fetch( - domain=[("is_failed_message", "=", True)], - max_id=max_id, - min_id=min_id, - limit=limit, + return ( + http.request.env["mail.message"] + ._message_fetch( + domain=[("is_failed_message", "=", True)], + max_id=max_id, + min_id=min_id, + limit=limit, + ) + .message_format() ) diff --git a/mail_tracking/controllers/main.py b/mail_tracking/controllers/main.py index 510d9de0e3..ab1ca78199 100644 --- a/mail_tracking/controllers/main.py +++ b/mail_tracking/controllers/main.py @@ -40,31 +40,6 @@ def _request_metadata(self): "ua_family": request.user_agent.browser or False, } - # TODO Remove useless controller - @http.route( - [ - "/mail/tracking/all/", - "/mail/tracking/event//", - ], - type="http", - auth="none", - csrf=False, - ) - def mail_tracking_event(self, db, event_type=None, **kw): - """Route used by external mail service""" - metadata = self._request_metadata() - res = None - with db_env(db) as env: - try: - res = env["mail.tracking.email"].event_process( - http.request, kw, metadata, event_type=event_type - ) - except Exception as e: - _logger.warning(e) - if not res or res == "NOT FOUND": - return werkzeug.exceptions.NotAcceptable() - return res - @http.route( [ "/mail/tracking/open/" "//blank.gif", diff --git a/mail_tracking/demo/demo.xml b/mail_tracking/demo/demo.xml index a1d7dea9b3..c121998ed3 100644 --- a/mail_tracking/demo/demo.xml +++ b/mail_tracking/demo/demo.xml @@ -13,10 +13,13 @@ This is a message with CC

]]>
wood.corner26@example.com - + Message with CC @@ -41,10 +44,13 @@ This is a failed message

]]>
wood.corner26@example.com - + Failed Message @@ -69,10 +75,13 @@ This is another failed message

]]>
jackson.group82@example.com - + Failed Message @@ -97,10 +106,13 @@ This is another failed message

]]>
admin@example.com - + Failed Message diff --git a/mail_tracking/models/mail_message.py b/mail_tracking/models/mail_message.py index b393f01d04..c62de8644b 100644 --- a/mail_tracking/models/mail_message.py +++ b/mail_tracking/models/mail_message.py @@ -262,14 +262,9 @@ def _prepare_dict_failed_message(self): return failed_partners = failed_trackings.mapped("partner_id") failed_recipients = failed_partners.name_get() - if self.author_id: - author = self.author_id.name_get()[0] - else: - author = (-1, _("-Unknown Author-")) return { "id": self.id, "date": self.date, - "author": author, "body": self.body, "failed_recipients": failed_recipients, } @@ -292,6 +287,7 @@ def set_need_action_done(self): self.env["bus.bus"]._sendone( self.env.user.partner_id, "toggle_tracking_status", self.ids ) + return self.mail_tracking_needs_action @api.model def get_failed_count(self): diff --git a/mail_tracking/models/mail_thread.py b/mail_tracking/models/mail_thread.py index 93391dc4ff..6807293082 100644 --- a/mail_tracking/models/mail_thread.py +++ b/mail_tracking/models/mail_thread.py @@ -88,17 +88,13 @@ def _add_extra_recipients_suggestions(self, suggestions, field_mail, reason): ) @api.model - def _fields_view_get( - self, view_id=None, view_type="form", toolbar=False, submenu=False - ): + def get_view(self, view_id=None, view_type="form", **options): """Add filters for failed messages. - These filters will show up on any form or search views of any + These filters will show up on any search views of any model inheriting from ``mail.thread``. """ - res = super()._fields_view_get( - view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu - ) + res = super().get_view(view_id, view_type, **options) if view_type != "search": return res doc = etree.XML(res["arch"]) diff --git a/mail_tracking/models/mail_tracking_email.py b/mail_tracking/models/mail_tracking_email.py index 64ec73e21d..84063bf386 100644 --- a/mail_tracking/models/mail_tracking_email.py +++ b/mail_tracking/models/mail_tracking_email.py @@ -41,7 +41,7 @@ class MailTrackingEmail(models.Model): time = fields.Datetime(readonly=True, index=True) date = fields.Date(readonly=True, compute="_compute_date", store=True) mail_message_id = fields.Many2one( - string="Message", comodel_name="mail.message", readonly=True, index=True + comodel_name="mail.message", readonly=True, index=True ) message_id = fields.Char(compute="_compute_message_id") mail_id = fields.Many2one(string="Email", comodel_name="mail.mail", readonly=True) diff --git a/mail_tracking/readme/CONTRIBUTORS.rst b/mail_tracking/readme/CONTRIBUTORS.rst index 93cebe9df1..ffcc606755 100644 --- a/mail_tracking/readme/CONTRIBUTORS.rst +++ b/mail_tracking/readme/CONTRIBUTORS.rst @@ -9,3 +9,6 @@ * `Eezee-IT `_: * Asma Elferkhsi + +* `Vauxoo `_: + * Agustín Payen Sandoval diff --git a/mail_tracking/static/src/client_actions/failed_message_storage.esm.js b/mail_tracking/static/src/client_actions/failed_message_storage.esm.js new file mode 100644 index 0000000000..5f3034d8fe --- /dev/null +++ b/mail_tracking/static/src/client_actions/failed_message_storage.esm.js @@ -0,0 +1,21 @@ +/** @odoo-module **/ + +const {reactive, useState} = owl; + +// Set reactive object to observe the current state of failed messages. +// This allows re-rendering only non-reviewed failed messages without +// reloading the window after a failed message has been dealt with. +export const store = reactive({ + reviewedChatterMessageIds: new Set(), + reviewedDiscussMessageIds: new Set(), + addChatterMessage(item) { + this.reviewedChatterMessageIds.add(item); + }, + addDiscussMessage(item) { + this.reviewedDiscussMessageIds.add(item); + }, +}); + +export function useStore() { + return useState(store); +} diff --git a/mail_tracking/static/src/components/discuss/discuss.xml b/mail_tracking/static/src/components/discuss/discuss.xml new file mode 100644 index 0000000000..8d459e2148 --- /dev/null +++ b/mail_tracking/static/src/components/discuss/discuss.xml @@ -0,0 +1,227 @@ + + + + + + + + + + + + +
+ No failed messages +
+ Failed messages will appear here. +
+
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set as Reviewed + + + + Retry + + + + + + + +

+ To: + + + - + + + + + + + + + +

+
+
+ + diff --git a/mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.esm.js b/mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.esm.js new file mode 100644 index 0000000000..52b391cd89 --- /dev/null +++ b/mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.esm.js @@ -0,0 +1,16 @@ +/** @odoo-module **/ + +import {DiscussSidebarMailbox} from "@mail/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox"; +import {patch} from "web.utils"; +import {useStore} from "../../client_actions/failed_message_storage.esm"; + +patch( + DiscussSidebarMailbox.prototype, + "mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.esm.js", + { + setup() { + this._super(...arguments); + this.store = useStore(); + }, + } +); diff --git a/mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.xml b/mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.xml new file mode 100644 index 0000000000..b9ab6ba543 --- /dev/null +++ b/mail_tracking/static/src/components/discuss_sidebar_mailbox/discuss_sidebar_mailbox.xml @@ -0,0 +1,34 @@ + + + + + + +
+ +
+
+
+ + + false + + +
+
diff --git a/mail_tracking/static/src/components/failed_message/failed_message.esm.js b/mail_tracking/static/src/components/failed_message/failed_message.esm.js new file mode 100644 index 0000000000..d559b54f34 --- /dev/null +++ b/mail_tracking/static/src/components/failed_message/failed_message.esm.js @@ -0,0 +1,11 @@ +/** @odoo-module **/ + +import {Message} from "@mail/components/message/message"; +import {registerMessagingComponent} from "@mail/utils/messaging_component"; + +export class FailedMessage extends Message {} + +FailedMessage.props = {record: Object, isFailedMessage: true}; +FailedMessage.template = "mail_tracking.FailedMessage"; + +registerMessagingComponent(FailedMessage); diff --git a/mail_tracking/static/src/components/failed_message/failed_message.scss b/mail_tracking/static/src/components/failed_message/failed_message.scss new file mode 100644 index 0000000000..f2672a1854 --- /dev/null +++ b/mail_tracking/static/src/components/failed_message/failed_message.scss @@ -0,0 +1,14 @@ +/* Copyright 2019 Alexandre Díaz + License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */ + +.o_Activity_icon.fa.fa-exclamation { + color: white; + left: 1.05ch; + position: relative; + top: 0.2ch; +} + +.o_Activity_iconContainer.bg-danger.rounded-circle { + width: 3ch; + height: 3ch; +} diff --git a/mail_tracking/static/src/components/failed_message/failed_message.xml b/mail_tracking/static/src/components/failed_message/failed_message.xml new file mode 100644 index 0000000000..f9b0531cb6 --- /dev/null +++ b/mail_tracking/static/src/components/failed_message/failed_message.xml @@ -0,0 +1,57 @@ + + + + + + + messageView.doNothing + messageView.doNothing + + + + false + + + +
+ + + false + + + +
+ +
+
+ + false + + + + diff --git a/mail_tracking/static/src/components/failed_message_list/failed_message_list.esm.js b/mail_tracking/static/src/components/failed_message_list/failed_message_list.esm.js new file mode 100644 index 0000000000..9e5e4a35fc --- /dev/null +++ b/mail_tracking/static/src/components/failed_message_list/failed_message_list.esm.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +import {MessageList} from "@mail/components/message_list/message_list"; +import {registerMessagingComponent} from "@mail/utils/messaging_component"; + +export class FailedMessageList extends MessageList { + _onClickTitle() { + this.messageListView.toggleMessageFailedBoxVisibility(); + } +} + +FailedMessageList.template = "mail_tracking.FailedMessageList"; + +registerMessagingComponent(FailedMessageList); diff --git a/mail_tracking/static/src/components/failed_message_list/failed_message_list.xml b/mail_tracking/static/src/components/failed_message_list/failed_message_list.xml new file mode 100644 index 0000000000..466207e60c --- /dev/null +++ b/mail_tracking/static/src/components/failed_message_list/failed_message_list.xml @@ -0,0 +1,70 @@ + + + + + + + + + diff --git a/mail_tracking/static/src/components/message/message.esm.js b/mail_tracking/static/src/components/message/message.esm.js new file mode 100644 index 0000000000..7eb0283311 --- /dev/null +++ b/mail_tracking/static/src/components/message/message.esm.js @@ -0,0 +1,71 @@ +/** @odoo-module **/ + +import {Message} from "@mail/components/message/message"; +import {patch} from "web.utils"; +import {useStore} from "../../client_actions/failed_message_storage.esm"; + +patch(Message.prototype, "mail_tracking/static/src/components/message/message.esm.js", { + constructor() { + this._super(...arguments); + }, + setup() { + this._super(...arguments); + this.store = useStore(); + }, + _onTrackingStatusClick(event) { + var tracking_email_id = $(event.currentTarget).data("tracking"); + event.preventDefault(); + return this.env.services.action.doAction({ + type: "ir.actions.act_window", + view_type: "form", + view_mode: "form", + res_model: "mail.tracking.email", + views: [[false, "form"]], + target: "new", + res_id: tracking_email_id, + }); + }, + _addMessageIdToStore(messageID) { + this.store.addChatterMessage(messageID); + if (this.props.record.message.isFailed) this.store.addDiscussMessage(messageID); + }, + async _onMarkFailedMessageReviewed(event) { + event.preventDefault(); + const messageID = $(event.currentTarget).data("message-id"); + const messageNeedsAction = await this._markFailedMessageReviewed(messageID); + // Add the reviewed message ID to storage so it is excluded from the list of rendered messages + if (!messageNeedsAction) { + this._addMessageIdToStore(messageID); + } + }, + _onRetryFailedMessage(event) { + event.preventDefault(); + const messageID = $(event.currentTarget).data("message-id"); + this.env.services.action.doAction("mail.mail_resend_message_action", { + additionalContext: { + mail_message_to_resend: messageID, + }, + onClose: async () => { + // Check if message is still 'failed' after Retry, and if it is not, add its ID to storage so + // it is excluded from the list of rendered messages + const failedMessages = await this.messaging.rpc({ + model: "mail.message", + method: "get_failed_messages", + args: [[messageID]], + }); + const failedMessageIds = failedMessages.map((message) => { + return (message || {}).id; + }); + if (failedMessageIds.length && !failedMessageIds.includes(messageID)) + this._addMessageIdToStore(messageID); + }, + }); + }, + _markFailedMessageReviewed(id) { + return this.messaging.rpc({ + model: "mail.message", + method: "set_need_action_done", + args: [[id]], + }); + }, +}); diff --git a/mail_tracking/static/src/css/mail_tracking.scss b/mail_tracking/static/src/components/message/message.scss similarity index 100% rename from mail_tracking/static/src/css/mail_tracking.scss rename to mail_tracking/static/src/components/message/message.scss diff --git a/mail_tracking/static/src/components/message_list/message_list.esm.js b/mail_tracking/static/src/components/message_list/message_list.esm.js new file mode 100644 index 0000000000..919b910420 --- /dev/null +++ b/mail_tracking/static/src/components/message_list/message_list.esm.js @@ -0,0 +1,12 @@ +/** @odoo-module **/ + +import {MessageList} from "@mail/components/message_list/message_list"; +import {patch} from "web.utils"; +import {useStore} from "../../client_actions/failed_message_storage.esm"; + +patch(MessageList.prototype, "mail_tracking/static/src/js/message_list.esm.js", { + setup() { + this._super(...arguments); + this.store = useStore(); + }, +}); diff --git a/mail_tracking/static/src/components/thread_view/thread_view.scss b/mail_tracking/static/src/components/thread_view/thread_view.scss new file mode 100644 index 0000000000..e527e97bd0 --- /dev/null +++ b/mail_tracking/static/src/components/thread_view/thread_view.scss @@ -0,0 +1,5 @@ +.o_ActivityThreadView { + .o_MessageList { + color: #000000; + } +} diff --git a/mail_tracking/static/src/components/thread_view/thread_view.xml b/mail_tracking/static/src/components/thread_view/thread_view.xml new file mode 100644 index 0000000000..5952603ba7 --- /dev/null +++ b/mail_tracking/static/src/components/thread_view/thread_view.xml @@ -0,0 +1,18 @@ + + + + + +
+ +
+
+
+ +
diff --git a/mail_tracking/static/src/css/failed_message.scss b/mail_tracking/static/src/css/failed_message.scss deleted file mode 100644 index 23e1772473..0000000000 --- a/mail_tracking/static/src/css/failed_message.scss +++ /dev/null @@ -1,348 +0,0 @@ -/* Copyright 2019 Alexandre Díaz - License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */ -// FIXME: More of these classes are cloned from other scss files. -.o_mail_failed_message { - &.o_field_widget { - display: block; - } - - .o_thread_date_separator.o_border_dashed { - border-bottom-style: dashed; - - &[data-toggle="collapse"] { - cursor: pointer; - - .o_chatter_failed_message_summary { - display: none; - } - - &.collapsed { - margin-bottom: 0; - transition: margin 0.8s ease 0s; - - .o_chatter_failed_message_summary { - display: inline-block; - - span { - padding: 0 5px; - border-radius: 100%; - font-size: 11px; - } - } - - i.fa-caret-down:before { - content: "\f0da"; - } - } - } - } - - .o_thread_show_more { - text-align: center; - } - - .o_mail_thread_content { - display: flex; - flex-direction: column; - min-height: 100%; - } - - .o_thread_bottom_free_space { - height: 15px; - } - - .o_thread_typing_notification_free_space { - flex-grow: 1; - } - - .o_thread_typing_notification_bar { - flex: 0, 0, 20px; - background-color: rgba($white, 0.75); - padding: 5px; - text-align: center; - color: gray("600"); - - &.o_thread_order_asc { - @include o-position-sticky($bottom: 0px); - } - - &.o_thread_order_desc { - @include o-position-sticky($top: 0px); - } - } - - .o_thread_tooltip_container { - display: inline; - position: relative; - } - - .o_thread_date_separator { - margin-top: 15px; - margin-bottom: 30px; - @include media-breakpoint-down(sm) { - margin-top: 0px; - margin-bottom: 15px; - } - border-bottom: 1px solid gray("400"); - text-align: center; - - .o_thread_date { - position: relative; - top: 10px; - margin: 0 auto; - padding: 0 10px; - font-weight: bold; - background: white; - } - } - - .o_thread_new_messages_separator { - margin-bottom: 15px; - border-bottom: solid lighten($o-brand-odoo, 15%) 1px; - text-align: right; - .o_thread_separator_label { - position: relative; - top: 8px; - padding: 0 10px; - background: white; - color: lighten($o-brand-odoo, 15%); - font-size: smaller; - } - } - - .o_thread_message { - display: flex; - padding: 4px $o-horizontal-padding; - margin-bottom: 0px; - - &.o_mail_not_discussion { - background-color: rgba(map-get($grays, "300"), 0.5); - border-bottom: 1px solid map-get($grays, "400"); - } - - .o_thread_message_sidebar { - flex: 0 0 $o-mail-thread-avatar-size; - margin-right: 10px; - margin-top: 2px; - text-align: center; - font-size: smaller; - - @include media-breakpoint-down(sm) { - margin-top: 4px; - font-size: x-small; - } - - .o_thread_message_avatar { - max-width: $o-mail-thread-avatar-size; - } - .o_thread_message_side_date { - margin-left: -5px; - } - .o_thread_message_star { - margin-right: -5px; - } - - .o_thread_message_side_date { - opacity: 0; - } - } - .o_thread_icon { - cursor: pointer; - opacity: 0; - &.fa-star { - opacity: $o-mail-thread-icon-opacity; - color: gold; - } - } - - &:hover, - &.o_thread_selected_message { - .o_thread_message_side_date { - opacity: $o-mail-thread-side-date-opacity; - } - .o_thread_icon { - opacity: $o-mail-thread-icon-opacity; - &:hover { - opacity: 1; - } - } - } - - .o_mail_redirect { - cursor: pointer; - } - - .o_thread_message_core { - flex: 1 1 auto; - min-width: 0; - max-width: 100%; - word-wrap: break-word; - > pre { - white-space: pre-wrap; - word-break: break-word; - text-align: justify; - } - - .o_mail_subject { - font-style: italic; - } - - .o_mail_notification { - font-style: italic; - color: gray; - } - - [summary~="o_mail_notification"] { - // name conflicts with channel notifications, but is odoo notification buttons to hide in chatter if present - display: none; - } - - p { - margin: 0 0 9px; // Required by the old design to override a general rule on p's - &:last-child { - margin-bottom: 0; - } - } - a { - display: inline-block; - word-break: break-all; - } - :not(.o_image_box) > img { - max-width: 100%; - height: auto; - } - - .o_mail_body_long { - display: none; - } - - .o_mail_info { - margin-bottom: 2px; - - strong { - color: $headings-color; - } - } - - .o_thread_message_star, - .o_thread_message_needaction, - .o_thread_message_reply, - .o_thread_message_email { - padding: 4px; - } - - i.o_thread_message_email { - &.o_thread_message_email_ready { - color: grey; - } - &.o_thread_message_email_exception, - &.o_thread_message_email_bounce { - color: red; - opacity: 1; - cursor: pointer; - } - } - - .o_attachments_list, - .o_attachments_previews { - &:last-child { - margin-bottom: $grid-gutter-width; - } - } - - .o_thread_tooltip_container { - display: inline; - position: relative; - } - } - } - .o_thread_title { - margin-top: 20px; - margin-bottom: 20px; - font-weight: bold; - font-size: 125%; - } - - .o_mail_no_content { - @include o-position-absolute(30%, 0, 0, 0); - text-align: center; - font-size: 115%; - } - - .o_thread_message .o_thread_message_core .o_mail_read_more { - display: block; - } - - #o_chatter_failed_message { - .o_thread_message { - .o_thread_message_sidebar { - .o_avatar_stack { - position: relative; - text-align: left; - margin-bottom: 8px; - - img { - width: 31px; - height: 31px; - } - - .o_avatar_icon { - @include o-position-absolute($right: -5px, $bottom: -5px); - width: 25px; - height: 25px; - padding: 6px 5px; - text-align: center; - line-height: 1.2; - color: white; - border-radius: 100%; - border: 2px solid white; - } - } - } - - .o_mail_info { - .o_activity_info { - vertical-align: baseline; - padding: 4px 6px; - background: theme-color("light"); - border-radius: 2px 2px 0 0; - @include o-hover-opacity(1, 1); - - &.collapsed { - @include o-hover-opacity(0.5, 1); - background: transparent; - } - } - } - - .o_thread_message_collapse .dl-horizontal.card { - display: inline-block; - margin-bottom: 0; - - dt { - max-width: 80px; - } - dd { - margin-left: 95px; - } - } - - .o_thread_message_note { - margin: 2px 0 5px; - padding: 0px; - } - .o_thread_message_warning { - margin: 2px 0 5px; - } - - .o_thread_message_tools { - .o_failed_message_link { - padding: 0 $input-btn-padding-x; - } - .o_failed_message_retry { - padding-left: 0; - } - } - } - } -} diff --git a/mail_tracking/static/src/js/failed_message/mail_failed_box.esm.js b/mail_tracking/static/src/js/failed_message/mail_failed_box.esm.js deleted file mode 100644 index 28b9c4f9ee..0000000000 --- a/mail_tracking/static/src/js/failed_message/mail_failed_box.esm.js +++ /dev/null @@ -1,57 +0,0 @@ -/** @odoo-module **/ - -import {registerMessagingComponent} from "@mail/utils/messaging_component"; -const {Component} = owl; - -export class MessageFailedBox extends Component { - _onClickTitle() { - this.chatter.toggleMessageFailedBoxVisibility(); - } - _markFailedMessageReviewed(id) { - return this.env.services.rpc({ - model: "mail.message", - method: "set_need_action_done", - args: [[id]], - }); - } - _onRetryFailedMessage(event) { - event.preventDefault(); - var messageID = $(event.currentTarget).data("message-id"); - const thread = this.chatter.thread; - var self = this; - this.env.bus.trigger("do-action", { - action: "mail.mail_resend_message_action", - options: { - additional_context: { - mail_message_to_resend: messageID, - }, - on_close: () => { - self.trigger("reload", {keepChanges: true}); - thread.refresh(); - }, - }, - }); - } - _onMarkFailedMessageReviewed(event) { - event.preventDefault(); - var messageID = $(event.currentTarget).data("message-id"); - this._markFailedMessageReviewed(messageID); - this.trigger("reload", {keepChanges: true}); - this.chatter.thread.refreshMessagefailed(); - this.chatter.thread.refresh(); - } - - /** - * @returns {Chatter} - */ - get chatter() { - return this.messaging.models["mail.chatter"].get(this.props.chatterLocalId); - } -} - -Object.assign(MessageFailedBox, { - props: {record: Object}, - template: "mail_tracking.MessageFailedBox", -}); - -registerMessagingComponent(MessageFailedBox); diff --git a/mail_tracking/static/src/js/failed_message/thread.esm.js b/mail_tracking/static/src/js/failed_message/thread.esm.js deleted file mode 100644 index 8e47f58c0c..0000000000 --- a/mail_tracking/static/src/js/failed_message/thread.esm.js +++ /dev/null @@ -1,58 +0,0 @@ -/** @odoo-module **/ - -import { - registerFieldPatchModel, - registerInstancePatchModel, -} from "@mail/model/model_core"; -import {one2many} from "@mail/model/model_field"; - -registerInstancePatchModel( - "mail.thread", - "mail_tracking/static/src/js/failed_message/thread.esm.js", - { - async refreshMessagefailed() { - var id = this.__values.id; - var model = this.__values.model; - const messagefailedData = await this.async(() => - this.env.services.rpc( - { - model: "mail.message", - method: "get_failed_messsage_info", - args: [id, model], - }, - { - shadow: true, - } - ) - ); - const messagefailed = this.messaging.models["mail.message.failed"].insert( - messagefailedData.map((messageData) => - this.messaging.models["mail.message.failed"].convertData( - messageData - ) - ) - ); - this.update({ - messagefailed: [["replace", messagefailed]], - }); - }, - - _computeFetchMessagesUrl() { - switch (this) { - case this.messaging.failedmsg: - return "/mail/failed/messages"; - } - return this._super(); - }, - } -); - -registerFieldPatchModel( - "mail.thread", - "mail_tracking/static/src/js/failed_message/thread.esm.js", - { - messagefailed: one2many("mail.message.failed", { - inverse: "thread", - }), - } -); diff --git a/mail_tracking/static/src/js/message.esm.js b/mail_tracking/static/src/js/message.esm.js deleted file mode 100644 index 413d3d46c7..0000000000 --- a/mail_tracking/static/src/js/message.esm.js +++ /dev/null @@ -1,55 +0,0 @@ -/** @odoo-module **/ - -import {Message} from "@mail/components/message/message"; -import {patch} from "web.utils"; - -patch(Message.prototype, "mail_tracking/static/src/js/message.esm.js", { - constructor() { - this._super(...arguments); - }, - _onTrackingStatusClick(event) { - var tracking_email_id = $(event.currentTarget).data("tracking"); - event.preventDefault(); - return this.env.bus.trigger("do-action", { - action: { - type: "ir.actions.act_window", - view_type: "form", - view_mode: "form", - res_model: "mail.tracking.email", - views: [[false, "form"]], - target: "new", - res_id: tracking_email_id, - }, - }); - }, - - // For discuss - _onMarkFailedMessageReviewed(event) { - event.preventDefault(); - var messageID = $(event.currentTarget).data("message-id"); - this._markFailedMessageReviewed(messageID); - window.location.reload(); - }, - _onRetryFailedMessage(event) { - event.preventDefault(); - var messageID = $(event.currentTarget).data("message-id"); - this.env.bus.trigger("do-action", { - action: "mail.mail_resend_message_action", - options: { - additional_context: { - mail_message_to_resend: messageID, - }, - on_close: () => { - window.location.reload(); - }, - }, - }); - }, - _markFailedMessageReviewed(id) { - return this.env.services.rpc({ - model: "mail.message", - method: "set_need_action_done", - args: [[id]], - }); - }, -}); diff --git a/mail_tracking/static/src/js/models/chatter.esm.js b/mail_tracking/static/src/js/models/chatter.esm.js deleted file mode 100644 index 62d92ec466..0000000000 --- a/mail_tracking/static/src/js/models/chatter.esm.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @odoo-module **/ - -import {attr} from "@mail/model/model_field"; -import {registerPatch} from "@mail/model/model_core"; - -registerPatch({ - name: "Chatter", - modelMethods: { - async refresh() { - this._super(...arguments); - this.thread.refreshMessagefailed(); - }, - toggleMessageFailedBoxVisibility() { - this.update({ - isMessageFailedBoxVisible: !this.isMessageFailedBoxVisible, - }); - }, - _onThreadIdOrThreadModelChanged() { - this._super(...arguments); - this.thread.refreshMessagefailed(); - }, - }, - fields: { - isMessageFailedBoxVisible: attr({ - default: true, - }), - }, -}); diff --git a/mail_tracking/static/src/js/models/mail_tracking.esm.js b/mail_tracking/static/src/js/models/mail_tracking.esm.js deleted file mode 100644 index 8f36bb60aa..0000000000 --- a/mail_tracking/static/src/js/models/mail_tracking.esm.js +++ /dev/null @@ -1,36 +0,0 @@ -/** @odoo-module **/ - -import {attr} from "@mail/model/model_field"; -import {registerPatch} from "@mail/model/model_core"; - -registerPatch({ - name: "Message", - modelMethods: { - convertData(data) { - const data2 = this._super(data); - if ("partner_trackings" in data) { - console.log(data.partner_trackings); - data2.partner_trackings = data.partner_trackings; - } - return data2; - }, - }, - recordMethods: { - hasPartnerTrackings() { - return _.some(this.__values.get("partner_trackings")); - }, - hasEmailCc() { - return _.some(this._emailCc); - }, - - getPartnerTrackings: function () { - if (!this.hasPartnerTrackings()) { - return []; - } - return this.__values.get("partner_trackings"); - }, - }, - fields: { - partner_trackings: attr(), - }, -}); diff --git a/mail_tracking/static/src/js/models/message.esm.js b/mail_tracking/static/src/js/models/message.esm.js deleted file mode 100644 index 8dc47cd69a..0000000000 --- a/mail_tracking/static/src/js/models/message.esm.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @odoo-module **/ - -import {attr} from "@mail/model/model_field"; -import {registerPatch} from "@mail/model/model_core"; - -registerPatch({ - name: "Message", - modelMethods: { - convertData(data) { - const data2 = this._super(data); - if ("is_failed_message" in data) { - data2.isFailed = data.is_failed_message; - } - return data2; - }, - }, - fields: { - isFailed: attr({ - default: false, - }), - }, -}); diff --git a/mail_tracking/static/src/js/models/message_failed.esm.js b/mail_tracking/static/src/js/models/message_failed.esm.js deleted file mode 100644 index 559fc789ab..0000000000 --- a/mail_tracking/static/src/js/models/message_failed.esm.js +++ /dev/null @@ -1,52 +0,0 @@ -/** @odoo-module **/ - -import {attr, many} from "@mail/model/model_field"; -import {registerModel} from "@mail/model/model_core"; - -registerModel({ - name: "MessageFailed", - modelMethods: { - /** - * @param {Object} data - * @returns {Object} - */ - convertData(data) { - const data2 = {}; - if ("author" in data) { - if (!data.author) { - data2.author = [["unlink-all"]]; - } else if (data.author) { - data2.author = data.author[1]; - data2.author_id = data.author[0]; - } - } - if ("body" in data) { - data2.body = data.body; - } - if ("date" in data) { - data2.date = data.date; - } - if ("failed_recipients" in data) { - data2.failed_recipients = data.failed_recipients; - } - if ("id" in data) { - data2.id = data.id; - } - return data2; - }, - }, - fields: { - thread: many("Thread", { - inverse: "messagefailed", - }), - body: attr(), - author: attr(), - author_id: attr(), - date: attr(), - failed_recipients: attr(), - id: attr({ - readonly: true, - required: true, - }), - }, -}); diff --git a/mail_tracking/static/src/js/models/message_view.esm.js b/mail_tracking/static/src/js/models/message_view.esm.js deleted file mode 100644 index 2c02e3acca..0000000000 --- a/mail_tracking/static/src/js/models/message_view.esm.js +++ /dev/null @@ -1,50 +0,0 @@ -/** @odoo-module **/ - -import {registerPatch} from "@mail/model/model_core"; - -registerPatch({ - name: "MessageView", - recordMethods: { - _onTrackingStatusClick(event) { - var tracking_email_id = $(event.currentTarget).data("tracking"); - event.preventDefault(); - return this.env.services.action.doAction({ - type: "ir.actions.act_window", - view_type: "form", - view_mode: "form", - res_model: "mail.tracking.email", - views: [[false, "form"]], - target: "new", - res_id: tracking_email_id, - }); - }, - _onMarkFailedMessageReviewed(event) { - event.preventDefault(); - var messageID = $(event.currentTarget).data("message-id"); - this._markFailedMessageReviewed(messageID); - window.location.reload(); - }, - _onRetryFailedMessage(event) { - event.preventDefault(); - var messageID = $(event.currentTarget).data("message-id"); - this.env.services.action.doAction({ - action: "mail.mail_resend_message_action", - options: { - additional_context: { - mail_message_to_resend: messageID, - }, - on_close: () => { - window.location.reload(); - }, - }, - }); - }, - _markFailedMessageReviewed(id) { - return this.env.services.rpc({ - model: "mail.message", - method: "set_need_action_done", - args: [[id]], - }); - }, - }, -}); diff --git a/mail_tracking/static/src/js/models/messaging_initializer.esm.js b/mail_tracking/static/src/js/models/messaging_initializer.esm.js deleted file mode 100644 index 518c57deb0..0000000000 --- a/mail_tracking/static/src/js/models/messaging_initializer.esm.js +++ /dev/null @@ -1,17 +0,0 @@ -/** @odoo-module **/ - -import {registerPatch} from "@mail/model/model_core"; - -registerPatch({ - name: "MessagingInitializer", - recordMethods: { - async _init({starred_counter = 0}) { - await this._super(...arguments); - this._initMailboxesFailed({starred_counter}); - }, - - _initMailboxesFailed({failedmsg_counter}) { - this.messaging.failedmsg.update({counter: failedmsg_counter}); - }, - }, -}); diff --git a/mail_tracking/static/src/js/models/thread_cache.esm.js b/mail_tracking/static/src/js/models/thread_cache.esm.js deleted file mode 100644 index a745f05b7b..0000000000 --- a/mail_tracking/static/src/js/models/thread_cache.esm.js +++ /dev/null @@ -1,16 +0,0 @@ -/** @odoo-module **/ - -import {registerPatch} from "@mail/model/model_core"; - -registerPatch({ - name: "ThreadCache", - recordMethods: { - _extendMessageDomain(domain) { - const thread = this.thread; - if (thread === this.env.messaging.failedmsg) { - return domain.concat([["is_failed_message", "=", true]]); - } - return this._super(...arguments); - }, - }, -}); diff --git a/mail_tracking/static/src/models/chatter.esm.js b/mail_tracking/static/src/models/chatter.esm.js new file mode 100644 index 0000000000..99c7015d48 --- /dev/null +++ b/mail_tracking/static/src/models/chatter.esm.js @@ -0,0 +1,17 @@ +/** @odoo-module **/ + +import {registerPatch} from "@mail/model/model_core"; + +registerPatch({ + name: "Chatter", + recordMethods: { + async refresh() { + this._super(...arguments); + if (this.thread) this.thread.refreshMessagefailed(); + }, + _onThreadIdOrThreadModelChanged() { + this._super(...arguments); + if (this.thread) this.thread.refreshMessagefailed(); + }, + }, +}); diff --git a/mail_tracking/static/src/js/models/discuss_sidebar_mailbox_view.esm.js b/mail_tracking/static/src/models/discuss_sidebar_mailbox_view.esm.js similarity index 51% rename from mail_tracking/static/src/js/models/discuss_sidebar_mailbox_view.esm.js rename to mail_tracking/static/src/models/discuss_sidebar_mailbox_view.esm.js index 7a00b9df3e..2eae4571ed 100644 --- a/mail_tracking/static/src/js/models/discuss_sidebar_mailbox_view.esm.js +++ b/mail_tracking/static/src/models/discuss_sidebar_mailbox_view.esm.js @@ -5,14 +5,20 @@ import {registerPatch} from "@mail/model/model_core"; registerPatch({ name: "DiscussSidebarMailboxView", + recordMethods: { + _getNonReviewedFailedMessages(messages, reviewedMessageIds) { + if (!messages.length) return []; + return messages.filter((message) => !reviewedMessageIds.has(message.id)); + }, + }, fields: { - discussViewOwnerAsFailedmsg: one("DiscussView", { + discussViewOwnerAsFailedMessage: one("DiscussView", { identifying: true, - inverse: "failedmsgView", + inverse: "failedMessageView", }), mailbox: { compute() { - if (this.discussViewOwnerAsFailedmsg) { + if (this.discussViewOwnerAsFailedMessage) { return this.messaging.failedmsg; } return this._super(); diff --git a/mail_tracking/static/src/js/models/discuss_view.esm.js b/mail_tracking/static/src/models/discuss_view.esm.js similarity index 65% rename from mail_tracking/static/src/js/models/discuss_view.esm.js rename to mail_tracking/static/src/models/discuss_view.esm.js index 66276cd8f5..e351270a25 100644 --- a/mail_tracking/static/src/js/models/discuss_view.esm.js +++ b/mail_tracking/static/src/models/discuss_view.esm.js @@ -6,9 +6,9 @@ import {registerPatch} from "@mail/model/model_core"; registerPatch({ name: "DiscussView", fields: { - failedmsgView: one("DiscussSidebarMailboxView", { + failedMessageView: one("DiscussSidebarMailboxView", { default: {}, - inverse: "discussViewOwnerAsFailedmsg", + inverse: "discussViewOwnerAsFailedMessage", }), }, }); diff --git a/mail_tracking/static/src/js/models/mailbox.esm.js b/mail_tracking/static/src/models/mailbox.esm.js similarity index 82% rename from mail_tracking/static/src/js/models/mailbox.esm.js rename to mail_tracking/static/src/models/mailbox.esm.js index ac2f979566..aa4d1bd81c 100644 --- a/mail_tracking/static/src/js/models/mailbox.esm.js +++ b/mail_tracking/static/src/models/mailbox.esm.js @@ -1,6 +1,5 @@ /** @odoo-module **/ -import {clear} from "@mail/model/model_field_command"; import {one} from "@mail/model/model_field"; import {registerPatch} from "@mail/model/model_core"; @@ -11,12 +10,12 @@ registerPatch({ compute() { switch (this) { case this.messaging.failedmsg: - return "/mail/failedmsg/messages"; + return "/mail/failed/messages"; } return this._super(); }, }, - messagingAsFailedmsg: one("Messaging", { + messagingAsFailed: one("Messaging", { identifying: true, inverse: "failedmsg", }), @@ -24,7 +23,7 @@ registerPatch({ compute() { switch (this) { case this.messaging.failedmsg: - return this.env._t("Failedmsg"); + return this.env._t("Failed"); } return this._super(); }, @@ -33,7 +32,7 @@ registerPatch({ compute() { switch (this) { case this.messaging.failedmsg: - return 4; + return 3; } return this._super(); }, @@ -45,10 +44,9 @@ registerPatch({ case this.messaging.failedmsg: return "failedmsg"; } - return this._super(); })(); if (!threadId) { - return clear(); + return this._super(); } return { id: threadId, diff --git a/mail_tracking/static/src/models/message.esm.js b/mail_tracking/static/src/models/message.esm.js new file mode 100644 index 0000000000..9684e1a44d --- /dev/null +++ b/mail_tracking/static/src/models/message.esm.js @@ -0,0 +1,64 @@ +/** @odoo-module **/ + +import {attr, one} from "@mail/model/model_field"; +import {registerPatch} from "@mail/model/model_core"; + +registerPatch({ + name: "Message", + modelMethods: { + convertData(data) { + const data2 = this._super(data); + if ("partner_trackings" in data) { + data2.partner_trackings = data.partner_trackings; + } + if ("is_failed_message" in data) { + data2.isFailed = data.is_failed_message; + } + if ("failed_recipients" in data) { + data2.failedRecipients = data.failed_recipients; + } + if ("is_failed_chatter_message" in data) { + data2.isFailedChatterMessage = data.is_failed_chatter_message; + } + return data2; + }, + }, + recordMethods: { + hasPartnerTrackings() { + return _.some(this.__values.get("partner_trackings")); + }, + + hasEmailCc() { + return _.some(this._emailCc); + }, + + getPartnerTrackings: function () { + if (!this.hasPartnerTrackings()) { + return []; + } + return this.__values.get("partner_trackings"); + }, + }, + fields: { + partner_trackings: attr(), + threads: { + compute() { + const threads = this._super(); + if (this.isFailed && this.messaging.failedmsg) { + threads.push(this.messaging.failedmsg.thread); + } + return threads; + }, + }, + messagingFailedmsg: one("Mailbox", { + related: "messaging.failedmsg", + }), + isFailed: attr({ + default: false, + }), + failedRecipients: attr(), + isFailedChatterMessage: attr({ + default: false, + }), + }, +}); diff --git a/mail_tracking/static/src/models/message_list_view.esm.js b/mail_tracking/static/src/models/message_list_view.esm.js new file mode 100644 index 0000000000..32d41f204f --- /dev/null +++ b/mail_tracking/static/src/models/message_list_view.esm.js @@ -0,0 +1,33 @@ +/** @odoo-module **/ + +import {attr, many} from "@mail/model/model_field"; +import {registerPatch} from "@mail/model/model_core"; + +registerPatch({ + name: "MessageListView", + recordMethods: { + toggleMessageFailedBoxVisibility() { + this.update({ + isMessageFailedBoxVisible: !this.isMessageFailedBoxVisible, + }); + }, + _getNonReviewedFailedMessageItems(messageItems, reviewedMessageIds) { + if (!messageItems.length) return []; + return messageItems.filter( + (item) => !reviewedMessageIds.has(item.message.id) + ); + }, + }, + fields: { + isMessageFailedBoxVisible: attr({ + default: true, + }), + messageFailedListViewItems: many("MessageListViewItem", { + compute() { + return this.messageListViewItems.filter( + (messageListViewItem) => messageListViewItem.isFailedChatterMessage + ); + }, + }), + }, +}); diff --git a/mail_tracking/static/src/models/message_list_view_item.esm.js b/mail_tracking/static/src/models/message_list_view_item.esm.js new file mode 100644 index 0000000000..b6bf3f647f --- /dev/null +++ b/mail_tracking/static/src/models/message_list_view_item.esm.js @@ -0,0 +1,15 @@ +/** @odoo-module **/ + +import {attr} from "@mail/model/model_field"; +import {registerPatch} from "@mail/model/model_core"; + +registerPatch({ + name: "MessageListViewItem", + fields: { + isFailedChatterMessage: attr({ + compute() { + return this.message.isFailedChatterMessage; + }, + }), + }, +}); diff --git a/mail_tracking/static/src/models/message_view.esm.js b/mail_tracking/static/src/models/message_view.esm.js new file mode 100644 index 0000000000..5173b965ff --- /dev/null +++ b/mail_tracking/static/src/models/message_view.esm.js @@ -0,0 +1,12 @@ +/** @odoo-module **/ + +import {registerPatch} from "@mail/model/model_core"; + +registerPatch({ + name: "MessageView", + recordMethods: { + doNothing() { + return true; + }, + }, +}); diff --git a/mail_tracking/static/src/js/models/messaging.esm.js b/mail_tracking/static/src/models/messaging.esm.js similarity index 85% rename from mail_tracking/static/src/js/models/messaging.esm.js rename to mail_tracking/static/src/models/messaging.esm.js index dc57c9921f..714d4ab213 100644 --- a/mail_tracking/static/src/js/models/messaging.esm.js +++ b/mail_tracking/static/src/models/messaging.esm.js @@ -8,7 +8,7 @@ registerPatch({ fields: { failedmsg: one("Mailbox", { default: {}, - inverse: "messagingAsFailedmsg", + inverse: "messagingAsFailed", }), }, }); diff --git a/mail_tracking/static/src/models/messaging_initializer.esm.js b/mail_tracking/static/src/models/messaging_initializer.esm.js new file mode 100644 index 0000000000..7aea520823 --- /dev/null +++ b/mail_tracking/static/src/models/messaging_initializer.esm.js @@ -0,0 +1,17 @@ +/** @odoo-module **/ + +import {registerPatch} from "@mail/model/model_core"; + +registerPatch({ + name: "MessagingInitializer", + recordMethods: { + async _init({failed_counter = 0}) { + await this._super(...arguments); + this._initFailedMailboxes(failed_counter); + }, + + _initFailedMailboxes(failed_counter) { + this.messaging.failedmsg.update({counter: failed_counter}); + }, + }, +}); diff --git a/mail_tracking/static/src/js/models/thread.esm.js b/mail_tracking/static/src/models/thread.esm.js similarity index 62% rename from mail_tracking/static/src/js/models/thread.esm.js rename to mail_tracking/static/src/models/thread.esm.js index 3e0ab29fad..a6a3d9a816 100644 --- a/mail_tracking/static/src/js/models/thread.esm.js +++ b/mail_tracking/static/src/models/thread.esm.js @@ -1,6 +1,5 @@ /** @odoo-module **/ -import {one} from "@mail/model/model_field"; import {registerPatch} from "@mail/model/model_core"; registerPatch({ @@ -19,19 +18,15 @@ registerPatch({ shadow: true, } ); - const messagefailed = this.messaging.models.MessageFailed.insert( + /* Create failed Message records; these will be updated when fetching + their usual Message data and assigned to their respective threads. */ + this.messaging.models.Message.insert( messagefailedData.map((messageData) => - this.messaging.models.MessageFailed.convertData(messageData) + this.messaging.models.Message.convertData( + Object.assign(messageData, {is_failed_chatter_message: true}) + ) ) ); - this.update({ - messagefailed: [["replace", messagefailed]], - }); }, }, - fields: { - messagefailed: one("MessageFailed", { - inverse: "thread", - }), - }, }); diff --git a/mail_tracking/static/src/xml/failed_message/common.xml b/mail_tracking/static/src/xml/failed_message/common.xml deleted file mode 100644 index 5aeeb81708..0000000000 --- a/mail_tracking/static/src/xml/failed_message/common.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - Set as Reviewed - - - Retry - - - - - diff --git a/mail_tracking/static/src/xml/failed_message/discuss.xml b/mail_tracking/static/src/xml/failed_message/discuss.xml deleted file mode 100644 index 364ebfad96..0000000000 --- a/mail_tracking/static/src/xml/failed_message/discuss.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - -
- - - - - - - - - - - - - -
- No failed messages -
- Failed messages will be appeared here. -
-
-
- - - - - - - - Set as Reviewed - - - - Retry - - - - - - diff --git a/mail_tracking/static/src/xml/failed_message/thread.xml b/mail_tracking/static/src/xml/failed_message/thread.xml deleted file mode 100644 index 702cb221a0..0000000000 --- a/mail_tracking/static/src/xml/failed_message/thread.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - -
- - -
- - - Failed messages - - - - - - - - - - -
-
- -
- -
- -
-
- - - -
- -
-
-
-
-
-
- -
- -
- -
-
- - - Set as Reviewed - - - Retry - - -
-
- Failed Recipients: - - - - - - - - - -
-
- -
-
-
-
-
-
-
-
-
-
- - - - - - - -
diff --git a/mail_tracking/static/src/xml/mail_tracking.xml b/mail_tracking/static/src/xml/mail_tracking.xml deleted file mode 100644 index c542f45c93..0000000000 --- a/mail_tracking/static/src/xml/mail_tracking.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - diff --git a/mail_tracking/tests/test_mail_tracking.py b/mail_tracking/tests/test_mail_tracking.py index f43b5663ae..601b33d070 100644 --- a/mail_tracking/tests/test_mail_tracking.py +++ b/mail_tracking/tests/test_mail_tracking.py @@ -3,15 +3,16 @@ import base64 import time -from unittest import mock +from unittest.mock import patch -import psycopg2 -import psycopg2.errorcodes +from werkzeug.exceptions import BadRequest from odoo import http +from odoo.fields import Command from odoo.tests.common import TransactionCase from odoo.tools.misc import mute_logger +from ..controllers.discuss import MailTrackingDiscussController from ..controllers.main import BLANK, MailTrackingController mock_send_email = "odoo.addons.base.models.ir_mail_server." "IrMailServer.send_email" @@ -51,6 +52,10 @@ def setUp(self, *args, **kwargs): ), }, ) + for _ in http._generate_routing_rules( + ["mail", "mail_tracking"], nodb_only=False + ): + pass def tearDown(self, *args, **kwargs): http.request = self.last_request @@ -84,7 +89,7 @@ def test_message_post(self): "message_type": "comment", "model": "res.partner", "res_id": self.recipient.id, - "partner_ids": [(4, self.recipient.id)], + "partner_ids": [Command.link(self.recipient.id)], "body": "

This is a test message

", } ) @@ -135,7 +140,7 @@ def test_message_post_partner_no_email(self): "message_type": "comment", "model": "res.partner", "res_id": self.recipient.id, - "partner_ids": [(4, self.recipient.id)], + "partner_ids": [Command.link(self.recipient.id)], "body": "

This is a test message

", } ) @@ -201,7 +206,7 @@ def test_email_cc(self): "message_type": "comment", "model": "res.partner", "res_id": self.recipient.id, - "partner_ids": [(4, self.recipient.id)], + "partner_ids": [Command.link(self.recipient.id)], "email_cc": "Dominique Pinon , sender@example.com" ", recipient@example.com", "body": "

This is another test message

", @@ -255,7 +260,7 @@ def test_email_to(self): "message_type": "comment", "model": "res.partner", "res_id": self.recipient.id, - "partner_ids": [(4, self.recipient.id)], + "partner_ids": [Command.link(self.recipient.id)], "email_to": "Dominique Pinon " ", sender@example.com, recipient@example.com" ", TheCatchall@test.com", @@ -318,7 +323,7 @@ def test_resend_failed_message(self): "message_type": "comment", "model": "res.partner", "res_id": self.recipient.id, - "partner_ids": [(4, self.recipient.id)], + "partner_ids": [Command.link(self.recipient.id)], "body": "

This is a test message

", } ) @@ -364,6 +369,7 @@ def mail_send(self, recipient): ) return mail, tracking_email + @mute_logger("odoo.addons.mail_tracking.controllers.main") def test_mail_send(self): controller = MailTrackingController() db = self.env.cr.dbname @@ -371,7 +377,7 @@ def test_mail_send(self): mail, tracking = self.mail_send(self.recipient.email) self.assertEqual(mail.email_to, tracking.recipient) self.assertEqual(mail.email_from, tracking.sender) - with mock.patch("odoo.http.db_filter") as mock_client: + with patch("odoo.http.db_filter") as mock_client: mock_client.return_value = True res = controller.mail_tracking_open(db, tracking.id, tracking.token) self.assertEqual(image, res.response[0]) @@ -383,10 +389,14 @@ def test_mail_send(self): # Two events again because no tracking_email_id found for False self.assertEqual(2, len(tracking.tracking_event_ids)) + @mute_logger("odoo.addons.mail_tracking.controllers.main") def test_mail_tracking_open(self): + def mock_error_function(*args, **kwargs): + raise Exception() + controller = MailTrackingController() db = self.env.cr.dbname - with mock.patch("odoo.http.db_filter") as mock_client: + with patch("odoo.http.db_filter") as mock_client: mock_client.return_value = True mail, tracking = self.mail_send(self.recipient.email) # Tracking is in sent or delivered state. But no token give. @@ -416,6 +426,30 @@ def test_mail_tracking_open(self): # Generates tracking event controller.mail_tracking_open(db, tracking.id, False) self.assertEqual(2, len(tracking.tracking_event_ids)) + # Purposely trigger an error during mail_tracking_open + # flow (to increase coverage) + with patch( + "odoo.addons.mail_tracking.models.mail_tracking_email.MailTrackingEmail.search", + wraps=mock_error_function, + ): + controller.mail_tracking_open(db, tracking.id, False) + # Purposely trigger an error during db_env (to increase coverage) + with patch("odoo.http.db_filter") as mock_client, self.assertRaises(BadRequest): + mock_client.return_value = False + controller.mail_tracking_open(db, tracking.id, False) + + def test_db_env_no_cr(self): + http.request.cr = None + db = self.env.cr.dbname + controller = MailTrackingController() + # Cast Cursor to Mock object to avoid raising 'Cursor not closed explicitly' log + with patch("odoo.sql_db.db_connect"), patch( + "odoo.http.db_filter" + ) as mock_client: + mock_client.return_value = True + mail, tracking = self.mail_send(self.recipient.email) + response = controller.mail_tracking_open(db, tracking.id, False) + self.assertEqual(response.status_code, 200) def test_concurrent_open(self): mail, tracking = self.mail_send(self.recipient.email) @@ -476,7 +510,7 @@ def test_concurrent_click(self): @mute_logger("odoo.addons.mail.models.mail_mail") def test_smtp_error(self): - with mock.patch(mock_send_email) as mock_func: + with patch(mock_send_email) as mock_func: mock_func.side_effect = Warning("Test error") mail, tracking = self.mail_send(self.recipient.email) self.assertEqual("error", tracking.state) @@ -573,22 +607,10 @@ def test_recordset_email_score(self): trackings |= tracking self.assertEqual(100.0, trackings.email_score()) - def test_db(self): - db = self.env.cr.dbname - controller = MailTrackingController() - with mock.patch("odoo.http.db_filter") as mock_client: - mock_client.return_value = True - with self.assertRaises(psycopg2.OperationalError): - controller.mail_tracking_event("not_found_db") - none = controller.mail_tracking_event(db) - self.assertEqual(b"NONE", none.response[0]) - none = controller.mail_tracking_event(db, "open") - self.assertEqual(b"NONE", none.response[0]) - def test_bounce_tracking_event_created(self): mail, tracking = self.mail_send(self.recipient.email) message = self.env.ref("mail.mail_message_channel_1_1") - message.mail_tracking_ids = [(4, tracking.id, False)] + message.mail_tracking_ids = [Command.link(tracking.id)] mail.mail_message_id = message message_dict = { "bounced_email": "test@test.net", @@ -628,7 +650,7 @@ def assert_tracking_tag_side_effect(*args, **kwargs): msg = "data-odoo-tracking-email found" raise AssertionError(msg) - with mock.patch(mock_send_email) as mock_func: + with patch(mock_send_email) as mock_func: mock_func.side_effect = assert_tracking_tag_side_effect self.env["ir.config_parameter"].set_param( "mail_tracking.tracking_img_disabled", False @@ -647,3 +669,38 @@ def assert_tracking_tag_side_effect(*args, **kwargs): self.assertEqual( "data-odoo-tracking-email not found", tracking.error_description ) + + def test_mail_init_messaging(self): + def mock_json_response(*args, **kwargs): + return {"expected_result": True} + + controller = MailTrackingDiscussController() + # This is non-functional test to increase coverage + with patch( + "odoo.addons.mail.controllers.discuss.DiscussController.mail_init_messaging", + wraps=mock_json_response, + ): + res = controller.mail_init_messaging() + self.assertTrue(res["expected_result"]) + + def test_discuss_failed_messages(self): + def mock_json_response(*args, **kwargs): + return {"expected_result": True} + + def mock_message_fetch(*args, **kwargs): + return self.env["mail.message"] + + controller = MailTrackingDiscussController() + # This is non-functional test to increase coverage + with patch( + "odoo.addons.mail_tracking.models.mail_message.MailMessage.message_format", + wraps=mock_json_response, + ), patch( + "odoo.addons.mail.models.mail_message.Message._message_fetch", + wraps=mock_message_fetch, + ): + res = controller.discuss_failed_messages() + self.assertTrue(res["expected_result"]) + + def test_unlink_mail_alias(self): + self.env["ir.config_parameter"].search([], limit=1).unlink() diff --git a/mail_tracking/views/mail_tracking_email_view.xml b/mail_tracking/views/mail_tracking_email_view.xml index 009404773d..247ff0d8a1 100644 --- a/mail_tracking/views/mail_tracking_email_view.xml +++ b/mail_tracking/views/mail_tracking_email_view.xml @@ -22,7 +22,7 @@ - +