From 19b02759caeef4af275ac683194ae7f8dd8e3113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 23 May 2022 07:57:31 +0000 Subject: [PATCH 1/4] [LNT] mass_mailing(_sms): perform various linting PURPOSE Reorganize addon according to guidelines, helping finding and updating code. SPECIFICATIONS Perform various code linting and cleanups, line breaks, linter issues... No code or feature change should occur with this commit. Task-2864264 (Mass Mailing Module Reorganization) Part-of: odoo/odoo#92509 --- addons/mass_mailing/models/mailing.py | 191 ++++++++++-------- addons/mass_mailing/models/mailing_contact.py | 26 ++- addons/mass_mailing/models/mailing_list.py | 16 +- .../models/res_config_settings.py | 26 ++- .../models/mailing_mailing.py | 18 +- 5 files changed, 167 insertions(+), 110 deletions(-) diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 8bd8b75c6ed..70c515902c3 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -30,7 +30,11 @@ class MassMailing(models.Model): A mass mailing is an occurence of sending emails. """ _name = 'mailing.mailing' _description = 'Mass Mailing' - _inherit = ['mail.thread', 'mail.activity.mixin', 'mail.render.mixin', 'utm.source.mixin'] + _inherit = ['mail.thread', + 'mail.activity.mixin', + 'mail.render.mixin', + 'utm.source.mixin' + ] _order = 'calendar_date DESC' _rec_name = "subject" @@ -65,67 +69,93 @@ class MassMailing(models.Model): return False active = fields.Boolean(default=True, tracking=True) - subject = fields.Char('Subject', help='Subject of your Mailing', required=True, translate=False) + subject = fields.Char( + 'Subject', help='Subject of your Mailing', + required=True, translate=False) preview = fields.Char( 'Preview', translate=False, help='Catchy preview sentence that encourages recipients to open this email.\n' 'In most inboxes, this is displayed next to the subject.\n' 'Keep it empty if you prefer the first characters of your email content to appear instead.') - email_from = fields.Char(string='Send From', required=True, store=True, readonly=False, compute='_compute_email_from', - default=lambda self: self.env.user.email_formatted) + email_from = fields.Char( + string='Send From', + compute='_compute_email_from', readonly=False, required=True, store=True, + default=lambda self: self.env.user.email_formatted) favorite = fields.Boolean('Favorite', copy=False, tracking=True) - favorite_date = fields.Datetime('Favorite Date', help='When this mailing was added in the favorites', - store=True, copy=False, compute='_compute_favorite_date') + favorite_date = fields.Datetime( + 'Favorite Date', + compute='_compute_favorite_date', store=True, + copy=False, + help='When this mailing was added in the favorites') sent_date = fields.Datetime(string='Sent Date', copy=False) - - schedule_type = fields.Selection([('now', 'Send now'), ('scheduled', 'Send on')], string='Schedule', - default='now', required=True, readonly=True, - states={'draft': [('readonly', False)], 'in_queue': [('readonly', False)]}) - schedule_date = fields.Datetime(string='Scheduled for', tracking=True, readonly=True, - states={'draft': [('readonly', False)], 'in_queue': [('readonly', False)]}, - compute='_compute_schedule_date', store=True, copy=True) - calendar_date = fields.Datetime('Calendar Date', compute='_compute_calendar_date', store=True, copy=False, + schedule_type = fields.Selection( + [('now', 'Send now'), ('scheduled', 'Send on')], + string='Schedule', default='now', + readonly=True, required=True, + states={'draft': [('readonly', False)], 'in_queue': [('readonly', False)]}) + schedule_date = fields.Datetime( + string='Scheduled for', + compute='_compute_schedule_date', readonly=True, store=True, + copy=True, tracking=True, + states={'draft': [('readonly', False)], 'in_queue': [('readonly', False)]}) + calendar_date = fields.Datetime( + 'Calendar Date', + compute='_compute_calendar_date', store=True, + copy=False, help="Date at which the mailing was or will be sent.") # don't translate 'body_arch', the translations are only on 'body_html' body_arch = fields.Html(string='Body', translate=False, sanitize=False) body_html = fields.Html(string='Body converted to be sent by mail', render_engine='qweb', sanitize=False) is_body_empty = fields.Boolean(compute="_compute_is_body_empty", help='Technical field used to determine if the mail body is empty') - attachment_ids = fields.Many2many('ir.attachment', 'mass_mailing_ir_attachments_rel', + attachment_ids = fields.Many2many( + 'ir.attachment', 'mass_mailing_ir_attachments_rel', 'mass_mailing_id', 'attachment_id', string='Attachments') keep_archives = fields.Boolean(string='Keep Archives') campaign_id = fields.Many2one('utm.campaign', string='UTM Campaign', index=True, ondelete='set null') medium_id = fields.Many2one( 'utm.medium', string='Medium', - compute='_compute_medium_id', readonly=False, store=True, ondelete='restrict', + compute='_compute_medium_id', readonly=False, store=True, + ondelete='restrict', help="UTM Medium: delivery method (email, sms, ...)") - state = fields.Selection([('draft', 'Draft'), ('in_queue', 'In Queue'), ('sending', 'Sending'), ('done', 'Sent')], - string='Status', required=True, tracking=True, copy=False, default='draft', group_expand='_group_expand_states') + state = fields.Selection( + [('draft', 'Draft'), ('in_queue', 'In Queue'), + ('sending', 'Sending'), ('done', 'Sent')], + string='Status', + default='draft', required=True, + copy=False, tracking=True, + group_expand='_group_expand_states') color = fields.Integer(string='Color Index') - user_id = fields.Many2one('res.users', string='Responsible', tracking=True, default=lambda self: self.env.user) + user_id = fields.Many2one( + 'res.users', string='Responsible', + tracking=True, + default=lambda self: self.env.user) # mailing options mailing_type = fields.Selection([('mail', 'Email')], string="Mailing Type", default="mail", required=True) mailing_type_description = fields.Char('Mailing Type Description', compute="_compute_mailing_type_description") - reply_to_mode = fields.Selection([ - ('update', 'Recipient Followers'), ('new', 'Specified Email Address')], - string='Reply-To Mode', compute='_compute_reply_to_mode', - readonly=False, store=True, + reply_to_mode = fields.Selection( + [('update', 'Recipient Followers'), ('new', 'Specified Email Address')], + string='Reply-To Mode', + compute='_compute_reply_to_mode', readonly=False, store=True, help='Thread: replies go to target document. Email: replies are routed to a given email.') reply_to = fields.Char( - string='Reply To', compute='_compute_reply_to', readonly=False, store=True, + string='Reply To', + compute='_compute_reply_to', readonly=False, store=True, help='Preferred Reply-To Address') # recipients - mailing_model_real = fields.Char(string='Recipients Real Model', compute='_compute_mailing_model_real') + mailing_model_real = fields.Char( + string='Recipients Real Model', compute='_compute_mailing_model_real') mailing_model_id = fields.Many2one( - 'ir.model', string='Recipients Model', ondelete='cascade', required=True, + 'ir.model', string='Recipients Model', + ondelete='cascade', required=True, domain=[('is_mailing_enabled', '=', True)], default=lambda self: self.env.ref('mass_mailing.model_mailing_list').id) mailing_model_name = fields.Char( - string='Recipients Model Name', related='mailing_model_id.model', - readonly=True, related_sudo=True) + string='Recipients Model Name', + related='mailing_model_id.model', readonly=True, related_sudo=True) mailing_domain = fields.Char( - string='Domain', compute='_compute_mailing_domain', - readonly=False, store=True) + string='Domain', + compute='_compute_mailing_domain', readonly=False, store=True) mail_server_available = fields.Boolean( compute='_compute_mail_server_available', help="Technical field used to know if the user has activated the outgoing mail server option in the settings") @@ -136,25 +166,30 @@ class MassMailing(models.Model): # Mailing Filter mailing_filter_id = fields.Many2one( 'mailing.filter', string='Favorite Filter', - domain="[('mailing_model_name', '=', mailing_model_name)]", - compute='_compute_mailing_filter_id', readonly=False, store=True) + compute='_compute_mailing_filter_id', readonly=False, store=True, + domain="[('mailing_model_name', '=', mailing_model_name)]") mailing_filter_domain = fields.Char('Favorite filter domain', related='mailing_filter_id.mailing_domain') mailing_filter_count = fields.Integer('# Favorite Filters', compute='_compute_mailing_filter_count') # A/B Testing ab_testing_completed = fields.Boolean(related='campaign_id.ab_testing_completed', store=True) ab_testing_description = fields.Html('A/B Testing Description', compute="_compute_ab_testing_description") - ab_testing_enabled = fields.Boolean(string='Allow A/B Testing', default=False, + ab_testing_enabled = fields.Boolean( + string='Allow A/B Testing', default=False, help='If checked, recipients will be mailed only once for the whole campaign. ' 'This lets you send different mailings to randomly selected recipients and test ' 'the effectiveness of the mailings, without causing duplicate messages.') ab_testing_mailings_count = fields.Integer(related="campaign_id.ab_testing_mailings_count") - ab_testing_pc = fields.Integer(string='A/B Testing percentage', - help='Percentage of the contacts that will be mailed. Recipients will be chosen randomly.', default=10) - ab_testing_schedule_datetime = fields.Datetime(related="campaign_id.ab_testing_schedule_datetime", readonly=False, + ab_testing_pc = fields.Integer( + string='A/B Testing percentage', + default=10, + help='Percentage of the contacts that will be mailed. Recipients will be chosen randomly.') + ab_testing_schedule_datetime = fields.Datetime( + related="campaign_id.ab_testing_schedule_datetime", readonly=False, default=lambda self: fields.Datetime.now() + relativedelta(days=1)) - ab_testing_winner_selection = fields.Selection(related="campaign_id.ab_testing_winner_selection", - default="opened_ratio", readonly=False, copy=True) - + ab_testing_winner_selection = fields.Selection( + related="campaign_id.ab_testing_winner_selection", readonly=False, + default="opened_ratio", + copy=True) kpi_mail_required = fields.Boolean('KPI mail required', copy=False) # statistics data mailing_trace_ids = fields.One2many('mailing.trace', 'mass_mailing_id', string='Emails Statistics') @@ -345,7 +380,7 @@ class MassMailing(models.Model): @api.depends('mailing_model_id') def _compute_mailing_model_real(self): for mailing in self: - mailing.mailing_model_real = (mailing.mailing_model_id.model != 'mailing.list') and mailing.mailing_model_id.model or 'mailing.contact' + 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', 'contact_list_ids', 'mailing_type', 'mailing_filter_id') def _compute_mailing_domain(self): @@ -552,10 +587,9 @@ class MassMailing(models.Model): self.ensure_one() if self.schedule_date and self.schedule_date > fields.Datetime.now(): return self.action_put_in_queue() - else: - action = self.env["ir.actions.actions"]._for_xml_id("mass_mailing.mailing_mailing_schedule_date_action") - action['context'] = dict(self.env.context, default_mass_mailing_id=self.id) - return action + action = self.env["ir.actions.actions"]._for_xml_id("mass_mailing.mailing_mailing_schedule_date_action") + action['context'] = dict(self.env.context, default_mass_mailing_id=self.id) + return action def action_put_in_queue(self): self.write({'state': 'in_queue'}) @@ -684,6 +718,37 @@ class MassMailing(models.Model): action['domain'] = [('list_ids', 'in', self.contact_list_ids.ids)] return action + @api.model + def action_fetch_favorites(self, extra_domain=None): + """Return all mailings set as favorite and skip mailings with empty body. + + Return archived mailing templates as well, so the user can archive the templates + while keeping using it, without cluttering the Kanban view if they're a lot of + templates. + """ + domain = [('favorite', '=', True)] + if extra_domain: + domain = expression.AND([domain, extra_domain]) + + values_list = self.with_context(active_test=False).search_read( + domain=domain, + fields=['id', 'subject', 'body_arch', 'user_id', 'mailing_model_id'], + order='favorite_date DESC', + ) + + values_list = [ + values for values in values_list + if not tools.is_html_empty(values['body_arch']) + ] + + # You see first the mailings without responsible, then your mailings and then the others + values_list.sort( + key=lambda values: + values['user_id'][0] != self.env.user.id if values['user_id'] else -1 + ) + + return values_list + def update_opt_out(self, email, list_ids, value): if len(list_ids) > 0: model = self.env['mailing.contact'].with_context(active_test=False) @@ -1173,8 +1238,8 @@ class MassMailing(models.Model): kpi, { 'kpi_fullname': _('Business Benefits on %(expected)i %(mailing_type)s Sent', - expected=self.expected, - mailing_type=mailing_type + expected=self.expected, + mailing_type=mailing_type ), 'kpi_action': None, 'kpi_col1': {}, @@ -1188,8 +1253,7 @@ class MassMailing(models.Model): } def _get_pretty_mailing_type(self): - if self.mailing_type == 'mail': - return _('Emails') + return _('Emails') def _get_unsubscribe_token(self, user_id): """Generate a secure hash for this user. It allows to opt out from @@ -1268,34 +1332,3 @@ class MassMailing(models.Model): return lxml.html.tostring(root, encoding='unicode') return body_html - - @api.model - def action_fetch_favorites(self, extra_domain=None): - """Return all mailings set as favorite and skip mailings with empty body. - - Return archived mailing templates as well, so the user can archive the templates - while keeping using it, without cluttering the Kanban view if they're a lot of - templates. - """ - domain = [('favorite', '=', True)] - if extra_domain: - domain = expression.AND([domain, extra_domain]) - - values_list = self.with_context(active_test=False).search_read( - domain=domain, - fields=['id', 'subject', 'body_arch', 'user_id', 'mailing_model_id'], - order='favorite_date DESC', - ) - - values_list = [ - values for values in values_list - if not tools.is_html_empty(values['body_arch']) - ] - - # You see first the mailings without responsible, then your mailings and then the others - values_list.sort( - key=lambda values: - values['user_id'][0] != self.env.user.id if values['user_id'] else -1 - ) - - return values_list diff --git a/addons/mass_mailing/models/mailing_contact.py b/addons/mass_mailing/models/mailing_contact.py index e45086330d2..717019aa886 100644 --- a/addons/mass_mailing/models/mailing_contact.py +++ b/addons/mass_mailing/models/mailing_contact.py @@ -18,8 +18,10 @@ class MassMailingContactListRel(models.Model): contact_id = fields.Many2one('mailing.contact', string='Contact', ondelete='cascade', required=True) list_id = fields.Many2one('mailing.list', string='Mailing List', ondelete='cascade', required=True) - opt_out = fields.Boolean(string='Opt Out', - help='The contact has chosen not to receive mails anymore from this list', default=False) + opt_out = fields.Boolean( + string='Opt Out', + default=False, + help='The contact has chosen not to receive mails anymore from this list') unsubscription_date = fields.Datetime(string='Unsubscription Date') message_bounce = fields.Integer(related='contact_id.message_bounce', store=False, readonly=False) is_blacklisted = fields.Boolean(related='contact_id.is_blacklisted', store=False, readonly=False) @@ -58,12 +60,12 @@ class MassMailingContact(models.Model): _order = 'email' _mailing_enabled = True - def default_get(self, fields): + def default_get(self, fields_list): """ When coming from a mailing list we may have a default_list_ids context key. We should use it to create subscription_list_ids default value that are displayed to the user as list_ids is not displayed on form view. """ - res = super(MassMailingContact, self).default_get(fields) - if 'subscription_list_ids' in fields and not res.get('subscription_list_ids'): + res = super(MassMailingContact, self).default_get(fields_list) + if 'subscription_list_ids' in fields_list and not res.get('subscription_list_ids'): list_ids = self.env.context.get('default_list_ids') if 'default_list_ids' not in res and list_ids and isinstance(list_ids, (list, tuple)): res['subscription_list_ids'] = [ @@ -77,12 +79,15 @@ class MassMailingContact(models.Model): list_ids = fields.Many2many( 'mailing.list', 'mailing_contact_list_rel', 'contact_id', 'list_id', string='Mailing Lists') - subscription_list_ids = fields.One2many('mailing.contact.subscription', 'contact_id', string='Subscription Information') + subscription_list_ids = fields.One2many( + 'mailing.contact.subscription', 'contact_id', string='Subscription Information') country_id = fields.Many2one('res.country', string='Country') tag_ids = fields.Many2many('res.partner.category', string='Tags') - opt_out = fields.Boolean('Opt Out', compute='_compute_opt_out', search='_search_opt_out', - help='Opt out flag for a specific mailing list.' - 'This field should not be used in a view without a unique and active mailing list context.') + opt_out = fields.Boolean( + 'Opt Out', + compute='_compute_opt_out', search='_search_opt_out', + help='Opt out flag for a specific mailing list. ' + 'This field should not be used in a view without a unique and active mailing list context.') @api.model def _search_opt_out(self, operator, value): @@ -97,8 +102,7 @@ class MassMailingContact(models.Model): [active_list_id] = self._context['default_list_ids'] contacts = self.env['mailing.contact.subscription'].search([('list_id', '=', active_list_id)]) return [('id', 'in', [record.contact_id.id for record in contacts if record.opt_out == value])] - else: - return expression.FALSE_DOMAIN if value else expression.TRUE_DOMAIN + return expression.FALSE_DOMAIN if value else expression.TRUE_DOMAIN @api.depends('subscription_list_ids') @api.depends_context('default_list_ids') diff --git a/addons/mass_mailing/models/mailing_list.py b/addons/mass_mailing/models/mailing_list.py index 2cfbb74bd38..79dc5ad255b 100644 --- a/addons/mass_mailing/models/mailing_list.py +++ b/addons/mass_mailing/models/mailing_list.py @@ -28,13 +28,17 @@ class MassMailingList(models.Model): 'mailing.contact', 'mailing_contact_list_rel', 'list_id', 'contact_id', string='Mailing Lists', copy=False) mailing_count = fields.Integer(compute="_compute_mailing_list_count", string="Number of Mailing") - mailing_ids = fields.Many2many('mailing.mailing', 'mail_mass_mailing_list_rel', string='Mass Mailings', copy=False) + mailing_ids = fields.Many2many( + 'mailing.mailing', 'mail_mass_mailing_list_rel', + string='Mass Mailings', copy=False) subscription_ids = fields.One2many( - 'mailing.contact.subscription', 'list_id', string='Subscription Information', + 'mailing.contact.subscription', 'list_id', + string='Subscription Information', copy=True, depends=['contact_ids']) - is_public = fields.Boolean(default=True, string='Show In Preferences', - help='The mailing list can be accessible by recipient in the unsubscription' - ' page to allows them to update their subscription preferences.') + is_public = fields.Boolean( + string='Show In Preferences', default=True, + help='The mailing list can be accessible by recipients in the subscription ' + 'management page to allows them to update their preferences.') # ------------------------------------------------------ # COMPUTE / ONCHANGE @@ -318,7 +322,7 @@ class MassMailingList(models.Model): if mass_mailing.id not in contact_counts: contact_counts[mass_mailing.id] = { field: 0 - for field in self._get_contact_statistics_fields().keys() + for field in mass_mailing._get_contact_statistics_fields() } return contact_counts diff --git a/addons/mass_mailing/models/res_config_settings.py b/addons/mass_mailing/models/res_config_settings.py index b4a0e41ccbe..71611acf8f0 100644 --- a/addons/mass_mailing/models/res_config_settings.py +++ b/addons/mass_mailing/models/res_config_settings.py @@ -7,15 +7,25 @@ from odoo import api, fields, models class ResConfigSettings(models.TransientModel): _inherit = 'res.config.settings' - group_mass_mailing_campaign = fields.Boolean(string="Mailing Campaigns", implied_group='mass_mailing.group_mass_mailing_campaign', help="""This is useful if your marketing campaigns are composed of several emails""") - mass_mailing_outgoing_mail_server = fields.Boolean(string="Dedicated Server", config_parameter='mass_mailing.outgoing_mail_server', + group_mass_mailing_campaign = fields.Boolean( + string="Mailing Campaigns", + implied_group='mass_mailing.group_mass_mailing_campaign', + help="""This is useful if your marketing campaigns are composed of several emails""") + mass_mailing_outgoing_mail_server = fields.Boolean( + string="Dedicated Server", + config_parameter='mass_mailing.outgoing_mail_server', help='Use a specific mail server in priority. Otherwise Odoo relies on the first outgoing mail server available (based on their sequencing) as it does for normal mails.') - mass_mailing_mail_server_id = fields.Many2one('ir.mail_server', string='Mail Server', config_parameter='mass_mailing.mail_server_id') - show_blacklist_buttons = fields.Boolean(string="Blacklist Option when Unsubscribing", - config_parameter='mass_mailing.show_blacklist_buttons', - help="""Allow the recipient to manage themselves their state in the blacklist via the unsubscription page.""") - mass_mailing_reports = fields.Boolean(string='24H Stat Mailing Reports', config_parameter='mass_mailing.mass_mailing_reports', - help='Check how well your mailing is doing a day after it has been sent.') + mass_mailing_mail_server_id = fields.Many2one( + 'ir.mail_server', string='Mail Server', + config_parameter='mass_mailing.mail_server_id') + show_blacklist_buttons = fields.Boolean( + string="Blacklist Option when Unsubscribing", + config_parameter='mass_mailing.show_blacklist_buttons', + help="""Allow the recipient to manage themselves their state in the blacklist via the unsubscription page.""") + mass_mailing_reports = fields.Boolean( + string='24H Stat Mailing Reports', + config_parameter='mass_mailing.mass_mailing_reports', + help='Check how well your mailing is doing a day after it has been sent.') @api.onchange('mass_mailing_outgoing_mail_server') def _onchange_mass_mailing_outgoing_mail_server(self): diff --git a/addons/mass_mailing_sms/models/mailing_mailing.py b/addons/mass_mailing_sms/models/mailing_mailing.py index 716437347cb..cd4a5a02d94 100644 --- a/addons/mass_mailing_sms/models/mailing_mailing.py +++ b/addons/mass_mailing_sms/models/mailing_mailing.py @@ -30,11 +30,15 @@ class Mailing(models.Model): # otherwise 'sms_subject' will get the old helper from 'mass_mailing' module. # overriding 'subject' field helper in this model is not working, since the helper will keep the new value # even when 'mass_mailing_sms' removed (see 'mailing_mailing_view_form_sms' for more details). - sms_subject = fields.Char('Title', help='For an email, the subject your recipients will see in their inbox.\n' - 'For an SMS, the internal title of the message.', - related='subject', translate=False, readonly=False) + sms_subject = fields.Char( + 'Title', related='subject', + readonly=False, translate=False, + help='For an email, the subject your recipients will see in their inbox.\n' + 'For an SMS, the internal title of the message.') # sms options - body_plaintext = fields.Text('SMS Body', compute='_compute_body_plaintext', store=True, readonly=False) + body_plaintext = fields.Text( + 'SMS Body', compute='_compute_body_plaintext', + store=True, readonly=False) sms_template_id = fields.Many2one('sms.template', string='SMS Template', ondelete='set null') sms_has_insufficient_credit = fields.Boolean( 'Insufficient IAP credits', compute='_compute_sms_has_iap_failure', @@ -47,7 +51,9 @@ class Mailing(models.Model): # opt_out_link sms_allow_unsubscribe = fields.Boolean('Include opt-out link', default=False) # A/B Testing - ab_testing_sms_winner_selection = fields.Selection(related="campaign_id.ab_testing_sms_winner_selection", default="clicks_ratio", readonly=False, copy=True) + ab_testing_sms_winner_selection = fields.Selection( + related="campaign_id.ab_testing_sms_winner_selection", + default="clicks_ratio", readonly=False, copy=True) @api.depends('mailing_type') def _compute_medium_id(self): @@ -78,7 +84,7 @@ class Mailing(models.Model): trace_dict = dict.fromkeys(self.ids, {key: False for key in failures}) for t in traces: - trace_dict[t['mass_mailing_id'][0]][t['failure_type']] = t['__count'] and True or False + trace_dict[t['mass_mailing_id'][0]][t['failure_type']] = bool(t['__count']) for mail in self: mail.sms_has_insufficient_credit = trace_dict[mail.id]['sms_credit'] From c617923664371953574bf09ab49fad0a526acbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 24 May 2022 13:32:55 +0000 Subject: [PATCH 2/4] [MOV][FIX] mass_mailing: reorganize data and models, remove duplicated data PURPOSE Reorganize addon according to guidelines, helping finding and updating code. SPECIFICATIONS Correctly split data into separate files. A lot of content was put a bit randomly in data files, leading to a hard discovery of code and features. We also fix duplicated attachments definition, both in mass_mailing_data and ir_attachment files. It has been merged into the attachment data file. Task-2864264 (Mass Mailing Module Reorganization) Part-of: odoo/odoo#92509 --- addons/mass_mailing/__manifest__.py | 11 +- .../mass_mailing/data/ir_attachment_data.xml | 50 +++- .../data/ir_config_parameter_data.xml | 9 + addons/mass_mailing/data/ir_cron_data.xml | 29 +++ addons/mass_mailing/data/ir_module_data.xml | 10 + addons/mass_mailing/data/mail_data.xml | 23 -- .../data/mailing_data_templates.xml | 87 +++++++ .../mass_mailing/data/mailing_list_data.xml | 13 + .../mass_mailing/data/mass_mailing_data.xml | 226 ------------------ addons/mass_mailing/data/res_users_data.xml | 8 + ...iling_security.xml => res_groups_data.xml} | 10 - addons/mass_mailing/views/assets.xml | 67 +----- 12 files changed, 213 insertions(+), 330 deletions(-) create mode 100644 addons/mass_mailing/data/ir_config_parameter_data.xml create mode 100644 addons/mass_mailing/data/ir_cron_data.xml create mode 100644 addons/mass_mailing/data/ir_module_data.xml delete mode 100644 addons/mass_mailing/data/mail_data.xml create mode 100644 addons/mass_mailing/data/mailing_list_data.xml delete mode 100644 addons/mass_mailing/data/mass_mailing_data.xml create mode 100644 addons/mass_mailing/data/res_users_data.xml rename addons/mass_mailing/security/{mass_mailing_security.xml => res_groups_data.xml} (66%) diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index 8c50e471297..b9ec211e7d0 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -20,13 +20,16 @@ 'digest', ], 'data': [ - 'security/mass_mailing_security.xml', + 'security/res_groups_data.xml', 'security/ir.model.access.csv', 'data/digest_data.xml', - 'data/mail_data.xml', - 'data/mailing_data_templates.xml', - 'data/mass_mailing_data.xml', 'data/ir_attachment_data.xml', + 'data/ir_config_parameter_data.xml', + 'data/ir_cron_data.xml', + 'data/ir_module_data.xml', + 'data/mailing_data_templates.xml', + 'data/mailing_list_data.xml', + 'data/res_users_data.xml', 'wizard/mail_compose_message_views.xml', 'wizard/mailing_contact_import_views.xml', 'wizard/mailing_contact_to_list_views.xml', diff --git a/addons/mass_mailing/data/ir_attachment_data.xml b/addons/mass_mailing/data/ir_attachment_data.xml index 65cc4ab2de4..a50944cde51 100644 --- a/addons/mass_mailing/data/ir_attachment_data.xml +++ b/addons/mass_mailing/data/ir_attachment_data.xml @@ -1,7 +1,13 @@ - + + + + s_cover_default_image.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_banner.jpg + s_media_list_default_image_1.jpg @@ -128,6 +134,18 @@ url /mass_mailing/static/src/img/snippets_demo/s_blockquote_cover.jpg + + + s_image_text_default_image.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_image_text.jpg + + + + s_mail_block_event_default_image.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_event.jpg + s_masonry_block_default_image_1.jpg @@ -140,5 +158,35 @@ url /mass_mailing/static/src/img/snippets_demo/s_cover.jpg + + + s_picture_default_image.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_image.jpg + + + + s_text_image_default_image.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_text_image.jpg + + + + s_three_columns_default_image_1.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_three_cols_1.jpg + + + + s_three_columns_default_image_2.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_three_cols_2.jpg + + + + s_three_columns_default_image_3.jpg + url + /mass_mailing/static/src/img/theme_default/s_default_image_block_three_cols_3.jpg + diff --git a/addons/mass_mailing/data/ir_config_parameter_data.xml b/addons/mass_mailing/data/ir_config_parameter_data.xml new file mode 100644 index 00000000000..531c0854ad9 --- /dev/null +++ b/addons/mass_mailing/data/ir_config_parameter_data.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/addons/mass_mailing/data/ir_cron_data.xml b/addons/mass_mailing/data/ir_cron_data.xml new file mode 100644 index 00000000000..c83a2387daf --- /dev/null +++ b/addons/mass_mailing/data/ir_cron_data.xml @@ -0,0 +1,29 @@ + + + + + + Mail Marketing: Process queue + + code + model._process_mass_mailing_queue() + + 1 + days + -1 + + + + + Mail Marketing: A/B Testing + + code + model._cron_process_mass_mailing_ab_testing() + + 1 + days + -1 + + + + diff --git a/addons/mass_mailing/data/ir_module_data.xml b/addons/mass_mailing/data/ir_module_data.xml new file mode 100644 index 00000000000..ab373707f62 --- /dev/null +++ b/addons/mass_mailing/data/ir_module_data.xml @@ -0,0 +1,10 @@ + + + + + 19 + Helps you manage your mass mailing to design + professional emails and reuse templates. + + + diff --git a/addons/mass_mailing/data/mail_data.xml b/addons/mass_mailing/data/mail_data.xml deleted file mode 100644 index fada8fb3bc8..00000000000 --- a/addons/mass_mailing/data/mail_data.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - diff --git a/addons/mass_mailing/data/mailing_data_templates.xml b/addons/mass_mailing/data/mailing_data_templates.xml index a011ed4155a..d35942f293c 100644 --- a/addons/mass_mailing/data/mailing_data_templates.xml +++ b/addons/mass_mailing/data/mailing_data_templates.xml @@ -1,5 +1,92 @@ + + + + + + + - - - - + From 4f39a80e7619870fb7f7655823fa5eecc67936a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 24 May 2022 14:03:11 +0000 Subject: [PATCH 3/4] [MOV] mass_mailing(_sms): split models and views PURPOSE Reorganize addon according to guidelines, helping finding and updating code. SPECIFICATIONS Move subscription model into its own file, to ease future improvements. Do the same for its views. Also move menu entries into a specific file for menus, allowing to easily understand menu organization in mass mailing. A duplicated menu about link trackers in SMS is also removed. Task-2864264 (Mass Mailing Module Reorganization) Part-of: odoo/odoo#92509 --- addons/mass_mailing/__manifest__.py | 5 +- addons/mass_mailing/models/__init__.py | 1 + addons/mass_mailing/models/mailing_contact.py | 43 -------- .../models/mailing_contact_subscription.py | 47 ++++++++ .../report/mailing_trace_report_views.xml | 4 - .../mass_mailing/views/link_tracker_views.xml | 8 -- .../mailing_contact_subscription_views.xml | 53 +++++++++ .../views/mailing_contact_views.xml | 58 +--------- .../mass_mailing/views/mailing_list_views.xml | 4 - .../views/mailing_mailing_views.xml | 6 - .../views/mailing_mailing_views_menus.xml | 28 ----- addons/mass_mailing/views/mailing_menus.xml | 103 ++++++++++++++++++ .../views/mailing_trace_views.xml | 6 - .../views/res_config_settings_views.xml | 3 - .../mass_mailing/views/utm_campaign_views.xml | 16 --- addons/mass_mailing_sms/__manifest__.py | 5 +- .../report/mailing_trace_report_views.xml | 5 - .../views/link_tracker_views.xml | 8 -- .../views/mailing_contact_views.xml | 6 - .../views/mailing_list_views.xml | 5 - .../views/mailing_mailing_views.xml | 5 - .../views/mailing_sms_menus.xml | 16 ++- .../views/utm_campaign_views.xml | 5 - 23 files changed, 224 insertions(+), 216 deletions(-) create mode 100644 addons/mass_mailing/models/mailing_contact_subscription.py create mode 100644 addons/mass_mailing/views/mailing_contact_subscription_views.xml delete mode 100644 addons/mass_mailing/views/mailing_mailing_views_menus.xml create mode 100644 addons/mass_mailing/views/mailing_menus.xml delete mode 100644 addons/mass_mailing_sms/views/link_tracker_views.xml diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index b9ec211e7d0..9580bce45b9 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -36,16 +36,17 @@ 'wizard/mailing_list_merge_views.xml', 'wizard/mailing_mailing_test_views.xml', 'wizard/mailing_mailing_schedule_date_views.xml', + 'report/mailing_trace_report_views.xml', 'views/mailing_filter_views.xml', - 'views/mailing_mailing_views_menus.xml', 'views/mailing_trace_views.xml', 'views/link_tracker_views.xml', 'views/mailing_contact_views.xml', + 'views/mailing_contact_subscription_views.xml', 'views/mailing_list_views.xml', 'views/mailing_mailing_views.xml', 'views/res_config_settings_views.xml', 'views/utm_campaign_views.xml', - 'report/mailing_trace_report_views.xml', + 'views/mailing_menus.xml', 'views/assets.xml', 'views/mass_mailing_templates_portal.xml', 'views/themes_templates.xml', diff --git a/addons/mass_mailing/models/__init__.py b/addons/mass_mailing/models/__init__.py index 62a584ceda8..3ad476609b3 100644 --- a/addons/mass_mailing/models/__init__.py +++ b/addons/mass_mailing/models/__init__.py @@ -3,6 +3,7 @@ from . import ir_model from . import link_tracker +from . import mailing_contact_subscription from . import mailing_contact from . import mailing_list from . import mailing_trace diff --git a/addons/mass_mailing/models/mailing_contact.py b/addons/mass_mailing/models/mailing_contact.py index 717019aa886..1fa42ad9135 100644 --- a/addons/mass_mailing/models/mailing_contact.py +++ b/addons/mass_mailing/models/mailing_contact.py @@ -6,49 +6,6 @@ from odoo.exceptions import UserError from odoo.osv import expression -class MassMailingContactListRel(models.Model): - """ Intermediate model between mass mailing list and mass mailing contact - Indicates if a contact is opted out for a particular list - """ - _name = 'mailing.contact.subscription' - _description = 'Mass Mailing Subscription Information' - _table = 'mailing_contact_list_rel' - _rec_name = 'contact_id' - _order = 'list_id DESC, contact_id DESC' - - contact_id = fields.Many2one('mailing.contact', string='Contact', ondelete='cascade', required=True) - list_id = fields.Many2one('mailing.list', string='Mailing List', ondelete='cascade', required=True) - opt_out = fields.Boolean( - string='Opt Out', - default=False, - help='The contact has chosen not to receive mails anymore from this list') - unsubscription_date = fields.Datetime(string='Unsubscription Date') - message_bounce = fields.Integer(related='contact_id.message_bounce', store=False, readonly=False) - is_blacklisted = fields.Boolean(related='contact_id.is_blacklisted', store=False, readonly=False) - - _sql_constraints = [ - ('unique_contact_list', 'unique (contact_id, list_id)', - 'A mailing contact cannot subscribe to the same mailing list multiple times.') - ] - - @api.model_create_multi - def create(self, vals_list): - now = fields.Datetime.now() - for vals in vals_list: - if 'opt_out' in vals and 'unsubscription_date' not in vals: - vals['unsubscription_date'] = now if vals['opt_out'] else False - if vals.get('unsubscription_date'): - vals['opt_out'] = True - return super().create(vals_list) - - def write(self, vals): - if 'opt_out' in vals and 'unsubscription_date' not in vals: - vals['unsubscription_date'] = fields.Datetime.now() if vals['opt_out'] else False - if vals.get('unsubscription_date'): - vals['opt_out'] = True - return super(MassMailingContactListRel, self).write(vals) - - class MassMailingContact(models.Model): """Model of a contact. This model is different from the partner model because it holds only some basic information: name, email. The purpose is to diff --git a/addons/mass_mailing/models/mailing_contact_subscription.py b/addons/mass_mailing/models/mailing_contact_subscription.py new file mode 100644 index 00000000000..c20c504587b --- /dev/null +++ b/addons/mass_mailing/models/mailing_contact_subscription.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class MassMailingContactListRel(models.Model): + """ Intermediate model between mass mailing list and mass mailing contact + Indicates if a contact is opted out for a particular list + """ + _name = 'mailing.contact.subscription' + _description = 'Mass Mailing Subscription Information' + _table = 'mailing_contact_list_rel' + _rec_name = 'contact_id' + _order = 'list_id DESC, contact_id DESC' + + contact_id = fields.Many2one('mailing.contact', string='Contact', ondelete='cascade', required=True) + list_id = fields.Many2one('mailing.list', string='Mailing List', ondelete='cascade', required=True) + opt_out = fields.Boolean( + string='Opt Out', + default=False, + help='The contact has chosen not to receive mails anymore from this list') + unsubscription_date = fields.Datetime(string='Unsubscription Date') + message_bounce = fields.Integer(related='contact_id.message_bounce', store=False, readonly=False) + is_blacklisted = fields.Boolean(related='contact_id.is_blacklisted', store=False, readonly=False) + + _sql_constraints = [ + ('unique_contact_list', 'unique (contact_id, list_id)', + 'A mailing contact cannot subscribe to the same mailing list multiple times.') + ] + + @api.model_create_multi + def create(self, vals_list): + now = fields.Datetime.now() + for vals in vals_list: + if 'opt_out' in vals and 'unsubscription_date' not in vals: + vals['unsubscription_date'] = now if vals['opt_out'] else False + if vals.get('unsubscription_date'): + vals['opt_out'] = True + return super().create(vals_list) + + def write(self, vals): + if 'opt_out' in vals and 'unsubscription_date' not in vals: + vals['unsubscription_date'] = fields.Datetime.now() if vals['opt_out'] else False + if vals.get('unsubscription_date'): + vals['opt_out'] = True + return super(MassMailingContactListRel, self).write(vals) diff --git a/addons/mass_mailing/report/mailing_trace_report_views.xml b/addons/mass_mailing/report/mailing_trace_report_views.xml index 464c9f09327..01b94169f32 100644 --- a/addons/mass_mailing/report/mailing_trace_report_views.xml +++ b/addons/mass_mailing/report/mailing_trace_report_views.xml @@ -95,8 +95,4 @@

