From fd9b2590261e6caf4a8952d17db6e1ca06778140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 31 Jan 2020 15:47:29 +0000 Subject: [PATCH] [REF] mail: merge blacklist and address mixins PURPOSE Perform some code cleaning in mail module SPECIFICATIONS mail.address.mixin is used only for mail.thread.blacklist mixin. Let us merge those two and simplify class organization. LINKS Task ID 2222033 closes odoo/odoo#48115 Related: odoo/upgrade#967 Signed-off-by: Thibault Delavallee (tde) --- addons/mail/models/__init__.py | 1 - addons/mail/models/mail_address_mixin.py | 39 --------------- addons/mail/models/mail_blacklist.py | 50 +++++++++++++++---- addons/mass_mailing/models/mailing.py | 2 +- .../models/mass_mail_test.py | 2 +- .../tests/test_performance.py | 2 +- 6 files changed, 42 insertions(+), 54 deletions(-) delete mode 100644 addons/mail/models/mail_address_mixin.py diff --git a/addons/mail/models/__init__.py b/addons/mail/models/__init__.py index e123a3920be..7f45f11aece 100644 --- a/addons/mail/models/__init__.py +++ b/addons/mail/models/__init__.py @@ -12,7 +12,6 @@ from . import mail_activity from . import mail_mail from . import mail_thread from . import mail_cc_mixin -from . import mail_address_mixin from . import mail_blacklist from . import mail_channel from . import mail_template diff --git a/addons/mail/models/mail_address_mixin.py b/addons/mail/models/mail_address_mixin.py deleted file mode 100644 index c2e5fdb9111..00000000000 --- a/addons/mail/models/mail_address_mixin.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import api, fields, models, tools, _ -from odoo.exceptions import UserError - - -class MailAddressMixin(models.AbstractModel): - """ Purpose of this mixin is to store a normalized email based on the primary email field. - A normalized email is considered as : - - having a left part + @ + a right part (the domain can be without '.something') - - being lower case - - having no name before the address. Typically, having no 'Name <>' - Ex: - - Formatted Email : 'Name ' - - Normalized Email : 'name@domain.com' - The primary email field can be specified on the parent model, if it differs from the default one ('email') - The email_normalized field can than be used on that model to search quickly on emails (by simple comparison - and not using time consuming regex anymore). """ - _name = 'mail.address.mixin' - _description = 'Email Address Mixin' - _primary_email = 'email' - - email_normalized = fields.Char( - string='Normalized Email', compute="_compute_email_normalized", compute_sudo=True, - store=True, invisible=True, - help="This field is used to search on email address as the primary email field can contain more than strictly an email address.") - - @api.depends(lambda self: [self._primary_email]) - def _compute_email_normalized(self): - self._assert_primary_email() - for record in self: - record.email_normalized = tools.email_normalize(record[self._primary_email]) - - def _assert_primary_email(self): - if not hasattr(self, "_primary_email") or not isinstance(self._primary_email, str): - raise UserError(_('Invalid primary email field on model %s') % self._name) - if self._primary_email not in self._fields or self._fields[self._primary_email].type != 'char': - raise UserError(_('Invalid primary email field on model %s') % self._name) diff --git a/addons/mail/models/mail_blacklist.py b/addons/mail/models/mail_blacklist.py index 24c7f2c7338..abae3f35fbd 100644 --- a/addons/mail/models/mail_blacklist.py +++ b/addons/mail/models/mail_blacklist.py @@ -1,13 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import logging - from odoo import api, fields, models, tools, _ from odoo.exceptions import UserError -_logger = logging.getLogger(__name__) - class MailBlackList(models.Model): """ Model of blacklisted email addresses to stop sending emails.""" @@ -93,14 +89,34 @@ class MailBlackList(models.Model): class MailBlackListMixin(models.AbstractModel): - """ Mixin that is inherited by all model with opt out. This mixin inherits from - mail.address.mixin which defines the _primary_email variable and the email_normalized - field that are mandatory to use the blacklist mixin. Mail Thread capabilities - are required for this mixin. """ - _name = 'mail.thread.blacklist' - _description = 'Mail Blacklist mixin' - _inherit = ['mail.thread', 'mail.address.mixin'] + """ Mixin that is inherited by all model with opt out. This mixin stores a normalized + email based on primary_email field. + A normalized email is considered as : + - having a left part + @ + a right part (the domain can be without '.something') + - being lower case + - having no name before the address. Typically, having no 'Name <>' + Ex: + - Formatted Email : 'Name ' + - Normalized Email : 'name@domain.com' + + The primary email field can be specified on the parent model, if it differs from the default one ('email') + The email_normalized field can than be used on that model to search quickly on emails (by simple comparison + and not using time consuming regex anymore). + + Using this email_normalized field, blacklist status is computed. + + Mail Thread capabilities are required for this mixin. """ + + _name = 'mail.thread.blacklist' + _inherit = ['mail.thread'] + _description = 'Mail Blacklist mixin' + _primary_email = 'email' + + email_normalized = fields.Char( + string='Normalized Email', compute="_compute_email_normalized", compute_sudo=True, + store=True, invisible=True, + help="This field is used to search on email address as the primary email field can contain more than strictly an email address.") # Note : is_blacklisted sould only be used for display. As the compute is not depending on the blacklist, # once read, it won't be re-computed again if the blacklist is modified in the same request. is_blacklisted = fields.Boolean( @@ -110,6 +126,12 @@ class MailBlackListMixin(models.AbstractModel): # messaging message_bounce = fields.Integer('Bounce', help="Counter of the number of bounced emails for this contact", default=0) + @api.depends(lambda self: [self._primary_email]) + def _compute_email_normalized(self): + self._assert_primary_email() + for record in self: + record.email_normalized = tools.email_normalize(record[self._primary_email]) + @api.model def _search_is_blacklisted(self, operator, value): # Assumes operator is '=' or '!=' and value is True or False @@ -152,6 +174,12 @@ class MailBlackListMixin(models.AbstractModel): for record in self: record.is_blacklisted = record.email_normalized in blacklist + def _assert_primary_email(self): + if not hasattr(self, "_primary_email") or not isinstance(self._primary_email, str): + raise UserError(_('Invalid primary email field on model %s') % self._name) + if self._primary_email not in self._fields or self._fields[self._primary_email].type != 'char': + raise UserError(_('Invalid primary email field on model %s') % self._name) + def _message_receive_bounce(self, email, partner): """ Override of mail.thread generic method. Purpose is to increment the bounce counter of the record. """ diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 0cb176d3174..88c5a9c4574 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -443,7 +443,7 @@ class MassMailing(models.Model): JOIN res_partner p ON (t.partner_id = p.id) WHERE substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL """ - elif issubclass(type(target), self.pool['mail.address.mixin']): + elif issubclass(type(target), self.pool['mail.thread.blacklist']): mail_field = 'email_normalized' elif 'email_from' in target._fields: mail_field = 'email_from' diff --git a/addons/test_mass_mailing/models/mass_mail_test.py b/addons/test_mass_mailing/models/mass_mail_test.py index 3da40c424ce..d4772433748 100644 --- a/addons/test_mass_mailing/models/mass_mail_test.py +++ b/addons/test_mass_mailing/models/mass_mail_test.py @@ -9,7 +9,7 @@ class MassMailTest(models.Model): mailing features and base performances. """ _description = 'Simple Mass Mailing Model' _name = 'mass.mail.test' - _inherit = ['mail.thread', 'mail.address.mixin'] + _inherit = ['mail.thread.blacklist'] _primary_email = 'email_from' name = fields.Char() diff --git a/addons/test_mass_mailing/tests/test_performance.py b/addons/test_mass_mailing/tests/test_performance.py index d1791ecb1bb..276b2701731 100644 --- a/addons/test_mass_mailing/tests/test_performance.py +++ b/addons/test_mass_mailing/tests/test_performance.py @@ -51,7 +51,7 @@ class TestMassMailPerformance(TestMassMailPerformanceBase): }) # runbot needs +50 compared to local - with self.assertQueryCount(__system__=1912, marketing=1913): + with self.assertQueryCount(__system__=1915, marketing=1916): mailing.action_send_mail() self.assertEqual(mailing.sent, 50)