diff options
| author | Thibault Delavallée <tde@odoo.com> | 2019-04-24 10:25:09 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2019-11-29 13:35:14 +0000 |
| commit | 1838191eece59051805862ed6ce914bf5e5d1efb (patch) | |
| tree | 75955be7412a59bd7463bf4b61116b5711141352 /addons | |
| parent | b9a22d2f24e587894c12bf7ad289fcddcea8a823 (diff) | |
[REF] mail, various: improve mail creation calls, notably author and email from default computation
Purpose of this commit is to correctly compute author_id and email_from
in mail_message and mail_mail as they depends from each other. Moreover it
is a good idea in various flows to specify email and author when giving
creation values to avoid default computation that is not always guaranteed to
be accurate notably when involving super user.
Mail message creation could lead to desynchronized values between author
and email_from. This is improved with this commit by correctly inheriting
from default_get and computing both of them at the same time instead of having
two default values. Indeed they depend on each other.
Same thing is done for mail composer. Mail Thread offers a tool method to
find email_from / author_id based on having one of those values or current
user and it is called whenever necessary.
Some calls to mail template send_mail are also cleaned.
Task ID 1853147
PR #32243
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/auth_signup/controllers/main.py | 5 | ||||
| -rw-r--r-- | addons/auth_signup/data/auth_signup_data.xml | 2 | ||||
| -rw-r--r-- | addons/auth_signup/models/res_users.py | 3 | ||||
| -rw-r--r-- | addons/hr_expense/models/hr_expense.py | 2 | ||||
| -rw-r--r-- | addons/im_livechat/models/mail_channel.py | 3 | ||||
| -rw-r--r-- | addons/mail/models/mail_channel.py | 5 | ||||
| -rw-r--r-- | addons/mail/models/mail_message.py | 41 | ||||
| -rw-r--r-- | addons/mail/models/mail_thread.py | 3 | ||||
| -rw-r--r-- | addons/mail/wizard/invite.py | 5 | ||||
| -rw-r--r-- | addons/mail/wizard/mail_compose_message.py | 16 | ||||
| -rw-r--r-- | addons/mass_mailing/models/mailing.py | 4 | ||||
| -rw-r--r-- | addons/mass_mailing/wizard/mailing_mailing_test.py | 4 | ||||
| -rw-r--r-- | addons/payment_paypal/models/payment.py | 3 | ||||
| -rw-r--r-- | addons/website_slides/models/slide_slide.py | 14 |
14 files changed, 63 insertions, 47 deletions
diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py index 986278e2ab3..3b6b92afd54 100644 --- a/addons/auth_signup/controllers/main.py +++ b/addons/auth_signup/controllers/main.py @@ -40,10 +40,7 @@ class AuthSignupHome(Home): user_sudo = request.env['res.users'].sudo().search([('login', '=', qcontext.get('login'))]) template = request.env.ref('auth_signup.mail_template_user_signup_account_created', raise_if_not_found=False) if user_sudo and template: - template.sudo().with_context( - lang=user_sudo.lang, - auth_login=werkzeug.url_encode({'auth_login': user_sudo.email}), - ).send_mail(user_sudo.id, force_send=True) + template.sudo().send_mail(user_sudo.id, force_send=True) return self.web_login(*args, **kw) except UserError as e: qcontext['error'] = e.name or e.value diff --git a/addons/auth_signup/data/auth_signup_data.xml b/addons/auth_signup/data/auth_signup_data.xml index 5fe062a6d44..e83930f0b88 100644 --- a/addons/auth_signup/data/auth_signup_data.xml +++ b/addons/auth_signup/data/auth_signup_data.xml @@ -289,7 +289,7 @@ Your login is <strong>${object.email}</strong><br/> To gain access to your account, you can use the following link: <div style="margin: 16px 0px 16px 0px;"> - <a href="/web/login?${ctx['auth_login']}" + <a href="/web/login?auth_login=${object.email}" style="background-color: #875A7B; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;"> Go to My Account </a> diff --git a/addons/auth_signup/models/res_users.py b/addons/auth_signup/models/res_users.py index 11df8c34116..a1abd1c32b6 100644 --- a/addons/auth_signup/models/res_users.py +++ b/addons/auth_signup/models/res_users.py @@ -195,8 +195,9 @@ class ResUsers(models.Model): for user in self: if not user.email: raise UserError(_("Cannot send email: user %s has no email address.") % user.name) + # TDE FIXME: make this template technical (qweb) with self.env.cr.savepoint(): - template.with_context(lang=user.lang).send_mail(user.id, force_send=True, raise_exception=True) + template.send_mail(user.id, force_send=True, raise_exception=True) _logger.info("Password reset email sent for user <%s> to <%s>", user.login, user.email) def send_unregistered_user_reminder(self, after_days=5): diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index a535a8840c0..259cb7e0167 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -617,6 +617,8 @@ class HrExpense(models.Model): ) else: self.env['mail.mail'].create({ + 'email_from': self.env.user.email_formatted, + 'author_id': self.env.user.partner_id.id, 'body_html': body, 'subject': 'Re: %s' % msg_dict.get('subject', ''), 'email_to': msg_dict.get('email_from', False), diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py index a46bc56d4d7..b5397e38bdf 100644 --- a/addons/im_livechat/models/mail_channel.py +++ b/addons/im_livechat/models/mail_channel.py @@ -173,7 +173,8 @@ class MailChannel(models.Model): mail_body = self.env['mail.thread']._replace_local_links(mail_body) mail = self.env['mail.mail'].create({ 'subject': _('Conversation with %s') % self.livechat_operator_id.name, - 'email_from': self.env.company.email, + 'email_from': company.catchall_formatted or company.email_formatted, + 'author_id': self.env.user.partner_id.id, 'email_to': email, 'body_html': mail_body, }) diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index a8440322c2b..ad1a1ef42b4 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -368,6 +368,8 @@ class Channel(models.Model): # The fields "email_from" and "reply_to" are filled in automatically by method create in model mail.message. if self.moderation_notify and self.moderation_notify_msg and message_type == 'email' and moderation_status == 'pending_moderation': self.env['mail.mail'].create({ + 'author_id': self.env.user.partner_id.id, + 'email_from': self.env.user.company_id.catchall_formatted or self.env.user.company_id.email_formatted, 'body_html': self.moderation_notify_msg, 'subject': 'Re: %s' % (kwargs.get('subject', '')), 'email_to': email, @@ -418,9 +420,10 @@ class Channel(models.Model): ]).mapped('email') for partner in partners.filtered(lambda p: p.email and not (p.email in banned_emails)): create_values = { + 'email_from': partner.company_id.catchall_formatted or partner.company_id.email_formatted, + 'author_id': self.env.user.partner_id.id, 'body_html': view.render({'channel': self, 'partner': partner}, engine='ir.qweb', minimal_qcontext=True), 'subject': _("Guidelines of channel %s") % self.name, - 'email_from': partner.company_id.catchall_formatted or partner.company_id.email, 'recipient_ids': [(4, partner.id)] } mail = self.env['mail.mail'].create(create_values) diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 0bcc082fee5..5be02450f87 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -9,7 +9,7 @@ from collections import defaultdict from operator import itemgetter from odoo import _, api, fields, models, modules, tools -from odoo.exceptions import UserError, AccessError +from odoo.exceptions import AccessError from odoo.http import request from odoo.osv import expression from odoo.tools import groupby @@ -27,14 +27,17 @@ class Message(models.Model): _rec_name = 'record_name' @api.model - def _get_default_from(self): - if self.env.user.email: - return tools.formataddr((self.env.user.name, self.env.user.email)) - raise UserError(_("Unable to post message, please configure the sender's email address.")) - - @api.model - def _get_default_author(self): - return self.env.user.partner_id + def default_get(self, fields): + res = super(Message, self).default_get(fields) + missing_author = 'author_id' in fields and 'author_id' not in res + missing_email_from = 'email_from' in fields and 'email_from' not in res + if missing_author or missing_email_from: + author_id, email_from = self.env['mail.thread']._message_compute_author(res.get('author_id'), res.get('email_from'), raise_exception=False) + if missing_email_from: + res['email_from'] = email_from + if missing_author: + res['author_id'] = author_id + return res # content subject = fields.Char('Subject') @@ -69,12 +72,9 @@ class Message(models.Model): 'mail.activity.type', 'Mail Activity Type', index=True, ondelete='set null') # origin - email_from = fields.Char( - 'From', default=_get_default_from, - help="Email address of the sender. This field is set when no matching partner is found and replaces the author_id field in the chatter.") + email_from = fields.Char('From', help="Email address of the sender. This field is set when no matching partner is found and replaces the author_id field in the chatter.") author_id = fields.Many2one( - 'res.partner', 'Author', index=True, - ondelete='set null', default=_get_default_author, + 'res.partner', 'Author', index=True, ondelete='set null', help="Author of the message. If not set, email_from may hold an email address that did not match any partner.") author_avatar = fields.Binary("Author's avatar", related='author_id.image_128', readonly=False) # recipients: include inactive partners (they may have been archived after @@ -574,7 +574,8 @@ class Message(models.Model): tracking_values_list = [] for values in values_list: if 'email_from' not in values: # needed to compute reply_to - values['email_from'] = self._get_default_from() + author_id, email_from = self.env['mail.thread']._message_compute_author(values.get('author_id'), email_from=None, raise_exception=False) + values['email_from'] = email_from if not values.get('message_id'): values['message_id'] = self._get_message_id(values) if 'reply_to' not in values: @@ -833,16 +834,12 @@ class Message(models.Model): for msg in self: if not msg.email_from: continue - if self.env.user.partner_id.email: - email_from = tools.formataddr((self.env.user.partner_id.name, self.env.user.partner_id.email)) - else: - email_from = self.env.company.catchall_formatted - body_html = tools.append_content_to_html('<div>%s</div>' % tools.ustr(comment), msg.body, plaintext=False) vals = { 'subject': subject, 'body_html': body_html, - 'email_from': email_from, + 'author_id': self.env.user.partner_id.id, + 'email_from': self.env.user.email_formatted or self.env.company_id.catchall_formatted, 'email_to': msg.email_from, 'auto_delete': True, 'state': 'outgoing' @@ -924,7 +921,7 @@ class Message(models.Model): partner_ids=moderator.partner_id.ids, subject=_('Message are pending moderation'), # tocheck: target language body=template.render({'record': moderator.partner_id}, engine='ir.qweb', minimal_qcontext=True), - email_from=moderator.company_id.catchall_formatted or moderator.company_id.email, + email_from=moderator.company_id.catchall_formatted or moderator.company_id.email_formatted, ) # ------------------------------------------------------ diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 0c53cbad6b1..d0abc8adab7 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -685,6 +685,7 @@ class MailThread(models.AbstractModel): def _routing_create_bounce_email(self, email_from, body_html, message, **mail_values): bounce_to = tools.decode_message_header(message, 'Return-Path') or email_from bounce_mail_values = { + 'author_id': False, 'body_html': body_html, 'subject': 'Re: %s' % message.get('subject'), 'email_to': bounce_to, @@ -693,6 +694,8 @@ class MailThread(models.AbstractModel): bounce_from = self.env['ir.mail_server']._get_default_bounce_address() if bounce_from: bounce_mail_values['email_from'] = tools.formataddr(('MAILER-DAEMON', bounce_from)) + else: + bounce_mail_values['email_from'] = tools.decode_message_header(message, 'To') bounce_mail_values.update(mail_values) self.env['mail.mail'].create(bounce_mail_values).send() diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index 44a68a92bb9..78bf03dd776 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -5,6 +5,7 @@ from lxml import etree from lxml.html import builder as html from odoo import _, api, fields, models +from odoo.exceptions import UserError class Invite(models.TransientModel): @@ -47,7 +48,9 @@ class Invite(models.TransientModel): send_mail = fields.Boolean('Send Email', default=True, help="If checked, the partners will receive an email warning they have been added in the document's followers.") def add_followers(self): - email_from = self.env['mail.message']._get_default_from() + if not self.env.user.email: + raise UserError(_("Unable to post message, please configure the sender's email address.")) + email_from = self.env.user.email_formatted for wizard in self: Model = self.env[wizard.res_model] document = Model.browse(wizard.res_id) diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 193f7faf38b..d3b0e6f16bf 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -54,14 +54,14 @@ class MailComposer(models.TransientModel): result = super(MailComposer, self).default_get(fields) # author - if 'author_id' not in result: - result['author_id'] = self.env.user.partner_id.id - if 'email_from' not in result and self.env.user.email: - result['email_from'] = self.env.user.email_formatted - elif 'email_from' not in result: - author = self.env['res.partner'].browse(result['author_id']) - if author.email: - result['email_from'] = tools.formataddr((author.name, author.email)) + missing_author = 'author_id' in fields and 'author_id' not in result + missing_email_from = 'email_from' in fields and 'email_from' not in result + if missing_author or missing_email_from: + author_id, email_from = self.env['mail.thread']._message_compute_author(result.get('author_id'), result.get('email_from'), raise_exception=False) + if missing_email_from: + result['email_from'] = email_from + if missing_author: + result['author_id'] = author_id result['composition_mode'] = result.get('composition_mode', 'comment') result['model'] = result.get('model', self._context.get('active_model')) diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index cd098b3a347..999b3f824b0 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -69,7 +69,7 @@ class MassMailing(models.Model): active = fields.Boolean(default=True, tracking=True) subject = fields.Char('Subject', help='Subject of emails to send', required=True, translate=True) email_from = fields.Char(string='Send From', required=True, - default=lambda self: self.env['mail.message']._get_default_from()) + default=lambda self: self.env.user.email_formatted) sent_date = fields.Datetime(string='Sent Date', copy=False) schedule_date = fields.Datetime(string='Scheduled for', tracking=True) # don't translate 'body_arch', the translations are only on 'body_html' @@ -92,7 +92,7 @@ class MassMailing(models.Model): reply_to_mode = fields.Selection( [('thread', 'Recipient Followers'), ('email', 'Specified Email Address')], string='Reply-To Mode', required=True) reply_to = fields.Char(string='Reply To', help='Preferred Reply-To Address', - default=lambda self: self.env['mail.message']._get_default_from()) + default=lambda self: self.env.user.email_formatted) # recipients mailing_model_real = fields.Char(compute='_compute_model', string='Recipients Real Model', default='mailing.contact', required=True) mailing_model_id = fields.Many2one('ir.model', string='Recipients Model', domain=[('model', 'in', MASS_MAILING_BUSINESS_MODELS)], diff --git a/addons/mass_mailing/wizard/mailing_mailing_test.py b/addons/mass_mailing/wizard/mailing_mailing_test.py index 54424262563..5aa09a71999 100644 --- a/addons/mass_mailing/wizard/mailing_mailing_test.py +++ b/addons/mass_mailing/wizard/mailing_mailing_test.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models, tools +from odoo import fields, models, tools class TestMassMailing(models.TransientModel): @@ -9,7 +9,7 @@ class TestMassMailing(models.TransientModel): _description = 'Sample Mail Wizard' email_to = fields.Char(string='Recipients', required=True, - help='Comma-separated list of email addresses.', default=lambda self: self.env['mail.message']._get_default_from()) + help='Comma-separated list of email addresses.', default=lambda self: self.env.user.email_formatted) mass_mailing_id = fields.Many2one('mailing.mailing', string='Mailing', required=True, ondelete='cascade') def send_mail_test(self): diff --git a/addons/payment_paypal/models/payment.py b/addons/payment_paypal/models/payment.py index 64afaf6ad7c..40b38c70092 100644 --- a/addons/payment_paypal/models/payment.py +++ b/addons/payment_paypal/models/payment.py @@ -199,7 +199,8 @@ class TxPaypal(models.Model): 'body_html': mail_body, 'subject': _('Add your Paypal account to Odoo'), 'email_to': self.acquirer_id.paypal_email_account, - 'email_from': self.acquirer_id.create_uid.email + 'email_from': self.acquirer_id.create_uid.email_formatted, + 'author_id': self.acquirer_id.create_uid.partner_id.id, } self.env['mail.mail'].sudo().create(mail_values).send() diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index 0a61291bb2c..9e0730a1abb 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -502,10 +502,18 @@ class Slide(models.Model): mail_ids = [] base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') for record in self: + template = self.channel_id.share_template_id.with_context( + user=self.env.user, + email=email, + base_url=base_url, + fullscreen=fullscreen + ) + email_values = {'email_to': email} if self.env.user.has_group('base.group_portal'): - mail_ids.append(self.channel_id.share_template_id.with_context(user=self.env.user, email=email, base_url=base_url, fullscreen=fullscreen).sudo().send_mail(record.id, notif_layout='mail.mail_notification_light', email_values={'email_from': self.env.company.catchall_formatted or self.env.company.email, 'email_to': email})) - else: - mail_ids.append(self.channel_id.share_template_id.with_context(user=self.env.user, email=email, base_url=base_url, fullscreen=fullscreen).send_mail(record.id, notif_layout='mail.mail_notification_light', email_values={'email_to': email})) + template = template.sudo() + email_values['email_from'] = self.env.company.catchall_formatted or self.env.company.email_formatted + + mail_ids.append(template.send_mail(record.id, notif_layout='mail.mail_notification_light', email_values=email_values)) return mail_ids def action_like(self): |
