diff --git a/mail_digest/README.rst b/mail_digest/README.rst index 9a163d31..6b00ee5e 100644 --- a/mail_digest/README.rst +++ b/mail_digest/README.rst @@ -65,6 +65,14 @@ NOTE: under the hood the digest notification logic excludes followers to be noti since you really want to notify only mail.digest's partner. +Digest rendering preview +------------------------ + +You can check how messages are formatted per each mail subtype by going to `/digest/layout-preview` in your browser. + +.. image:: ./images/digest_layout_preview.png + + Known issues / Roadmap ====================== diff --git a/mail_digest/__init__.py b/mail_digest/__init__.py index 0650744f..91c5580f 100644 --- a/mail_digest/__init__.py +++ b/mail_digest/__init__.py @@ -1 +1,2 @@ +from . import controllers from . import models diff --git a/mail_digest/__manifest__.py b/mail_digest/__manifest__.py index 0c0fcb8c..59d374fc 100644 --- a/mail_digest/__manifest__.py +++ b/mail_digest/__manifest__.py @@ -4,7 +4,7 @@ { 'name': 'Mail digest', 'summary': """Basic digest mail handling.""", - 'version': '11.0.1.0.2', + 'version': '11.0.1.1.0', 'license': 'AGPL-3', 'author': 'Camptocamp, Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/social', @@ -20,6 +20,7 @@ 'views/user_notification_views.xml', 'views/user_views.xml', 'templates/digest_default.xml', + 'templates/digest_layout_preview.xml', ], 'images': [ 'static/description/preview.png', diff --git a/mail_digest/controllers/__init__.py b/mail_digest/controllers/__init__.py new file mode 100644 index 00000000..f7b863bf --- /dev/null +++ b/mail_digest/controllers/__init__.py @@ -0,0 +1 @@ +from . import digest_layout_preview diff --git a/mail_digest/controllers/digest_layout_preview.py b/mail_digest/controllers/digest_layout_preview.py new file mode 100644 index 00000000..b205857a --- /dev/null +++ b/mail_digest/controllers/digest_layout_preview.py @@ -0,0 +1,139 @@ +# Copyright 2018 Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import http +from odoo.http import request +import random + + +FAKE_NAMES = [ + 'Madison Castillo', + 'Destiny Frost', + 'Dennis Parrish', + 'Christy Moore', + 'Larry James', + 'David Simmons', + 'Dr. Francis Ramos', + 'Michelle Williams', + 'Allison Montgomery', + 'Michelle Rodriguez', + 'Gina Patel', + 'Corey Ray', + 'Brent Myers', + 'Sydney Hicks', + 'Austin Buckley', + 'Patricia Jones DDS', + 'Dylan Davila', + 'Christopher Bolton', + 'James Cline', + 'Gary Johnson', + 'Jennifer Reese', + 'Kevin Davis', + 'Sandra Robinson', + 'Sara Warner', + 'Jaime Dunn', + 'Mark Austin', + 'Kendra Nelson', + 'Matthew White', + 'Rebecca Berger', + 'Amanda Thornton', + 'Lorraine Schultz', + 'Chelsea Daniel', + 'Kayla Jackson', + 'Melanie Grant', + 'Oscar Jones', + 'Jon Sanchez', + 'Kevin Anderson', + 'Yvonne Mullen', + 'Jonathan King', + 'Wendy Hernandez' +] + +FAKE_NUMBERS = range(1, 30) + + +class DigestPreview(http.Controller): + + digest_test_template = 'mail_digest.digest_layout_preview' + + @http.route([ + '/digest/layout-preview', + ], type='http', auth='user') + def digest_test(self): + digest = self._fake_digest() + mail_values = digest._get_email_values() + values = { + 'env': request.env, + 'digest_html': mail_values['body_html'], + } + return request.render(self.digest_test_template, values) + + def _fake_digest(self): + user = request.env.user + digest_model = request.env['mail.digest'].sudo() + digest = digest_model.new() + digest.partner_id = user.partner_id + digest.digest_template_id = digest._default_digest_template_id() + digest.message_ids = self._fake_messages() + digest.sanitize_msg_body = True + return digest + + def _fake_messages(self): + messages = request.env['mail.message'].sudo() + subtype_model = request.env['mail.message.subtype'].sudo() + subtypes = subtype_model.search([]) + records = request.env['res.partner'].sudo().search([]) + # TODO: filter subtypes? + for i, subtype in enumerate(subtypes): + # generate a couple of messages for each type + for x in range(1, 3): + msg = messages.new() + msg.subtype_id = subtype + subject, body = self._fake_content(subtype, i, x) + msg.subject = subject + msg.message_type = random.choice( + ('email', 'comment', 'notification')) + msg.email_from = 'random@user%d.com' % i + msg.partner_ids = [(6, 0, request.env.user.partner_id.ids)] + if i + x % 2 == 0: + # relate a document + msg.model = records._name + msg.res_id = random.choice(records.ids) + # simulate messages w/ no body but tracking values + if x == random.choice([1, 2]): + msg.tracking_value_ids = self._fake_tracking_vals() + else: + msg.body = body + messages += msg + return messages + + def _fake_content(self, subtype, i, x): + subject = 'Lorem ipsum %d / %d' % (i, x) + body = 'Random text here lorem ipsum %d / %d' % (i, x) + if i % 2 == 0 and x > 1: + # simulate also random styles that are goin to be stripped + body = """ +

