From 1efeffd2977885aff22ec9c2564c0e8d53de855a Mon Sep 17 00:00:00 2001 From: Jairo Llopis Date: Thu, 8 Jul 2021 10:12:41 +0000 Subject: [PATCH] [FW][IMP] test_mail: test models with type do not mess with attachment types Purpose of this commit is to highlight an issue that may happens easily with `crm` that is made generic here within `test_mail`. `crm` alters the context when creating a new record adding in this case `default_type` to it][1]. The returned record contains that altered context. his results in other records created from it trying to assign that same default value for `type`. This is a very common name for fields, and happens to exist in `ir.attachment` too. If you create an alias for incoming leads in your DB with default values `{"type": "lead"}` (something very common) and then an email comes to that alias that contains an inlined base64 image, the attachment creation process would simply fail. Obtained error is ``ValueError: Wrong value for ir.attachment.type: 'lead'`` . [1]: https://github.com/odoo/odoo/blob/272602193f5647f7f2270ed6ec68777625a139dd/addons/crm/models/crm_lead.py#L310-L311 X-original-commit: 99434b2e8528c10fcc9cb6860765e0ddcaa364c8 Part-of: odoo/odoo#77005 Co-authored-by: Thibault Delavallee --- addons/mail/tests/common.py | 14 ++++-- addons/test_mail/data/test_mail_data.py | 44 +++++++++++++++++ addons/test_mail/models/__init__.py | 3 +- .../models/test_mail_corner_case_models.py | 22 +++++++++ addons/test_mail/security/ir.model.access.csv | 2 + addons/test_mail/tests/test_mail_gateway.py | 49 +++++++++++++++++++ 6 files changed, 129 insertions(+), 5 deletions(-) diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py index a2bd6db544a..67883fdc223 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -109,20 +109,26 @@ class MockEmail(common.BaseCase): def format(self, template, to='groups@example.com, other@gmail.com', subject='Frogs', email_from='Sylvie Lelitre ', return_path='', cc='', - extra='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>'): + extra='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>', + **kwargs): return template.format( subject=subject, to=to, cc=cc, email_from=email_from, return_path=return_path, - extra=extra, msg_id=msg_id) + extra=extra, msg_id=msg_id, + **kwargs) def format_and_process(self, template, email_from, to, subject='Frogs', cc='', return_path='', extra='', msg_id=False, - model=None, target_model='mail.test.gateway', target_field='name'): + model=None, target_model='mail.test.gateway', target_field='name', + **kwargs): self.assertFalse(self.env[target_model].search([(target_field, '=', subject)])) if not msg_id: msg_id = "<%.7f-test@iron.sky>" % (time.time()) - mail = self.format(template, to=to, subject=subject, cc=cc, return_path=return_path, extra=extra, email_from=email_from, msg_id=msg_id) + mail = self.format(template, to=to, subject=subject, cc=cc, + return_path=return_path, extra=extra, + email_from=email_from, msg_id=msg_id, + **kwargs) self.env['mail.thread'].message_process(model, mail) return self.env[target_model].search([(target_field, '=', subject)]) diff --git a/addons/test_mail/data/test_mail_data.py b/addons/test_mail/data/test_mail_data.py index c7fd5cb853e..81a8f456d7a 100644 --- a/addons/test_mail/data/test_mail_data.py +++ b/addons/test_mail/data/test_mail_data.py @@ -43,6 +43,50 @@ Content-Transfer-Encoding: quoted-printable ------=_Part_4200734_24778174.1344608186754-- """ +MAIL_TEMPLATE_EXTRA_HTML = """Return-Path: +To: {to} +cc: {cc} +Received: by mail1.openerp.com (Postfix, from userid 10002) + id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST) +From: {email_from} +Subject: {subject} +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_Part_4200734_24778174.1344608186754" +Date: Fri, 10 Aug 2012 14:16:26 +0000 +Message-ID: {msg_id} +{extra} +------=_Part_4200734_24778174.1344608186754 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + +Please call me as soon as possible this afternoon! + +-- +Sylvie +------=_Part_4200734_24778174.1344608186754 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + + + =20 + + =20 + =20 + +

Please call me as soon as possible this afternoon!

+ {extra_html} + +

--
+ Sylvie +