- - diff --git a/addons/mass_mailing/views/link_tracker_views.xml b/addons/mass_mailing/views/link_tracker_views.xml index 615b4c27f24..ef227f04f75 100644 --- a/addons/mass_mailing/views/link_tracker_views.xml +++ b/addons/mass_mailing/views/link_tracker_views.xml @@ -78,12 +78,4 @@ - - - - diff --git a/addons/mass_mailing/views/mailing_contact_subscription_views.xml b/addons/mass_mailing/views/mailing_contact_subscription_views.xml new file mode 100644 index 00000000000..d59e92300f4 --- /dev/null +++ b/addons/mass_mailing/views/mailing_contact_subscription_views.xml @@ -0,0 +1,53 @@ + + + + mailing.contact.subscription.view.form + mailing.contact.subscription + 10 + +
+ + + + + + +
+
+
+ + + mailing.contact.subscription.view.tree + mailing.contact.subscription + + + + + + + + + + + + + mailing.contact.subscription.view.search + mailing.contact.subscription + + + + + + + + +
diff --git a/addons/mass_mailing/views/mailing_contact_views.xml b/addons/mass_mailing/views/mailing_contact_views.xml index 30a491b311d..a8ce9c32af7 100644 --- a/addons/mass_mailing/views/mailing_contact_views.xml +++ b/addons/mass_mailing/views/mailing_contact_views.xml @@ -1,58 +1,6 @@ - - - mailing.contact.subscription.view.form - mailing.contact.subscription - 10 - -
- - - - - - -
-
-
- - - mailing.contact.subscription.view.tree - mailing.contact.subscription - - - - - - - - - - - - - mailing.contact.subscription.view.search - mailing.contact.subscription - - - - - - - - - - + mailing.contact.view.search mailing.contact @@ -241,8 +189,4 @@