Lorem ipsum dolor sit amet, cetero menandri mel id.

+ +

Ad modus tantas qui, quo choro facete delicata te. + Epicurei accusata vix eu, prima erant graeci sit te, + vivendum molestiae an mel.

+ +

Sed apeirian atomorum id, no ius possit antiopam molestiae.

+ """ # noqa + return subject, body.strip() + + def _fake_tracking_vals(self): + tracking_model = request.env['mail.tracking.value'].sudo() + track_vals1 = tracking_model.create_tracking_values( + random.choice(FAKE_NAMES), random.choice(FAKE_NAMES), + 'name', {'type': 'char', 'string': 'Name'}, + ) + track_vals2 = tracking_model.create_tracking_values( + random.choice(FAKE_NUMBERS), random.choice(FAKE_NUMBERS), + 'count', {'type': 'integer', 'string': 'Count'}, + ) + return [ + (0, 0, track_vals1), + (0, 0, track_vals2), + ] diff --git a/mail_digest/images/digest_layout_preview.png b/mail_digest/images/digest_layout_preview.png new file mode 100644 index 00000000..3c64aa93 Binary files /dev/null and b/mail_digest/images/digest_layout_preview.png differ diff --git a/mail_digest/models/mail_digest.py b/mail_digest/models/mail_digest.py index ac74ab25..8cafb298 100644 --- a/mail_digest/models/mail_digest.py +++ b/mail_digest/models/mail_digest.py @@ -1,8 +1,7 @@ # Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo import fields, models, api, exceptions, _ - +from odoo import fields, models, api, exceptions, tools, _ import logging logger = logging.getLogger('[mail_digest]') @@ -52,6 +51,14 @@ class MailDigest(models.Model): default=lambda self: self._default_digest_template_id(), domain=[('type', '=', 'qweb')], ) + sanitize_msg_body = fields.Boolean( + string='Sanitize message body', + help='Collected messages can have different styles applied ' + 'on each element. If this flag is enabled (default) ' + 'each message content will be sanitized ' + 'before generating the email.', + default=True, + ) def _default_digest_template_id(self): """Retrieve default template to render digest.""" @@ -121,6 +128,19 @@ class MailDigest(models.Model): grouped.setdefault(self._message_group_by_key(msg), []).append(msg) return grouped + @api.model + def message_body(self, msg, strip_style=True): + """Return body message prepared for email content. + + Message's body can contains styles and other stuff + that can screw the look and feel of digests' mails. + + Here we sanitize it if `sanitize_msg_body` is set on the digest. + """ + if not self.sanitize_msg_body: + return msg.body + return tools.html_sanitize(msg.body or '', strip_style=strip_style) + def _get_site_name(self): """Retrieve site name for meaningful mail subject. diff --git a/mail_digest/templates/digest_default.xml b/mail_digest/templates/digest_default.xml index 29391f3e..409c4690 100644 --- a/mail_digest/templates/digest_default.xml +++ b/mail_digest/templates/digest_default.xml @@ -24,14 +24,39 @@