From f72621a445d6f4b82c14bdd82077d65a10504b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 18 May 2022 14:19:25 +0000 Subject: [PATCH 1/8] [FIX] mass_mailing: use frontend assets in subscription page PURPOSE Overall cleaning of subscription and exclusion management code from portal. SPECIFICATIONS Unsubscribe page uses a custom layout allowing a portal-like behavior for mass mailing without any link to website or portal. However it currently uses the complete backend assets. This leads to a lot of unnecessary css and js being loaded. When having frontend pages like the one used in mass mailing it should rely on frontend assets with some custom assets if necessary for the page to be correctly displayed. In this commit we choose to use frontend assets like other portal-like pages. Mailing layout now uses the frontend layout defined in web and adds its own subset of assets (mailing_assets). Some custom css is moved or added as well as few tweaks to ensure layouting is globally the same as before this commit. Task-3082546 (Mass Mailing: Fix assets and unsubscribe page) Task-2669037 (Mass Mailing: Subscription page code cleaning) Prepares Task-2150462 (Mass Mailing: Unsubscribe flow refactoring) Part-of: odoo/odoo#106568 --- addons/mass_mailing/__manifest__.py | 5 +++- .../static/src/scss/mailing_portal.scss | 16 ++++++++++ .../static/src/scss/mass_mailing.scss | 9 ------ .../mailing_templates_portal_layouts.xml | 29 +++++-------------- .../mailing_templates_portal_unsubscribe.xml | 26 +++++++++++------ 5 files changed, 44 insertions(+), 41 deletions(-) create mode 100644 addons/mass_mailing/static/src/scss/mailing_portal.scss diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index 7b0fc32dbf9..5dd136c88a4 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -85,6 +85,10 @@ ], 'application': True, 'assets': { + 'mass_mailing.mailing_assets': [ + 'mass_mailing/static/src/scss/mailing_portal.scss', + 'mass_mailing/static/src/js/mailing_portal.js', + ], 'web.assets_backend': [ 'mass_mailing/static/src/scss/mailing_filter_widget.scss', 'mass_mailing/static/src/scss/mass_mailing.scss', @@ -98,7 +102,6 @@ 'mass_mailing/static/src/js/mass_mailing_mobile_preview.js', 'mass_mailing/static/src/js/mass_mailing_html_field.js', 'mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js', - 'mass_mailing/static/src/js/mailing_portal.js', 'mass_mailing/static/src/xml/mailing_filter_widget.xml', 'mass_mailing/static/src/xml/mass_mailing.xml', 'mass_mailing/static/src/views/*.xml', diff --git a/addons/mass_mailing/static/src/scss/mailing_portal.scss b/addons/mass_mailing/static/src/scss/mailing_portal.scss new file mode 100644 index 00000000000..85ea4a0f20f --- /dev/null +++ b/addons/mass_mailing/static/src/scss/mailing_portal.scss @@ -0,0 +1,16 @@ +.o_mailing_portal_body { + // Taken from webclient.scss to copy backend styling + // Uppercase primary and secondary except when secondary is used as a dropdown + // toggler. + .btn-primary, + .btn-secondary:not(.dropdown-toggle):not(.dropdown-item), + .btn-secondary.o_arrow_button:not(.dropdown-item) { + text-transform: uppercase; + } + + .o_mailing_portal_list_unsubscribed { + margin-left: 20px; + color: #005326; + font-size: 90%; + } +} diff --git a/addons/mass_mailing/static/src/scss/mass_mailing.scss b/addons/mass_mailing/static/src/scss/mass_mailing.scss index 31b9597bd60..06956315fef 100644 --- a/addons/mass_mailing/static/src/scss/mass_mailing.scss +++ b/addons/mass_mailing/static/src/scss/mass_mailing.scss @@ -210,15 +210,6 @@ bottom: 55px; } } -.o_white_body { - background-color: white; -} - -.o_mass_mailing_unsubscribed { - margin-left: 20px; - color: #005326; - font-size: 90%; -} .o_mailing_contact_import_list { diff --git a/addons/mass_mailing/views/mailing_templates_portal_layouts.xml b/addons/mass_mailing/views/mailing_templates_portal_layouts.xml index 600d026fb6f..1cbc80a3de5 100644 --- a/addons/mass_mailing/views/mailing_templates_portal_layouts.xml +++ b/addons/mass_mailing/views/mailing_templates_portal_layouts.xml @@ -2,18 +2,8 @@ diff --git a/addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml b/addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml index 32d26518283..df8cf87f693 100644 --- a/addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml +++ b/addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml @@ -29,11 +29,11 @@
  • - + class="o_mailing_portal_list_unsubscribed"> Unsubscribed
  • @@ -42,11 +42,15 @@
    -
    - -
    - - + + +
    @@ -89,8 +93,12 @@
    - - + +
    From 1844f335d780762da997cec40019bec8958d9edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 9 Jun 2022 08:39:42 +0000 Subject: [PATCH 2/8] [IMP] mail, phone_validation: allow to log a message when (un)blacklisting Add possibility to add a message when adding or removing a blacklist entry for both mail and phone_validation (used for SMS). This replaces the ``action_remove_with_reason`` method. When updating active flag this is added as a tracking note to avoid having several messages. Indeed message is concatenated with the tracking itself instead of adding message for tracking + a message for the log itself. When a new record is created, a note is logged. Task-2710804 (Mail: Clean MailThread API) Prepares Task-2150462 (Mass Mailing: Unsubscribe flow refactoring) Part-of: odoo/odoo#106568 --- addons/mail/models/mail_blacklist.py | 25 +++++++---- addons/mail/wizard/mail_blacklist_remove.py | 12 +++++- .../models/phone_blacklist.py | 41 ++++++++++++------- .../wizard/phone_blacklist_remove.py | 12 +++++- .../test_mass_mailing/tests/test_mailing.py | 4 +- 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/addons/mail/models/mail_blacklist.py b/addons/mail/models/mail_blacklist.py index 4fdd6c6764f..7adf2476721 100644 --- a/addons/mail/models/mail_blacklist.py +++ b/addons/mail/models/mail_blacklist.py @@ -69,29 +69,36 @@ class MailBlackList(models.Model): new_args = args return super(MailBlackList, self)._search(new_args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid) - def _add(self, email): + def _add(self, email, message=None): normalized = tools.email_normalize(email) record = self.env["mail.blacklist"].with_context(active_test=False).search([('email', '=', normalized)]) if len(record) > 0: + if message: + record._track_set_log_message(message) record.action_unarchive() else: record = self.create({'email': email}) + if message: + record.with_context(mail_create_nosubscribe=True).message_post( + body=message, + subtype_id=self.env.ref('mail.mt_note').id, + ) return record - def action_remove_with_reason(self, email, reason=None): - record = self._remove(email) - if reason: - record.message_post(body=_("Unblacklisting Reason: %s", reason)) - - return record - - def _remove(self, email): + def _remove(self, email, message=None): normalized = tools.email_normalize(email) record = self.env["mail.blacklist"].with_context(active_test=False).search([('email', '=', normalized)]) if len(record) > 0: + if message: + record._track_set_log_message(message) record.action_archive() else: record = record.create({'email': email, 'active': False}) + if message: + record.with_context(mail_create_nosubscribe=True).message_post( + body=message, + subtype_id=self.env.ref('mail.mt_note').id, + ) return record def mail_action_blacklist_remove(self): diff --git a/addons/mail/wizard/mail_blacklist_remove.py b/addons/mail/wizard/mail_blacklist_remove.py index 2fc6374cc3d..f4347d54b9d 100644 --- a/addons/mail/wizard/mail_blacklist_remove.py +++ b/addons/mail/wizard/mail_blacklist_remove.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -from odoo import fields, models +from markupsafe import Markup +from odoo import fields, models, _ class MailBlacklistRemove(models.TransientModel): @@ -11,4 +12,11 @@ class MailBlacklistRemove(models.TransientModel): reason = fields.Char(name="Reason") def action_unblacklist_apply(self): - return self.env['mail.blacklist'].action_remove_with_reason(self.email, self.reason) + if self.reason: + message = Markup('

    %s

    ') % _("Unblock Reason: %(reason)s", reason=self.reason) + else: + message = None + return self.env['mail.blacklist']._remove( + self.email, + message=message, + ) diff --git a/addons/phone_validation/models/phone_blacklist.py b/addons/phone_validation/models/phone_blacklist.py index 2d40e5ad73c..8ce9b5ef4d3 100644 --- a/addons/phone_validation/models/phone_blacklist.py +++ b/addons/phone_validation/models/phone_blacklist.py @@ -78,43 +78,54 @@ class PhoneBlackList(models.Model): new_args = args return super(PhoneBlackList, self)._search(new_args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid) - def add(self, number): + def add(self, number, message=None): sanitized = phone_validation.phone_sanitize_numbers_w_record([number], self.env.user)[number]['sanitized'] - return self._add([sanitized]) + return self._add([sanitized], message=message) - def _add(self, numbers): + def _add(self, numbers, message=None): """ Add or re activate a phone blacklist entry. :param numbers: list of sanitized numbers """ records = self.env["phone.blacklist"].with_context(active_test=False).search([('number', 'in', numbers)]) todo = [n for n in numbers if n not in records.mapped('number')] if records: + if message: + records._track_set_log_message(message) records.action_unarchive() if todo: - records += self.create([{'number': n} for n in todo]) + new_records = self.create([{'number': n} for n in todo]) + if message: + for record in new_records: + record.with_context(mail_create_nosubscribe=True).message_post( + body=message, + subtype_id=self.env.ref('mail.mt_note').id, + ) + records += new_records return records - def action_remove_with_reason(self, number, reason=None): - records = self.remove(number) - if reason: - for record in records: - record.message_post(body=_("Unblacklisting Reason: %s", reason)) - return records - - def remove(self, number): + def remove(self, number, message=None): sanitized = phone_validation.phone_sanitize_numbers_w_record([number], self.env.user)[number]['sanitized'] - return self._remove([sanitized]) + return self._remove([sanitized], message=message) - def _remove(self, numbers): + def _remove(self, numbers, message=None): """ Add de-activated or de-activate a phone blacklist entry. :param numbers: list of sanitized numbers """ records = self.env["phone.blacklist"].with_context(active_test=False).search([('number', 'in', numbers)]) todo = [n for n in numbers if n not in records.mapped('number')] if records: + if message: + records._track_set_log_message(message) records.action_archive() if todo: - records += self.create([{'number': n, 'active': False} for n in todo]) + new_records = self.create([{'number': n, 'active': False} for n in todo]) + if message: + for record in new_records: + record.with_context(mail_create_nosubscribe=True).message_post( + body=message, + subtype_id=self.env.ref('mail.mt_note').id, + ) + records += new_records return records def phone_action_blacklist_remove(self): diff --git a/addons/phone_validation/wizard/phone_blacklist_remove.py b/addons/phone_validation/wizard/phone_blacklist_remove.py index 8dff728f9f8..be18b5a3f2d 100644 --- a/addons/phone_validation/wizard/phone_blacklist_remove.py +++ b/addons/phone_validation/wizard/phone_blacklist_remove.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -from odoo import fields, models +from markupsafe import Markup +from odoo import fields, models, _ class PhoneBlacklistRemove(models.TransientModel): @@ -11,4 +12,11 @@ class PhoneBlacklistRemove(models.TransientModel): reason = fields.Char(name="Reason") def action_unblacklist_apply(self): - return self.env['phone.blacklist'].action_remove_with_reason(self.phone, self.reason) + if self.reason: + message = Markup('

    %s

    ') % _("Unblock Reason: %(reason)s", reason=self.reason) + else: + message = None + return self.env['phone.blacklist']._remove( + self.phone, + message=message, + ) diff --git a/addons/test_mass_mailing/tests/test_mailing.py b/addons/test_mass_mailing/tests/test_mailing.py index 029e55ac7d3..df06c911a85 100644 --- a/addons/test_mass_mailing/tests/test_mailing.py +++ b/addons/test_mass_mailing/tests/test_mailing.py @@ -229,8 +229,8 @@ class TestMassMailing(TestMassMailCommon): self.env['mail.blacklist'].create({'email': recipients[4].email_normalized}) # unblacklist record 2 - self.env['mail.blacklist'].action_remove_with_reason( - recipients[2].email_normalized, "human error" + self.env['mail.blacklist']._remove( + recipients[2].email_normalized, message="human error" ) self.env['mail.blacklist'].flush_model(['active']) From f0bbe9561fad555ce70fdf23c55403d24cd12449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 16 Sep 2022 13:51:53 +0000 Subject: [PATCH 3/8] [REF] mail, mass_mailing: improve logging of emails exclusion Purpose of this commit is to use the newly introduced feature to log a message when adding or removing an entry in block list of emails in email marketing application. Logging itself is improved, as it now contains * source of the request (unsubscribe link, or manual ask through the portal unsubscription page); * link to the source mailing; * link to the document that generated the click (a mailing contact, a sales order, ...); Task-2710804 (Mail: Clean MailThread API) Prepares Task-2150462 (Mass Mailing: Unsubscribe flow refactoring) Part-of: odoo/odoo#106568 --- addons/mail/models/res_users.py | 10 ++-- addons/mass_mailing/controllers/main.py | 59 ++++++++++++++++------- addons/mass_mailing/models/mail_thread.py | 10 ++-- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/addons/mail/models/res_users.py b/addons/mail/models/res_users.py index bcdba48601c..13ae3c1c5ed 100644 --- a/addons/mail/models/res_users.py +++ b/addons/mail/models/res_users.py @@ -189,11 +189,11 @@ class Users(models.Model): super(Users, self)._deactivate_portal_user(**post) for user in users_to_blacklist: - blacklist = self.env['mail.blacklist']._add(user.email) - blacklist._message_log( - body=_('Blocked by deletion of portal account %(portal_user_name)s by %(user_name)s (#%(user_id)s)', - user_name=current_user.name, user_id=current_user.id, - portal_user_name=user.name), + self.env['mail.blacklist']._add( + user.email, + message=_('Blocked by deletion of portal account %(portal_user_name)s by %(user_name)s (#%(user_id)s)', + user_name=current_user.name, user_id=current_user.id, + portal_user_name=user.name) ) # ------------------------------------------------------------ diff --git a/addons/mass_mailing/controllers/main.py b/addons/mass_mailing/controllers/main.py index 2b3cfd32fc7..5dc4217e6bc 100644 --- a/addons/mass_mailing/controllers/main.py +++ b/addons/mass_mailing/controllers/main.py @@ -7,6 +7,8 @@ import werkzeug from odoo import _, exceptions, http, tools from odoo.http import request from odoo.tools import consteq + +from markupsafe import Markup, escape from werkzeug.exceptions import BadRequest, NotFound @@ -18,11 +20,6 @@ class MassMailController(http.Controller): mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) return consteq(mailing._unsubscribe_token(res_id, email), token) - def _log_blacklist_action(self, blacklist_entry, mailing_id, description): - mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) - model_display = mailing.mailing_model_id.display_name - blacklist_entry._message_log(body=description + " ({})".format(model_display)) - # ------------------------------------------------------------ # SUBSCRIPTION MANAGEMENT # ------------------------------------------------------------ @@ -66,10 +63,15 @@ class MassMailController(http.Controller): ('contact_id.email_normalized', '=', email), ('opt_out', '=', False) ]).mapped('list_id') - blacklist_rec = request.env['mail.blacklist'].sudo()._add(email) - self._log_blacklist_action( - blacklist_rec, mailing_id, - _("""Requested blacklisting via unsubscribe link.""")) + + message = Markup('

    %s

    ') % Markup( + _( + 'Blocklist request from unsubscribe link of mailing %(mailing_link)s (document %(record_link)s)', + **self._format_bl_request(mailing, res_id) + ) + ) + _blacklist_rec = request.env['mail.blacklist'].sudo()._add(email, message=message) + return request.render('mass_mailing.page_unsubscribed', { 'email': email, 'mailing_id': mailing_id, @@ -204,10 +206,18 @@ class MassMailController(http.Controller): if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): return 'unauthorized' if email: - blacklist_rec = request.env['mail.blacklist'].sudo()._add(email) - self._log_blacklist_action( - blacklist_rec, mailing_id, - _("""Requested blacklisting via unsubscription page.""")) + if mailing_id and res_id: + mailing_sudo = request.env['mailing.mailing'].sudo().browse(mailing_id) + message = Markup('

    %s

    ') % Markup( + _( + 'Blocklist request from portal of mailing %(mailing_link)s (document %(record_link)s)', + **self._format_bl_request(mailing_sudo, res_id) + ) + ) + else: + message = Markup('

    %s

    ') % _('Blocklist request from portal') + + _blacklist_rec = request.env['mail.blacklist'].sudo()._add(email, message=message) return True return 'error' @@ -216,13 +226,28 @@ class MassMailController(http.Controller): if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): return 'unauthorized' if email: - blacklist_rec = request.env['mail.blacklist'].sudo()._remove(email) - self._log_blacklist_action( - blacklist_rec, mailing_id, - _("""Requested de-blacklisting via unsubscription page.""")) + if mailing_id and res_id: + mailing_sudo = request.env['mailing.mailing'].sudo().browse(mailing_id) + message = Markup('

    %s

    ') % Markup( + _( + 'Blocklist removal request from portal of mailing %(mailing_link)s (document %(record_link)s)', + **self._format_bl_request(mailing_sudo, res_id) + ) + ) + else: + message = Markup('

    %s

    ') % _('Blocklist removal request from portal') + + _blacklist_rec = request.env['mail.blacklist'].sudo()._remove(email, message=message) return True return 'error' + def _format_bl_request(self, mailing, document_id): + mailing_model_name = request.env['ir.model']._get(mailing.mailing_model_real).display_name + return { + 'mailing_link': Markup(f'{escape(mailing.subject)}'), + 'record_link': Markup(f'{escape(mailing_model_name)}'), + } + # ------------------------------------------------------------ # MISCELLANEOUS # ------------------------------------------------------------ diff --git a/addons/mass_mailing/models/mail_thread.py b/addons/mass_mailing/models/mail_thread.py index 08fb3b67e86..fff1aea4641 100644 --- a/addons/mass_mailing/models/mail_thread.py +++ b/addons/mass_mailing/models/mail_thread.py @@ -2,8 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import datetime +from markupsafe import Markup -from odoo import api, models, fields, tools +from odoo import api, models, fields, tools, _ BLACKLIST_MAX_BOUNCED_LIMIT = 5 @@ -59,9 +60,10 @@ class MailThread(models.AbstractModel): stats = self.env['mailing.trace'].search(['&', '&', ('trace_status', '=', 'bounce'), ('write_date', '>', three_months_ago), ('email', '=ilike', bounced_email)]).mapped('write_date') if len(stats) >= BLACKLIST_MAX_BOUNCED_LIMIT and (not bounced_partner or any(p.message_bounce >= BLACKLIST_MAX_BOUNCED_LIMIT for p in bounced_partner)): if max(stats) > min(stats) + datetime.timedelta(weeks=1): - blacklist_rec = self.env['mail.blacklist'].sudo()._add(bounced_email) - blacklist_rec._message_log( - body='This email has been automatically blacklisted because of too much bounced.') + self.env['mail.blacklist'].sudo()._add( + bounced_email, + message=Markup('

    %s

    ') % _('This email has been automatically added in blocklist because of too much bounced.') + ) @api.model def message_new(self, msg_dict, custom_values=None): From 225b487a3c8689a62b35d3b23783aaf01c2222f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 9 Jun 2022 08:40:59 +0000 Subject: [PATCH 4/8] [IMP] mass_mailing: add helper field when targeting mailing lists Currently there are several checks on mailed model directly in code due to mailing list specific behavior. In order to be easier to manipulate and a bit less low leve, a computed field is introduced for that purpose. Indeed there are some behavior changes when the mailing runs on mailing lists instead of directly on records. There are notably some changes in display (choose mailing lists but mail contact is the real contact model), and in subscription page (directly unsubscribe from mailing lists). Task-2710804 (Mail: Clean MailThread API) Prepares Task-2150462 (Mass Mailing: Unsubscribe flow refactoring) Part-of: odoo/odoo#106568 --- addons/mass_mailing/__manifest__.py | 2 +- addons/mass_mailing/models/mailing.py | 11 ++++++++++- .../views/mailing_mailing_views.xml | 19 ++++++++++--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index 5dd136c88a4..36abfb83f75 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -4,7 +4,7 @@ { 'name': 'Email Marketing', 'summary': 'Design, send and track emails', - 'version': '2.5', + 'version': '2.6', 'sequence': 60, 'website': 'https://www.odoo.com/app/email-marketing', 'category': 'Marketing/Email Marketing', diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index d95f295c1b3..00ccf892457 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -53,7 +53,7 @@ class MassMailing(models.Model): }) if 'contact_list_ids' in fields_list and not vals.get('contact_list_ids') and vals.get('mailing_model_id'): - if vals.get('mailing_model_id') == self.env['ir.model']._get('mailing.list').id: + if vals.get('mailing_model_id') == self.env['ir.model']._get_id('mailing.list'): mailing_list = self.env['mailing.list'].search([], limit=2) if len(mailing_list) == 1: vals['contact_list_ids'] = [(6, 0, [mailing_list.id])] @@ -154,6 +154,9 @@ class MassMailing(models.Model): mailing_model_name = fields.Char( string='Recipients Model Name', related='mailing_model_id.model', readonly=True, related_sudo=True) + mailing_on_mailing_list = fields.Boolean( + string='Based on Mailing Lists', + compute='_compute_mailing_on_mailing_list') mailing_domain = fields.Char( string='Domain', compute='_compute_mailing_domain', readonly=False, store=True) @@ -383,6 +386,12 @@ class MassMailing(models.Model): for mailing in self: mailing.mailing_model_real = 'mailing.contact' if mailing.mailing_model_id.model == 'mailing.list' else mailing.mailing_model_id.model + @api.depends('mailing_model_id') + def _compute_mailing_on_mailing_list(self): + mailing_list_model_id = self.env['ir.model']._get('mailing.list') + self.mailing_on_mailing_list = False + self.filtered(lambda m: m.mailing_model_id == mailing_list_model_id).mailing_on_mailing_list = True + @api.depends('mailing_model_id', 'contact_list_ids', 'mailing_type', 'mailing_filter_id') def _compute_mailing_domain(self): for mailing in self: diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index a1af5512eee..1a43b40e0a7 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -194,14 +194,14 @@ -
    +
    -
    +
    + -
    +
    @@ -483,7 +484,7 @@ - + @@ -536,8 +537,8 @@
    / Delivered to - - Mailing Contact + + Mailing Contact
    @@ -567,8 +568,8 @@ - - Mailing Contact + + Mailing Contact From b4559e55d25e0a519b84b02ec191633146e1654c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 9 Mar 2022 08:59:57 +0000 Subject: [PATCH 5/8] [REF] mass_mailing: rename templates and controller methods PURPOSE Overall cleaning of subscription and exclusion list management code from portal. SPECIFICATIONS Rename templates to better understand their purpose. Current naming is not crystal clear. Rename controller methods in order to be clearer and more aligned with current guidelines. Notably namespace by mailing, try to be clearer about their purpose, ... No change should occur with this commit. Task-2710804 (Mail: Clean MailThread API) Task-2669037 (Mass Mailing: Subscription page code cleaning) Prepares Task-2150462 (Mass Mailing: Unsubscribe flow refactoring) Part-of: odoo/odoo#106568 --- addons/mass_mailing/controllers/main.py | 40 +++++++++---------- .../mailing_templates_portal_management.xml | 2 +- .../mailing_templates_portal_unsubscribe.xml | 28 ++++++------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/addons/mass_mailing/controllers/main.py b/addons/mass_mailing/controllers/main.py index 5dc4217e6bc..839be83a5c7 100644 --- a/addons/mass_mailing/controllers/main.py +++ b/addons/mass_mailing/controllers/main.py @@ -14,7 +14,7 @@ from werkzeug.exceptions import BadRequest, NotFound class MassMailController(http.Controller): - def _valid_unsubscribe_token(self, mailing_id, res_id, email, token): + def _check_mailing_email_token(self, mailing_id, res_id, email, token): if not (mailing_id and res_id and email and token): return False mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) @@ -25,11 +25,11 @@ class MassMailController(http.Controller): # ------------------------------------------------------------ @http.route(['/mail/mailing//unsubscribe'], type='http', website=True, auth='public') - def mailing(self, mailing_id, email=None, res_id=None, token="", **post): + def mailing_unsubscribe(self, mailing_id, email=None, res_id=None, token="", **post): mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) if mailing.exists(): res_id = res_id and int(res_id) - if not self._valid_unsubscribe_token(mailing_id, res_id, email, str(token)): + if not self._check_mailing_email_token(mailing_id, res_id, email, str(token)): raise exceptions.AccessDenied() if mailing.mailing_model_real == 'mailing.contact': @@ -48,7 +48,7 @@ class MassMailController(http.Controller): unique_list_ids = set([list.list_id.id for list in subscription_list_ids]) list_ids = request.env['mailing.list'].sudo().browse(unique_list_ids) unsubscribed_list = ', '.join(str(list.name) for list in mailing.contact_list_ids if list.is_public) - return request.render('mass_mailing.page_unsubscribe', { + return request.render('mass_mailing.page_mailing_unsubscribe', { 'contacts': contacts, 'list_ids': list_ids, 'opt_out_list_ids': opt_out_list_ids, @@ -72,7 +72,7 @@ class MassMailController(http.Controller): ) _blacklist_rec = request.env['mail.blacklist'].sudo()._add(email, message=message) - return request.render('mass_mailing.page_unsubscribed', { + return request.render('mass_mailing.page_mailing_unsubscribe_done', { 'email': email, 'mailing_id': mailing_id, 'res_id': res_id, @@ -83,10 +83,10 @@ class MassMailController(http.Controller): return request.redirect('/web') @http.route('/mail/mailing/unsubscribe', type='json', auth='public') - def unsubscribe(self, mailing_id, opt_in_ids, opt_out_ids, email, res_id, token): + def mailing_update_list_subscription(self, mailing_id, opt_in_ids, opt_out_ids, email, res_id, token): mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) if mailing.exists(): - if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): + if not self._check_mailing_email_token(mailing_id, res_id, email, token): return 'unauthorized' mailing.update_opt_out(email, opt_in_ids, False) mailing.update_opt_out(email, opt_out_ids, True) @@ -94,10 +94,10 @@ class MassMailController(http.Controller): return 'error' @http.route('/mailing/feedback', type='json', auth='public') - def send_feedback(self, mailing_id, res_id, email, feedback, token): + def mailing_send_feedback(self, mailing_id, res_id, email, feedback, token): mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) if mailing.exists() and email: - if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): + if not self._check_mailing_email_token(mailing_id, res_id, email, token): return 'unauthorized' model = request.env[mailing.mailing_model_real] records = model.sudo().search([('email_normalized', '=', tools.email_normalize(email))]) @@ -107,7 +107,7 @@ class MassMailController(http.Controller): return 'error' @http.route(['/unsubscribe_from_list'], type='http', website=True, multilang=False, auth='public', sitemap=False) - def unsubscribe_placeholder_link(self, **post): + def mailing_unsubscribe_placeholder_link(self, **post): """Dummy route so placeholder is not prefixed by language, MUST have multilang=False""" raise werkzeug.exceptions.NotFound() @@ -147,7 +147,7 @@ class MassMailController(http.Controller): # ------------------------------------------------------------ @http.route('/mailing/report/unsubscribe', type='http', website=True, auth='public') - def turn_off_mailing_reports(self, token, user_id): + def mailing_report_deactivate(self, token, user_id): if not token or not user_id: raise werkzeug.exceptions.NotFound() user_id = int(user_id) @@ -162,11 +162,11 @@ class MassMailController(http.Controller): raise werkzeug.exceptions.NotFound() @http.route(['/mailing//view'], type='http', website=True, auth='public') - def view(self, mailing_id, email=None, res_id=None, token=""): + def mailing_view_in_browser(self, mailing_id, email=None, res_id=None, token=""): mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) if mailing.exists(): res_id = int(res_id) if res_id else False - if not self._valid_unsubscribe_token(mailing_id, res_id, email, str(token)) and not request.env.user.has_group('mass_mailing.group_mass_mailing_user'): + if not self._check_mailing_email_token(mailing_id, res_id, email, str(token)) and not request.env.user.has_group('mass_mailing.group_mass_mailing_user'): raise exceptions.AccessDenied() # do not force lang, will simply use user context @@ -180,7 +180,7 @@ class MassMailController(http.Controller): html_markupsafe = html_markupsafe.replace('/unsubscribe_from_list', mailing._get_unsubscribe_url(email, res_id)) - return request.render('mass_mailing.view', { + return request.render('mass_mailing.mailing_view', { 'body': html_markupsafe, }) @@ -191,8 +191,8 @@ class MassMailController(http.Controller): # ------------------------------------------------------------ @http.route('/mailing/blacklist/check', type='json', auth='public') - def blacklist_check(self, mailing_id, res_id, email, token): - if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): + def mail_blacklist_check(self, mailing_id, res_id, email, token): + if not self._check_mailing_email_token(mailing_id, res_id, email, token): return 'unauthorized' if email: record = request.env['mail.blacklist'].sudo().with_context(active_test=False).search([('email', '=', tools.email_normalize(email))]) @@ -202,8 +202,8 @@ class MassMailController(http.Controller): return 'error' @http.route('/mailing/blacklist/add', type='json', auth='public') - def blacklist_add(self, mailing_id, res_id, email, token): - if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): + def mail_blacklist_add(self, mailing_id, res_id, email, token): + if not self._check_mailing_email_token(mailing_id, res_id, email, token): return 'unauthorized' if email: if mailing_id and res_id: @@ -222,8 +222,8 @@ class MassMailController(http.Controller): return 'error' @http.route('/mailing/blacklist/remove', type='json', auth='public') - def blacklist_remove(self, mailing_id, res_id, email, token): - if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): + def mail_blacklist_remove(self, mailing_id, res_id, email, token): + if not self._check_mailing_email_token(mailing_id, res_id, email, token): return 'unauthorized' if email: if mailing_id and res_id: diff --git a/addons/mass_mailing/views/mailing_templates_portal_management.xml b/addons/mass_mailing/views/mailing_templates_portal_management.xml index 43b141f3a8b..cd8ca143bdd 100644 --- a/addons/mass_mailing/views/mailing_templates_portal_management.xml +++ b/addons/mass_mailing/views/mailing_templates_portal_management.xml @@ -25,7 +25,7 @@ -