From 6d618abde8d9046540f403ffd92bc6fa6149b46c Mon Sep 17 00:00:00 2001 From: Thierry Ducrest Date: Fri, 21 Jun 2024 16:05:40 +0200 Subject: [PATCH] mail_restrict_follower_selection: improve eval With this is change it is now possible to use the `ref` function in the domain set in a parameter, allowing to include xmlids in the domain. --- mail_restrict_follower_selection/__init__.py | 1 + .../models/mail_followers.py | 7 +++- .../models/mail_thread.py | 6 +++- .../models/mail_wizard_invite.py | 9 +++++- .../test_mail_restrict_follower_selection.py | 32 +++++++++++++++++++ mail_restrict_follower_selection/utils.py | 10 ++++++ 6 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 mail_restrict_follower_selection/utils.py diff --git a/mail_restrict_follower_selection/__init__.py b/mail_restrict_follower_selection/__init__.py index 9537e12db4..52c9640c7f 100644 --- a/mail_restrict_follower_selection/__init__.py +++ b/mail_restrict_follower_selection/__init__.py @@ -3,3 +3,4 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import models +from . import utils diff --git a/mail_restrict_follower_selection/models/mail_followers.py b/mail_restrict_follower_selection/models/mail_followers.py index 30ca69c799..50fe96e6a4 100644 --- a/mail_restrict_follower_selection/models/mail_followers.py +++ b/mail_restrict_follower_selection/models/mail_followers.py @@ -5,6 +5,8 @@ from odoo.tools import config from odoo.tools.safe_eval import safe_eval +from ..utils import _id_get + class MailFollowers(models.Model): _inherit = "mail.followers" @@ -38,7 +40,10 @@ def _add_followers( "mail.wizard.invite" ]._mail_restrict_follower_selection_get_domain(res_model=res_model) partners = self.env["res.partner"].search( - [("id", "in", partner_ids)] + safe_eval(domain) + [("id", "in", partner_ids)] + + safe_eval( + domain, locals_dict={"ref": lambda str_id: _id_get(self.env, str_id)} + ) ) _res_ids = res_ids.copy() or [0] new, update = super()._add_followers( diff --git a/mail_restrict_follower_selection/models/mail_thread.py b/mail_restrict_follower_selection/models/mail_thread.py index 6b1201bd8c..d694e177ce 100644 --- a/mail_restrict_follower_selection/models/mail_thread.py +++ b/mail_restrict_follower_selection/models/mail_thread.py @@ -2,6 +2,8 @@ from odoo.tools import config from odoo.tools.safe_eval import safe_eval +from ..utils import _id_get + class MailThread(models.AbstractModel): _inherit = "mail.thread" @@ -20,7 +22,9 @@ def _message_add_suggested_recipient( domain = self.env[ "mail.wizard.invite" ]._mail_restrict_follower_selection_get_domain() - eval_domain = safe_eval(domain) + eval_domain = safe_eval( + domain, locals_dict={"ref": lambda str_id: _id_get(self.env, str_id)} + ) for key in result: for partner_id, email, reason in result[key]: if partner_id: diff --git a/mail_restrict_follower_selection/models/mail_wizard_invite.py b/mail_restrict_follower_selection/models/mail_wizard_invite.py index 9434f1581f..6f8289bf31 100644 --- a/mail_restrict_follower_selection/models/mail_wizard_invite.py +++ b/mail_restrict_follower_selection/models/mail_wizard_invite.py @@ -5,6 +5,9 @@ from lxml import etree from odoo import api, models +from odoo.tools.safe_eval import safe_eval + +from ..utils import _id_get class MailWizardInvite(models.TransientModel): @@ -34,7 +37,11 @@ def fields_view_get( view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu ) arch = etree.fromstring(result["arch"]) + domain = self._mail_restrict_follower_selection_get_domain() + eval_domain = safe_eval( + domain, locals_dict={"ref": lambda str_id: _id_get(self.env, str_id)} + ) for field in arch.xpath('//field[@name="partner_ids"]'): - field.attrib["domain"] = self._mail_restrict_follower_selection_get_domain() + field.attrib["domain"] = str(eval_domain) result["arch"] = etree.tostring(arch) return result diff --git a/mail_restrict_follower_selection/tests/test_mail_restrict_follower_selection.py b/mail_restrict_follower_selection/tests/test_mail_restrict_follower_selection.py index e8bf0565ca..c0cd68ae35 100644 --- a/mail_restrict_follower_selection/tests/test_mail_restrict_follower_selection.py +++ b/mail_restrict_follower_selection/tests/test_mail_restrict_follower_selection.py @@ -21,6 +21,12 @@ def setUp(self): "email": "test@test.com", } ) + self.switzerland = self.env.ref("base.ch") + + def _use_ref_in_domain(self): + """Change the general domain to test the safe_eval.""" + param = self.env.ref("mail_restrict_follower_selection.parameter_domain") + param.value = "[('country_id', '!=', ref('base.ch'))]" def test_fields_view_get(self): result = self.env["mail.wizard.invite"].fields_view_get(view_type="form") @@ -80,3 +86,29 @@ def test_message_add_suggested_recipient(self): test_restrict_follower=True )._message_add_suggested_recipient({self.partner.id: []}) self.assertFalse(new_res[self.partner.id][0][0]) + + def test_fields_view_get_eval(self): + """Check using safe_eval in field_view_get.""" + self._use_ref_in_domain() + result = self.env["mail.wizard.invite"].fields_view_get(view_type="form") + for field in etree.fromstring(result["arch"]).xpath( + '//field[@name="partner_ids"]' + ): + domain = field.get("domain") + self.assertTrue(domain.find("country_id") > 0) + self.assertTrue(domain.find(str(self.switzerland.id)) > 0) + + def test_message_add_suggested_recipient_eval(self): + """Check using safe_eval when adding recipients.""" + self._use_ref_in_domain() + partner = self.partner.with_context(test_restrict_follower=True) + res = partner._message_add_suggested_recipient( + {self.partner.id: []}, partner=self.partner + ) + self.assertEqual(res[self.partner.id][0][0], self.partner.id) + # Partner from Swizterland should be excluded + partner.country_id = self.switzerland + res = partner._message_add_suggested_recipient( + {self.partner.id: []}, partner=self.partner + ) + self.assertFalse(res[self.partner.id]) diff --git a/mail_restrict_follower_selection/utils.py b/mail_restrict_follower_selection/utils.py new file mode 100644 index 0000000000..272bd220a7 --- /dev/null +++ b/mail_restrict_follower_selection/utils.py @@ -0,0 +1,10 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + + +def _id_get(env, id_str): + """Have a more secure ref function for use with safe_eval. + + Returning only the ID of the record. + """ + return env.ref(id_str).id