diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py index a10ce16a38f..be72b5ac41d 100644 --- a/addons/base_automation/models/base_automation.py +++ b/addons/base_automation/models/base_automation.py @@ -194,8 +194,9 @@ class BaseAutomation(models.Model): def _filter_pre(self, records): """ Filter the records that satisfy the precondition of action ``self``. """ - if self.filter_pre_domain and records: - domain = [('id', 'in', records.ids)] + safe_eval.safe_eval(self.filter_pre_domain, self._get_eval_context()) + self_sudo = self.sudo() + if self_sudo.filter_pre_domain and records: + domain = [('id', 'in', records.ids)] + safe_eval.safe_eval(self_sudo.filter_pre_domain, self._get_eval_context()) return records.sudo().search(domain).with_env(records.env) else: return records @@ -205,8 +206,9 @@ class BaseAutomation(models.Model): def _filter_post_export_domain(self, records): """ Filter the records that satisfy the postcondition of action ``self``. """ - if self.filter_domain and records: - domain = [('id', 'in', records.ids)] + safe_eval.safe_eval(self.filter_domain, self._get_eval_context()) + self_sudo = self.sudo() + if self_sudo.filter_domain and records: + domain = [('id', 'in', records.ids)] + safe_eval.safe_eval(self_sudo.filter_domain, self._get_eval_context()) return records.sudo().search(domain).with_env(records.env), domain else: return records, None @@ -262,7 +264,8 @@ class BaseAutomation(models.Model): def _check_trigger_fields(self, record): """ Return whether any of the trigger fields has been modified on ``record``. """ - if not self.trigger_field_ids: + self_sudo = self.sudo() + if not self_sudo.trigger_field_ids: # all fields are implicit triggers return True @@ -280,7 +283,7 @@ class BaseAutomation(models.Model): field.convert_to_cache(record[name], record, validate=False) != field.convert_to_cache(old_vals[name], record, validate=False) ) - return any(differ(field.name) for field in self.trigger_field_ids) + return any(differ(field.name) for field in self_sudo.trigger_field_ids) def _register_hook(self): """ Patch models that should trigger action rules based on creation, @@ -389,7 +392,7 @@ class BaseAutomation(models.Model): def base_automation_onchange(self): action_rule = self.env['base.automation'].browse(action_rule_id) result = {} - server_action = action_rule.action_server_id.with_context(active_model=self._name, onchange_self=self) + server_action = action_rule.sudo().action_server_id.with_context(active_model=self._name, onchange_self=self) try: res = server_action.run() except Exception as e: diff --git a/addons/base_automation/tests/__init__.py b/addons/base_automation/tests/__init__.py new file mode 100644 index 00000000000..92a8a4959d9 --- /dev/null +++ b/addons/base_automation/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import test_automation diff --git a/addons/base_automation/tests/test_automation.py b/addons/base_automation/tests/test_automation.py new file mode 100644 index 00000000000..1acdf6178c7 --- /dev/null +++ b/addons/base_automation/tests/test_automation.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.tests import TransactionCase +from odoo.exceptions import UserError + +import odoo.tests + +@odoo.tests.tagged('post_install', '-at_install') +class TestAutomation(TransactionCase): + + def test_01_on_create(self): + """ Simple on_create with admin user """ + self.env["base.automation"].create({ + "name": "Force Archived Contacts", + "trigger": "on_create_or_write", + "model_id": self.env.ref("base.model_res_partner").id, + "type": "ir.actions.server", + "trigger_field_ids": [(6, 0, [self.env.ref("base.field_res_partner__name").id])], + "fields_lines": [(0, 0, { + "col1": self.env.ref("base.field_res_partner__active").id, + "evaluation_type": "equation", + "value": "False", + })], + }) + + # verify the partner can be created and the action still runs + bilbo = self.env["res.partner"].create({"name": "Bilbo Baggins"}) + self.assertFalse(bilbo.active) + + # verify the partner can be updated and the action still runs + bilbo.active = True + bilbo.name = "Bilbo" + self.assertFalse(bilbo.active) + + + def test_02_on_create_restricted(self): + """ on_create action with low portal user """ + action = self.env["base.automation"].create({ + "name": "Force Archived Filters", + "trigger": "on_create_or_write", + "model_id": self.env.ref("base.model_ir_filters").id, + "type": "ir.actions.server", + "trigger_field_ids": [(6, 0, [self.env.ref("base.field_ir_filters__name").id])], + "fields_lines": [(0, 0, { + "col1": self.env.ref("base.field_ir_filters__active").id, + "evaluation_type": "equation", + "value": "False", + })], + }) + # action cached was cached with admin, force CacheMiss + action.env.clear() + + self_portal = self.env["ir.filters"].with_user(self.env.ref("base.user_demo").id) + # verify the portal user can create ir.filters but can not read base.automation + self.assertTrue(self_portal.env["ir.filters"].check_access_rights("create", raise_exception=False)) + self.assertFalse(self_portal.env["base.automation"].check_access_rights("read", raise_exception=False)) + + # verify the filter can be created and the action still runs + filters = self_portal.create({ + "name": "Where is Bilbo?", + "domain": "[('name', 'ilike', 'bilbo')]", + "model_id": "res.partner", + }) + self.assertFalse(filters.active) + + # verify the filter can be updated and the action still runs + filters.active = True + filters.name = "Where is Bilbo Baggins?" + self.assertFalse(filters.active) + + + def test_03_on_change_restricted(self): + """ on_create action with low portal user """ + action = self.env["base.automation"].create({ + "name": "Force Archived Filters", + "trigger": "on_change", + "model_id": self.env.ref("base.model_ir_filters").id, + "type": "ir.actions.server", + "on_change_field_ids": [(6, 0, [self.env.ref("base.field_ir_filters__name").id])], + "state": "code", + "code": """action = {'value': {'active': False}}""", + }) + # action cached was cached with admin, force CacheMiss + action.env.clear() + + self_portal = self.env["ir.filters"].with_user(self.env.ref("base.user_demo").id) + + # simulate a onchange call on name + onchange = self_portal.onchange({}, [], {"name": "1", "active": ""}) + self.assertEqual(onchange["value"]["active"], False)