- -
diff --git a/addons/mass_mailing/views/mailing_list_views.xml b/addons/mass_mailing/views/mailing_list_views.xml index db3b5c34528..22de8850c81 100644 --- a/addons/mass_mailing/views/mailing_list_views.xml +++ b/addons/mass_mailing/views/mailing_list_views.xml @@ -293,8 +293,4 @@

- - diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index 7e8745fb0e2..8a755956fc3 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -718,10 +718,4 @@ mailing.mailing form - - - diff --git a/addons/mass_mailing/views/mailing_mailing_views_menus.xml b/addons/mass_mailing/views/mailing_mailing_views_menus.xml deleted file mode 100644 index db7aa2b7dc8..00000000000 --- a/addons/mass_mailing/views/mailing_mailing_views_menus.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/addons/mass_mailing/views/mailing_menus.xml b/addons/mass_mailing/views/mailing_menus.xml new file mode 100644 index 00000000000..20f92317129 --- /dev/null +++ b/addons/mass_mailing/views/mailing_menus.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/mass_mailing/views/mailing_trace_views.xml b/addons/mass_mailing/views/mailing_trace_views.xml index ec50f179d98..29de31fffc2 100644 --- a/addons/mass_mailing/views/mailing_trace_views.xml +++ b/addons/mass_mailing/views/mailing_trace_views.xml @@ -140,10 +140,4 @@

