[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) <tde@openerp.com>
This commit is contained in:
Thibault Delavallée
2020-03-20 14:58:44 +00:00
parent 5353fb2496
commit fd9b259026
6 changed files with 42 additions and 54 deletions
-1
View File
@@ -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
-39
View File
@@ -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 <NaMe@DoMaIn.CoM>'
- 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)
+39 -11
View File
@@ -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 <NaMe@DoMaIn.CoM>'
- 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. """
+1 -1
View File
@@ -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'
@@ -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()
@@ -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)