Files
odoo_source/addons/mass_mailing/models/mail_mail.py
T
Pierre-Yves Dufays 3e57dc295c [IMP] mail, portal, website_slides, mass_mailing: unfollow record from email
Allow partner to unfollow a document from a follow up email of that document
through an unsubscribe URL in the email even if not connected.

It works for internal user for follow up on any document and for any partner on
follow up of document tagged as authorizing being unfollowed by any partner (
slide.channel and slide.slide).

Technical note:
The unfollow block is rendered in mail_thread and updated for each recipient in
mail_mail. We don't render it in mail_mail because we don't have the language
of the message at that point.

Depending on the partner and the related document, the unfollow block is:
- either removed if the user cannot unfollow the document (for example if it
doesn't follow it)
- or updated with partner and document information + a security token

Task-3061864

Part-of: odoo/odoo#107978
2023-05-10 13:21:07 +02:00

99 lines
4.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import re
import werkzeug.urls
from odoo import api, fields, models, tools
class MailMail(models.Model):
"""Add the mass mailing campaign data to mail"""
_inherit = ['mail.mail']
mailing_id = fields.Many2one('mailing.mailing', string='Mass Mailing')
mailing_trace_ids = fields.One2many('mailing.trace', 'mail_mail_id', string='Statistics')
@api.model_create_multi
def create(self, values_list):
""" Override mail_mail creation to create an entry in mail.mail.statistics """
# TDE note: should be after 'all values computed', to have values (FIXME after merging other branch holding create refactoring)
mails = super(MailMail, self).create(values_list)
for mail, values in zip(mails, values_list):
if values.get('mailing_trace_ids'):
mail.mailing_trace_ids.write({'message_id': mail.message_id})
return mails
def _get_tracking_url(self):
token = self._generate_mail_recipient_token(self.id)
return werkzeug.urls.url_join(
self.get_base_url(),
f'mail/track/{self.id}/{token}/blank.gif'
)
@api.model
def _generate_mail_recipient_token(self, mail_id):
return tools.hmac(self.env(su=True), 'mass_mailing-mail_mail-open', mail_id)
def _prepare_outgoing_body(self):
""" Override to add the tracking URL to the body and to add trace ID in
shortened urls """
self.ensure_one()
# super() already cleans pseudo-void content from editor
body = super()._prepare_outgoing_body()
if body and self.mailing_id and self.mailing_trace_ids:
for match in set(re.findall(tools.URL_REGEX, body)):
href = match[0]
url = match[1]
parsed = werkzeug.urls.url_parse(url, scheme='http')
if parsed.scheme.startswith('http') and parsed.path.startswith('/r/'):
new_href = href.replace(url, url + '/m/' + str(self.mailing_trace_ids[0].id))
body = body.replace(href, new_href)
# generate tracking URL
tracking_url = self._get_tracking_url()
body = tools.append_content_to_html(
body,
f'<img src="{tracking_url}"/>',
plaintext=False,
)
return body
def _prepare_outgoing_list(self, recipients_follower_status=None):
""" Update mailing specific links to add tracking based on res_id """
email_list = super()._prepare_outgoing_list(recipients_follower_status)
if not self.res_id or not self.mailing_id:
return email_list
base_url = self.mailing_id.get_base_url()
for email_values in email_list:
if tools.is_html_empty(email_values['body']) or not email_values['email_to']:
continue
emails = tools.email_split(email_values['email_to'][0])
email_to = emails[0] if emails else False
if f'{base_url}/unsubscribe_from_list' in email_values['body']:
email_values['body'] = email_values['body'].replace(
f'{base_url}/unsubscribe_from_list',
self.mailing_id._get_unsubscribe_url(email_to, self.res_id),
)
if f'{base_url}/view' in email_values['body']:
email_values['body'] = email_values['body'].replace(
f'{base_url}/view',
self.mailing_id._get_view_url(email_to, self.res_id),
)
return email_list
def _postprocess_sent_message(self, success_pids, failure_reason=False, failure_type=None):
mail_sent = not failure_type # we consider that a recipient error is a failure with mass mailling and show them as failed
for mail in self:
if mail.mailing_id:
if mail_sent is True and mail.mailing_trace_ids:
mail.mailing_trace_ids.set_sent()
elif mail_sent is False and mail.mailing_trace_ids:
mail.mailing_trace_ids.set_failed(failure_type=failure_type)
return super()._postprocess_sent_message(success_pids, failure_reason=failure_reason, failure_type=failure_type)