From 9bbb276c42ac0733e98f28f1a2cbccb072807ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 5 Jan 2023 14:03:18 +0000 Subject: [PATCH] [REF] mail: cleanup message_{notify, log} wrappers RATIONALE Purpose of this commit is to cleanup main post helpers and have a more easy and understandable way of calling them. SPECIFICATIONS Update methods parameters to look more like 'message_post' definition. Add docstrings to explain parameter usage. Cleanup some parameter we do not want. Add a api.returns on message_notify to wrap the value in case of external call, as this method is public, like message_post. Task-2710804 (Mail: Clean MailThread Posting API) Part-of: odoo/odoo#99482 --- addons/mail/models/mail_thread.py | 62 ++++++++++++++----- .../tests/test_mail_thread_internals.py | 30 ++++++++- 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index d9b0498e65f..e76eb1fe214 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -2281,10 +2281,12 @@ class MailThread(models.AbstractModel): ) return messages + @api.returns('mail.message', lambda value: value.id) def message_notify(self, *, - partner_ids=False, parent_id=False, model=False, res_id=False, - author_id=None, email_from=None, body='', subject=False, - subtype_xmlid=None, + body='', subject=False, + author_id=None, email_from=None, + model=False, res_id=False, + subtype_xmlid=None, subtype_id=False, partner_ids=False, **kwargs): """ Shortcut allowing to notify partners of messages that should not be displayed on a document. It pushes notifications on inbox or by email @@ -2294,6 +2296,29 @@ class MailThread(models.AbstractModel): * subtype_id: if not given, fallback on ``note`` to be consistent with what message_post does; + :param str body: body of the message, usually raw HTML that will + be sanitized + :param str subject: subject of the message + :param int author_id: optional ID of partner record being the author. See + ``_message_compute_author`` that uses it to make email_from / author_id coherent; + :param str email_from: from address of the author. See ``_message_compute_author`` + that uses it to make email_from / author_id coherent; + :param str model: when invoked on MailThread directly, this method + allows to push a notification on a given record (allows to notify + on not thread-enabled records); + :param int res_id: defines the record in combination with model; + :param str subtype_xmlid: optional xml id of a mail.message.subtype to + fetch, will force value of subtype_id; + :param int subtype_id: subtype_id of the message, used mainly for followers + notification mechanism; + :param list(int) partner_ids: partner_ids to notify in addition to partners + computed based on subtype / followers matching; + + Extra keyword arguments will be used either + * as default column values for the new mail.message record if they match + mail.message fields; + * propagated to notification methods if not; + :return: posted mail.message records """ if self: @@ -2305,7 +2330,7 @@ class MailThread(models.AbstractModel): # preliminary value safety check self._raise_for_invalid_parameters( set(kwargs.keys()), - forbidden_names={'message_id', 'message_type'} + forbidden_names={'message_id', 'message_type', 'parent_id'} ) if not tools.is_list_of(partner_ids, int): raise ValueError( @@ -2325,6 +2350,11 @@ class MailThread(models.AbstractModel): if not model or not res_id: model, res_id = False, False + if subtype_xmlid: + subtype_id = self.env['ir.model.data']._xmlid_to_res_id(subtype_xmlid) + if not subtype_id: + subtype_id = self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note') + msg_values = { # author 'author_id': author_id, @@ -2337,25 +2367,21 @@ class MailThread(models.AbstractModel): 'body': body, 'is_internal': True, 'message_type': 'user_notification', - 'parent_id': parent_id, 'subject': subject, + 'subtype_id': subtype_id, # recipients 'message_id': tools.generate_tracking_message_id('message-notify'), 'partner_ids': partner_ids, + # notification + 'email_add_signature': True, } msg_values.update(msg_kwargs) # add default-like values afterwards, to avoid useless queries - if subtype_xmlid: - msg_values['subtype_id'] = self.env['ir.model.data']._xmlid_to_res_id(subtype_xmlid) - elif 'subtype_id' not in msg_values: - msg_values['subtype_id'] = self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note') if 'reply_to' not in msg_values: msg_values['reply_to'] = self._notify_get_reply_to(default=email_from)[self.id if self else False] - if 'email_add_signature' not in msg_values: - msg_values['email_add_signature'] = True new_message = self._message_create([msg_values]) - self._notify_thread(new_message, msg_values, **notif_kwargs) + self._fallback_lang()._notify_thread(new_message, msg_values, **notif_kwargs) return new_message def _message_log_with_view(self, view_ref, render_values=None, @@ -2391,7 +2417,9 @@ class MailThread(models.AbstractModel): **kwargs ) - def _message_log(self, *, body='', author_id=None, email_from=None, subject=False, + def _message_log(self, *, + body='', subject=False, + author_id=None, email_from=None, message_type='notification', attachment_ids=False, tracking_value_ids=False): """ Shortcut allowing to post note on a document. See ``_message_log_batch`` @@ -2399,12 +2427,14 @@ class MailThread(models.AbstractModel): self.ensure_one() return self._message_log_batch( - {self.id: body}, author_id=author_id, email_from=email_from, - subject=subject, message_type=message_type, + {self.id: body}, subject=subject, + author_id=author_id, email_from=email_from, + message_type=message_type, attachment_ids=attachment_ids, tracking_value_ids=tracking_value_ids ) - def _message_log_batch(self, bodies, author_id=None, email_from=None, subject=False, + def _message_log_batch(self, bodies, subject=False, + author_id=None, email_from=None, message_type='notification', attachment_ids=False, tracking_value_ids=False): """ Shortcut allowing to post notes on a batch of documents. It does not diff --git a/addons/test_mail/tests/test_mail_thread_internals.py b/addons/test_mail/tests/test_mail_thread_internals.py index f7bb3470d45..56122681bac 100644 --- a/addons/test_mail/tests/test_mail_thread_internals.py +++ b/addons/test_mail/tests/test_mail_thread_internals.py @@ -443,6 +443,8 @@ class TestNoThread(TestMailCommon, TestRecipients): @users('employee') def test_message_notify(self): + """ Test notifying using model / res_id linking to a model not being + mail.thread enabled. """ test_record = self.env['mail.test.nothread'].create({ 'customer_id': self.partner_1.id, 'name': 'Not A Thread', @@ -451,6 +453,7 @@ class TestNoThread(TestMailCommon, TestRecipients): 'content': 'Hello Paulo', 'email_values': { 'reply_to': self.company_admin.catchall_formatted, + 'subject': 'Test Notify', }, 'message_type': 'user_notification', 'notif': [{ @@ -465,7 +468,32 @@ class TestNoThread(TestMailCommon, TestRecipients): _message = self.env['mail.thread'].message_notify( body='

Hello Paulo

', model=test_record._name, + partner_ids=self.partner_2.ids, res_id=test_record.id, subject='Test Notify', - partner_ids=self.partner_2.ids + ) + + @users('employee') + def test_message_notify_norecord(self): + """ Test notifying on no record, just using the abstract model itself. """ + with self.assertPostNotifications([{ + 'content': 'Hello Paulo', + 'email_values': { + 'reply_to': self.company_admin.catchall_formatted, + 'subject': 'Test Notify', + }, + 'message_type': 'user_notification', + 'notif': [{ + 'check_send': True, + 'is_read': True, + 'partner': self.partner_2, + 'status': 'sent', + 'type': 'email', + }], + 'subtype': 'mail.mt_note', + }]): + _message = self.env['mail.thread'].message_notify( + body='

Hello Paulo

', + partner_ids=self.partner_2.ids, + subject='Test Notify', )