- - - diff --git a/addons/mass_mailing/views/res_config_settings_views.xml b/addons/mass_mailing/views/res_config_settings_views.xml index d3b8715b288..0ef06f24ac0 100644 --- a/addons/mass_mailing/views/res_config_settings_views.xml +++ b/addons/mass_mailing/views/res_config_settings_views.xml @@ -78,7 +78,4 @@ inline {'module' : 'mass_mailing', 'bin_size': False} - - diff --git a/addons/mass_mailing/views/utm_campaign_views.xml b/addons/mass_mailing/views/utm_campaign_views.xml index 8b01bc0f94f..b93eb906b05 100644 --- a/addons/mass_mailing/views/utm_campaign_views.xml +++ b/addons/mass_mailing/views/utm_campaign_views.xml @@ -111,20 +111,4 @@ [('is_auto_campaign', '=', False)] - - - - - - diff --git a/addons/mass_mailing_sms/__manifest__.py b/addons/mass_mailing_sms/__manifest__.py index 8346e4c4d77..80fbd96f4cf 100644 --- a/addons/mass_mailing_sms/__manifest__.py +++ b/addons/mass_mailing_sms/__manifest__.py @@ -15,15 +15,14 @@ 'data': [ 'data/utm_data.xml', 'security/ir.model.access.csv', - 'views/mailing_sms_menus.xml', + 'report/mailing_trace_report_views.xml', 'views/mailing_list_views.xml', 'views/mailing_contact_views.xml', 'views/mailing_trace_views.xml', 'views/mailing_mailing_views.xml', - 'views/link_tracker_views.xml', 'views/mass_mailing_sms_templates_portal.xml', 'views/utm_campaign_views.xml', - 'report/mailing_trace_report_views.xml', + 'views/mailing_sms_menus.xml', 'wizard/sms_composer_views.xml', 'wizard/mailing_sms_test_views.xml', ], diff --git a/addons/mass_mailing_sms/report/mailing_trace_report_views.xml b/addons/mass_mailing_sms/report/mailing_trace_report_views.xml index 4a84bd7df6e..430aedd4246 100644 --- a/addons/mass_mailing_sms/report/mailing_trace_report_views.xml +++ b/addons/mass_mailing_sms/report/mailing_trace_report_views.xml @@ -83,9 +83,4 @@ - - - - - diff --git a/addons/mass_mailing_sms/views/link_tracker_views.xml b/addons/mass_mailing_sms/views/link_tracker_views.xml deleted file mode 100644 index 30ab3459e02..00000000000 --- a/addons/mass_mailing_sms/views/link_tracker_views.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/addons/mass_mailing_sms/views/mailing_contact_views.xml b/addons/mass_mailing_sms/views/mailing_contact_views.xml index 0d6c1acf46b..012722dae27 100644 --- a/addons/mass_mailing_sms/views/mailing_contact_views.xml +++ b/addons/mass_mailing_sms/views/mailing_contact_views.xml @@ -91,10 +91,4 @@

