diff --git a/addons/mail/models/__init__.py b/addons/mail/models/__init__.py index 03c7e597fa2..97eaa360340 100644 --- a/addons/mail/models/__init__.py +++ b/addons/mail/models/__init__.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import mail_render_mixin +from . import mail_composer_mixin + from . import mail_message_subtype from . import mail_tracking_value from . import mail_alias from . import mail_alias_mixin from . import mail_followers from . import mail_notification -from . import mail_render_mixin from . import mail_message from . import mail_activity from . import mail_mail diff --git a/addons/mail/models/mail_composer_mixin.py b/addons/mail/models/mail_composer_mixin.py new file mode 100644 index 00000000000..03d4fcc6a87 --- /dev/null +++ b/addons/mail/models/mail_composer_mixin.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class MailComposerMixin(models.AbstractModel): + """ Mixin used to edit and render some fields used when sending emails or + notifications based on a mail template. + + Main current purpose is to hide details related to subject and body computation + and rendering based on a mail.template. It also give the base tools to control + who is allowed to edit body, notably when dealing with templating language + like jinja or qweb. + + It is meant to evolve in a near future with upcoming support of qweb and fine + grain control of rendering access. + """ + _name = 'mail.composer.mixin' + _inherit = 'mail.render.mixin' + _description = 'Mail Composer Mixin' + + # Content + subject = fields.Char('Subject', compute='_compute_subject', readonly=False, store=True) + body = fields.Html('Contents', sanitize_style=True, compute='_compute_body', store=True, readonly=False) + template_id = fields.Many2one('mail.template', 'Mail Template', domain="[('model', '=', render_model)]") + # Access + can_edit_body = fields.Boolean('Can Edit Body', compute='_compute_can_edit_body') + + @api.depends('template_id') + def _compute_subject(self): + for composer_mixin in self: + if composer_mixin.template_id: + composer_mixin.subject = composer_mixin.template_id.subject + elif not composer_mixin.subject: + composer_mixin.subject = False + + @api.depends('template_id') + def _compute_body(self): + for composer_mixin in self: + if composer_mixin.template_id: + composer_mixin.body = composer_mixin.template_id.body_html + elif not composer_mixin.body: + composer_mixin.body = False + + @api.depends('template_id') + @api.depends_context('uid') + def _compute_can_edit_body(self): + self.can_edit_body = True diff --git a/addons/test_mail/models/test_mail_models.py b/addons/test_mail/models/test_mail_models.py index 47fdf6ae1ed..b0773d71c95 100644 --- a/addons/test_mail/models/test_mail_models.py +++ b/addons/test_mail/models/test_mail_models.py @@ -122,3 +122,16 @@ class MailTestContainer(models.Model): values['alias_force_thread_id'] = self.id values['alias_parent_thread_id'] = self.id return values + +class MailTestComposerMixin(models.Model): + """ A simple invite-like wizard using the composer mixin, rendering on + itself. """ + _description = 'Invite-like Wizard' + _name = 'mail.test.composer.mixin' + _inherit = ['mail.composer.mixin'] + + name = fields.Char('Name') + author_id = fields.Many2one('res.partner') + + def _compute_render_model(self): + self.render_model = self._name diff --git a/addons/test_mail/security/ir.model.access.csv b/addons/test_mail/security/ir.model.access.csv index 2f2fe28732d..5a834b20a8d 100644 --- a/addons/test_mail/security/ir.model.access.csv +++ b/addons/test_mail/security/ir.model.access.csv @@ -11,6 +11,8 @@ access_mail_test_activity_portal,mail.test.activity.portal,model_mail_test_activ access_mail_test_activity_user,mail.test.activity.user,model_mail_test_activity,base.group_user,1,1,1,1 access_mail_test_ticket_portal,mail.test.ticket.portal,model_mail_test_ticket,base.group_portal,0,0,0,0 access_mail_test_ticket_user,mail.test.ticket.user,model_mail_test_ticket,base.group_user,1,1,1,1 +access_mail_test_composer_mixin_all,mail.test.composer.mixin.all,model_mail_test_composer_mixin,,0,0,0,0 +access_mail_test_composer_mixin_user,mail.test.composer.mixin.user,model_mail_test_composer_mixin,base.group_user,1,1,1,1 access_mail_test_container_portal,mail.test.container_portal,model_mail_test_container,base.group_portal,1,1,0,0 access_mail_test_container_user,mail.test.container.user,model_mail_test_container,base.group_user,1,1,1,1 access_mail_test_cc_portal,mail.test.cc.portal,model_mail_test_cc,base.group_portal,1,0,0,0 diff --git a/addons/test_mail/tests/__init__.py b/addons/test_mail/tests/__init__.py index 15d441d888c..547eb93779a 100644 --- a/addons/test_mail/tests/__init__.py +++ b/addons/test_mail/tests/__init__.py @@ -4,6 +4,7 @@ from . import test_invite from . import test_ir_actions from . import test_mail_activity from . import test_mail_composer +from . import test_mail_composer_mixin from . import test_mail_followers from . import test_mail_message from . import test_mail_mail diff --git a/addons/test_mail/tests/test_mail_composer_mixin.py b/addons/test_mail/tests/test_mail_composer_mixin.py new file mode 100644 index 00000000000..265a509da9d --- /dev/null +++ b/addons/test_mail/tests/test_mail_composer_mixin.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.test_mail.tests.common import TestMailCommon, TestRecipients +from odoo.tests import tagged +from odoo.tests.common import users + + +@tagged('mail_composer_mixin') +class TestMailComposerMixin(TestMailCommon, TestRecipients): + + @classmethod + def setUpClass(cls): + super(TestMailComposerMixin, cls).setUpClass() + cls._init_mail_gateway() + + cls.mail_template = cls.env['mail.template'].create({ + 'subject': 'Subject for ${object.name}', + 'body_html': '

Body for ${object.name}

', + }) + + @users("employee") + def test_content_sync(self): + record = self.env['mail.test.composer.mixin'].create({ + 'name': 'Invite', + 'template_id': self.mail_template.id, + }) + self.assertEqual(record.subject, self.mail_template.subject) + self.assertEqual(record.body, self.mail_template.body_html) + + subject = record._render_field('subject', record.ids)[record.id] + self.assertEqual(subject, 'Subject for %s' % record.name) + body = record._render_field('body', record.ids)[record.id] + self.assertEqual(body, '

Body for %s

' % record.name) + + @users("employee") + def test_rendering(self): + record = self.env['mail.test.composer.mixin'].create({ + 'name': 'Invite', + 'subject': 'Subject for ${object.name}', + 'body': '

Content from ${user.name}

', + }) + self.assertEqual(record.subject, 'Subject for ${object.name}') + self.assertEqual(record.body, '

Content from ${user.name}

') + + subject = record._render_field('subject', record.ids)[record.id] + self.assertEqual(subject, 'Subject for %s' % record.name) + body = record._render_field('body', record.ids)[record.id] + self.assertEqual(body, '

Content from %s

' % self.env.user.name)