+ + +------=_Part_4200734_24778174.1344608186754-- +""" + + MAIL_TEMPLATE_PLAINTEXT = """Return-Path: To: {to} Received: by mail1.openerp.com (Postfix, from userid 10002) diff --git a/addons/test_mail/models/__init__.py b/addons/test_mail/models/__init__.py index 0f5cea0a294..64cc5bb37b9 100644 --- a/addons/test_mail/models/__init__.py +++ b/addons/test_mail/models/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import test_mail_models from . import test_mail_corner_case_models +from . import test_mail_models from . import test_mail_thread_models diff --git a/addons/test_mail/models/test_mail_corner_case_models.py b/addons/test_mail/models/test_mail_corner_case_models.py index c540676d497..8272a559d17 100644 --- a/addons/test_mail/models/test_mail_corner_case_models.py +++ b/addons/test_mail/models/test_mail_corner_case_models.py @@ -32,6 +32,28 @@ class MailPerformanceTracking(models.Model): field_2 = fields.Char(tracking=True) +class MailTestFieldType(models.Model): + """ Test default values, notably type, messing through models during gateway + processing (i.e. lead.type versus attachment.type). """ + _description = 'Test Field Type' + _name = 'mail.test.field.type' + _inherit = ['mail.thread'] + + name = fields.Char() + email_from = fields.Char() + datetime = fields.Datetime(default=fields.Datetime.now) + customer_id = fields.Many2one('res.partner', 'Customer') + type = fields.Selection([('first', 'First'), ('second', 'Second')]) + user_id = fields.Many2one('res.users', 'Responsible', tracking=True) + + @api.model_create_multi + def create(self, vals_list): + # Emulate an addon that alters the creation context, such as `crm` + if not self._context.get('default_type'): + self = self.with_context(default_type='first') + return super(MailTestFieldType, self).create(vals_list) + + class MailTestLang(models.Model): """ A simple chatter model with lang-based capabilities, allowing to test translations. """ diff --git a/addons/test_mail/security/ir.model.access.csv b/addons/test_mail/security/ir.model.access.csv index e5feacb7a54..9c4a96ae8ba 100644 --- a/addons/test_mail/security/ir.model.access.csv +++ b/addons/test_mail/security/ir.model.access.csv @@ -9,6 +9,8 @@ access_mail_test_track_portal,mail.test.track.portal,model_mail_test_track,base. access_mail_test_track_user,mail.test.track.user.employee,model_mail_test_track,base.group_user,1,1,1,1 access_mail_test_activity_portal,mail.test.activity.portal,model_mail_test_activity,base.group_portal,1,0,0,0 access_mail_test_activity_user,mail.test.activity.user,model_mail_test_activity,base.group_user,1,1,1,1 +access_mail_test_field_type_portal,mail.test.field.type.portal,model_mail_test_field_type,base.group_portal,0,0,0,0 +access_mail_test_field_type_user,mail.test.field.type.user,model_mail_test_field_type,base.group_user,1,1,1,1 access_mail_test_ticket_portal,mail.test.ticket.portal,model_mail_test_ticket,base.group_portal,0,0,0,0 access_mail_test_ticket_user,mail.test.ticket.user,model_mail_test_ticket,base.group_user,1,1,1,1 access_mail_test_composer_mixin_all,mail.test.composer.mixin.all,model_mail_test_composer_mixin,,0,0,0,0 diff --git a/addons/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index d58e57e10d1..aff9f63bf71 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -1140,6 +1140,55 @@ class TestMailgateway(TestMailCommon): self.assertFalse(incoming_msg.parent_id) self.assertTrue(incoming_msg.res_id == res_test.id) + # -------------------------------------------------- + # Gateway / Record synchronization + # -------------------------------------------------- + + @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') + def test_gateway_values_base64_image(self): + """New record with mail that contains base64 inline image.""" + target_model = "mail.test.field.type" + alias = self.env["mail.alias"].create({ + "alias_name": "base64-lover", + "alias_model_id": self.env["ir.model"]._get(target_model).id, + "alias_defaults": "{}", + "alias_contact": "everyone", + }) + record = self.format_and_process( + test_mail_data.MAIL_TEMPLATE_EXTRA_HTML, self.email_from, + '%s@%s' % (alias.alias_name, self.alias_catchall), + subject='base64 image to alias', + target_model=target_model, + extra_html='', + ) + self.assertEqual(record.type, "first") + self.assertEqual(len(record.message_ids[0].attachment_ids), 1) + self.assertEqual(record.message_ids[0].attachment_ids[0].name, "image0") + self.assertEqual(record.message_ids[0].attachment_ids[0].type, "binary") + + @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.models') + def test_gateway_values_base64_image_walias(self): + """New record with mail that contains base64 inline image + default values + coming from alias.""" + target_model = "mail.test.field.type" + alias = self.env["mail.alias"].create({ + "alias_name": "base64-lover", + "alias_model_id": self.env["ir.model"]._get(target_model).id, + "alias_defaults": "{'type': 'second'}", + "alias_contact": "everyone", + }) + record = self.format_and_process( + test_mail_data.MAIL_TEMPLATE_EXTRA_HTML, self.email_from, + '%s@%s' % (alias.alias_name, self.alias_catchall), + subject='base64 image to alias', + target_model=target_model, + extra_html='', + ) + self.assertEqual(record.type, "second") + self.assertEqual(len(record.message_ids[0].attachment_ids), 1) + self.assertEqual(record.message_ids[0].attachment_ids[0].name, "image0") + self.assertEqual(record.message_ids[0].attachment_ids[0].type, "binary") + # -------------------------------------------------- # Thread formation: mail gateway corner cases # --------------------------------------------------