- - - - - - diff --git a/addons/mass_mailing_sms/views/mailing_list_views.xml b/addons/mass_mailing_sms/views/mailing_list_views.xml index 16ccdf0ccad..a469d9a899f 100644 --- a/addons/mass_mailing_sms/views/mailing_list_views.xml +++ b/addons/mass_mailing_sms/views/mailing_list_views.xml @@ -42,9 +42,4 @@

- - - - - diff --git a/addons/mass_mailing_sms/views/mailing_mailing_views.xml b/addons/mass_mailing_sms/views/mailing_mailing_views.xml index 14decacb220..6d336dcd25e 100644 --- a/addons/mass_mailing_sms/views/mailing_mailing_views.xml +++ b/addons/mass_mailing_sms/views/mailing_mailing_views.xml @@ -281,9 +281,4 @@ - - - - - diff --git a/addons/mass_mailing_sms/views/mailing_sms_menus.xml b/addons/mass_mailing_sms/views/mailing_sms_menus.xml index b60d678c5b5..c60a4ebf881 100644 --- a/addons/mass_mailing_sms/views/mailing_sms_menus.xml +++ b/addons/mass_mailing_sms/views/mailing_sms_menus.xml @@ -10,6 +10,7 @@ @@ -23,19 +24,30 @@ - + + + + @@ -55,7 +67,7 @@ groups="mass_mailing.group_mass_mailing_user"/> - - From f446e54cbd788875f2032f07445d3ce24608a503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 9 Mar 2022 08:36:12 +0000 Subject: [PATCH 4/4] [MOV] mass_mailing: reorganize controllers and templates PURPOSE Reorganize addon according to guidelines, helping finding and updating SPECIFICATIONS Reorganize templates in order to see a bit what's going on here. Notably split subscription (opt-out, blacklist) from management (view, reporting) templates. Reorganize controller code by main section in order to separate a bit various code purpose. This commit contains only file split / renaming and code move. Task-2864264 (Mass Mailing Module Reorganization) Part-of: odoo/odoo#92509 --- addons/mass_mailing/__manifest__.py | 6 +- addons/mass_mailing/controllers/main.py | 108 ++++++++++-------- .../js/{unsubscribe.js => mailing_portal.js} | 0 .../mailing_templates_portal_layouts.xml | 36 ++++++ .../mailing_templates_portal_management.xml | 32 ++++++ ... mailing_templates_portal_unsubscribe.xml} | 63 ---------- 6 files changed, 134 insertions(+), 111 deletions(-) rename addons/mass_mailing/static/src/js/{unsubscribe.js => mailing_portal.js} (100%) create mode 100644 addons/mass_mailing/views/mailing_templates_portal_layouts.xml create mode 100644 addons/mass_mailing/views/mailing_templates_portal_management.xml rename addons/mass_mailing/views/{mass_mailing_templates_portal.xml => mailing_templates_portal_unsubscribe.xml} (68%) diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index 9580bce45b9..85b9c2e55db 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -48,7 +48,9 @@ 'views/utm_campaign_views.xml', 'views/mailing_menus.xml', 'views/assets.xml', - 'views/mass_mailing_templates_portal.xml', + 'views/mailing_templates_portal_layouts.xml', + 'views/mailing_templates_portal_management.xml', + 'views/mailing_templates_portal_unsubscribe.xml', 'views/themes_templates.xml', 'views/snippets_themes.xml', 'views/snippets/s_alert.xml', @@ -94,7 +96,7 @@ 'mass_mailing/static/src/js/mass_mailing_design_constants.js', 'mass_mailing/static/src/js/mass_mailing_widget.js', 'mass_mailing/static/src/js/mailing_mailing_view_form_full_width.js', - 'mass_mailing/static/src/js/unsubscribe.js', + 'mass_mailing/static/src/js/mailing_portal.js', ], 'mass_mailing.assets_mail_themes': [ 'mass_mailing/static/src/scss/themes/**/*', diff --git a/addons/mass_mailing/controllers/main.py b/addons/mass_mailing/controllers/main.py index c3c92d8465b..517fa7fa227 100644 --- a/addons/mass_mailing/controllers/main.py +++ b/addons/mass_mailing/controllers/main.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import base64 +import base64 import werkzeug from odoo import _, exceptions, http, tools @@ -23,10 +23,9 @@ class MassMailController(http.Controller): model_display = mailing.mailing_model_id.display_name blacklist_entry._message_log(body=description + " ({})".format(model_display)) - @http.route(['/unsubscribe_from_list'], type='http', website=True, multilang=False, auth='public', sitemap=False) - def unsubscribe_placeholder_link(self, **post): - """Dummy route so placeholder is not prefixed by language, MUST have multilang=False""" - raise werkzeug.exceptions.NotFound() + # ------------------------------------------------------------ + # SUBSCRIPTION MANAGEMENT + # ------------------------------------------------------------ @http.route(['/mail/mailing//unsubscribe'], type='http', website=True, auth='public') def mailing(self, mailing_id, email=None, res_id=None, token="", **post): @@ -92,6 +91,28 @@ class MassMailController(http.Controller): return True return 'error' + @http.route('/mailing/feedback', type='json', auth='public') + def 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): + return 'unauthorized' + model = request.env[mailing.mailing_model_real] + records = model.sudo().search([('email_normalized', '=', tools.email_normalize(email))]) + for record in records: + record.sudo().message_post(body=_("Feedback from %(email)s: %(feedback)s", email=email, feedback=feedback)) + return bool(records) + return 'error' + + @http.route(['/unsubscribe_from_list'], type='http', website=True, multilang=False, auth='public', sitemap=False) + def unsubscribe_placeholder_link(self, **post): + """Dummy route so placeholder is not prefixed by language, MUST have multilang=False""" + raise werkzeug.exceptions.NotFound() + + # ------------------------------------------------------------ + # TRACKING + # ------------------------------------------------------------ + @http.route('/mail/track///blank.gif', type='http', auth='public') def track_mail_open(self, mail_id, token, **post): """ Email tracking. """ @@ -105,6 +126,39 @@ class MassMailController(http.Controller): return response + @http.route('/r//m/', type='http', auth="public") + def full_url_redirect(self, code, mailing_trace_id, **post): + # don't assume geoip is set, it is part of the website module + # which mass_mailing doesn't depend on + country_code = request.geoip.get('country_code') + + request.env['link.tracker.click'].sudo().add_click( + code, + ip=request.httprequest.remote_addr, + country_code=country_code, + mailing_trace_id=mailing_trace_id + ) + return request.redirect(request.env['link.tracker'].get_url_from_code(code), code=301, local=False) + + # ------------------------------------------------------------ + # MAILING MANAGEMENT + # ------------------------------------------------------------ + + @http.route('/mailing/report/unsubscribe', type='http', website=True, auth='public') + def turn_off_mailing_reports(self, token, user_id): + if not token or not user_id: + raise werkzeug.exceptions.NotFound() + user_id = int(user_id) + correct_token = consteq(token, request.env['mailing.mailing']._get_unsubscribe_token(user_id)) + user = request.env['res.users'].sudo().browse(user_id) + if correct_token and user.has_group('mass_mailing.group_mass_mailing_user'): + request.env['ir.config_parameter'].sudo().set_param('mass_mailing.mass_mailing_reports', False) + if user.has_group('base.group_system'): + menu_id = request.env.ref('mass_mailing.menu_mass_mailing_global_settings').id + return request.render('mass_mailing.mailing_report_deactivated', {'menu_id': menu_id}) + return request.render('mass_mailing.mailing_report_deactivated') + 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=""): mailing = request.env['mailing.mailing'].sudo().browse(mailing_id) @@ -134,19 +188,9 @@ class MassMailController(http.Controller): return request.redirect('/web') - @http.route('/r//m/', type='http', auth="public") - def full_url_redirect(self, code, mailing_trace_id, **post): - # don't assume geoip is set, it is part of the website module - # which mass_mailing doesn't depend on - country_code = request.geoip.get('country_code') - - request.env['link.tracker.click'].sudo().add_click( - code, - ip=request.httprequest.remote_addr, - country_code=country_code, - mailing_trace_id=mailing_trace_id - ) - return request.redirect(request.env['link.tracker'].get_url_from_code(code), code=301, local=False) + # ------------------------------------------------------------ + # BLACKLIST + # ------------------------------------------------------------ @http.route('/mailing/blacklist/check', type='json', auth='public') def blacklist_check(self, mailing_id, res_id, email, token): @@ -182,31 +226,3 @@ class MassMailController(http.Controller): _("""Requested de-blacklisting via unsubscription page.""")) return True return 'error' - - @http.route('/mailing/feedback', type='json', auth='public') - def 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): - return 'unauthorized' - model = request.env[mailing.mailing_model_real] - records = model.sudo().search([('email_normalized', '=', tools.email_normalize(email))]) - for record in records: - record.sudo().message_post(body=_("Feedback from %(email)s: %(feedback)s", email=email, feedback=feedback)) - return bool(records) - return 'error' - - @http.route('/mailing/report/unsubscribe', type='http', website=True, auth='public') - def turn_off_mailing_reports(self, token, user_id): - if not token or not user_id: - raise werkzeug.exceptions.NotFound() - user_id = int(user_id) - correct_token = consteq(token, request.env['mailing.mailing']._get_unsubscribe_token(user_id)) - user = request.env['res.users'].sudo().browse(user_id) - if correct_token and user.has_group('mass_mailing.group_mass_mailing_user'): - request.env['ir.config_parameter'].sudo().set_param('mass_mailing.mass_mailing_reports', False) - if user.has_group('base.group_system'): - menu_id = request.env.ref('mass_mailing.menu_mass_mailing_global_settings').id - return request.render('mass_mailing.mailing_report_deactivated', {'menu_id': menu_id}) - return request.render('mass_mailing.mailing_report_deactivated') - raise werkzeug.exceptions.NotFound() diff --git a/addons/mass_mailing/static/src/js/unsubscribe.js b/addons/mass_mailing/static/src/js/mailing_portal.js similarity index 100% rename from addons/mass_mailing/static/src/js/unsubscribe.js rename to addons/mass_mailing/static/src/js/mailing_portal.js diff --git a/addons/mass_mailing/views/mailing_templates_portal_layouts.xml b/addons/mass_mailing/views/mailing_templates_portal_layouts.xml new file mode 100644 index 00000000000..ba652e5bfbc --- /dev/null +++ b/addons/mass_mailing/views/mailing_templates_portal_layouts.xml @@ -0,0 +1,36 @@ + + + + + diff --git a/addons/mass_mailing/views/mailing_templates_portal_management.xml b/addons/mass_mailing/views/mailing_templates_portal_management.xml new file mode 100644 index 00000000000..03dafe2cd6c --- /dev/null +++ b/addons/mass_mailing/views/mailing_templates_portal_management.xml @@ -0,0 +1,32 @@ + + + + + + + \ No newline at end of file diff --git a/addons/mass_mailing/views/mass_mailing_templates_portal.xml b/addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml similarity index 68% rename from addons/mass_mailing/views/mass_mailing_templates_portal.xml rename to addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml index c1f4f6be745..bc46f2914d6 100644 --- a/addons/mass_mailing/views/mass_mailing_templates_portal.xml +++ b/addons/mass_mailing/views/mailing_templates_portal_unsubscribe.xml @@ -1,29 +1,5 @@ - - - - - - -