From 292da0f91e737ff5122123a35f3fa7c3be2cb143 Mon Sep 17 00:00:00 2001 From: Mark Schuit Date: Mon, 3 Jul 2023 12:45:26 +0200 Subject: [PATCH 1/2] [FIX] base_changeset: permission errors on models and fields Fixes ``` Traceback (most recent call last): File "/home/odoo/15.0/parts/server-tools/base_changeset/tests/test_changeset_flow.py", line 63, in test_new_changeset self.partner.write({"name": "Y", "street": "street Y", "street2": "street2 Y"}) File "/home/odoo/15.0/parts/odoo/odoo/addons/base/models/res_partner.py", line 603, in write result = result and super(Partner, self).write(vals) File "/home/odoo/15.0/parts/server-tools/base_changeset/models/base.py", line 97, in write if self._changeset_disabled(): File "/home/odoo/15.0/parts/server-tools/base_changeset/models/base.py", line 111, in _changeset_disabled if self._name not in self.models_to_track_changeset(): File "", line 2, in models_to_track_changeset File "/home/odoo/15.0/parts/odoo/odoo/tools/cache.py", line 90, in lookup value = d[key] = self.method(*args, **kwargs) File "/home/odoo/15.0/parts/server-tools/base_changeset/models/base.py", line 71, in models_to_track_changeset models = self.env["changeset.field.rule"].search([]).mapped("model_id.model") File "/home/odoo/15.0/parts/odoo/odoo/models.py", line 5464, in mapped recs = recs._fields[name].mapped(recs) File "/home/odoo/15.0/parts/odoo/odoo/fields.py", line 1180, in mapped self.__get__(first(remaining), type(remaining)) File "/home/odoo/15.0/parts/odoo/odoo/fields.py", line 1089, in __get__ record._fetch_field(self) File "/home/odoo/15.0/parts/odoo/odoo/models.py", line 3276, in _fetch_field self._read(fnames) File "/home/odoo/15.0/parts/odoo/odoo/models.py", line 3290, in _read self.check_access_rights('read') File "/home/odoo/15.0/parts/odoo/odoo/models.py", line 3547, in check_access_rights return self.env['ir.model.access'].check(self._name, operation, raise_exception) File "", line 2, in check File "/home/odoo/15.0/parts/odoo/odoo/tools/cache.py", line 90, in lookup value = d[key] = self.method(*args, **kwargs) File "/home/odoo/15.0/parts/odoo/odoo/addons/base/models/ir_model.py", line 1820, in check raise AccessError(msg) odoo.exceptions.AccessError: You are not allowed to access 'Models' (ir.model) records. This operation is allowed for the following groups: - Administration/Access Rights - Changeset Validations Contact your administrator to request access if necessary. ``` --- base_changeset/models/base.py | 4 +++- base_changeset/models/changeset_field_rule.py | 2 +- .../models/record_changeset_change.py | 7 ++++--- base_changeset/tests/test_changeset_flow.py | 19 +++++++++++-------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/base_changeset/models/base.py b/base_changeset/models/base.py index 9d4b9c6ac..6565e6fe5 100644 --- a/base_changeset/models/base.py +++ b/base_changeset/models/base.py @@ -68,7 +68,9 @@ class Base(models.AbstractModel): :args: :returns: list of models """ - models = self.env["changeset.field.rule"].search([]).mapped("model_id.model") + models = ( + self.env["changeset.field.rule"].sudo().search([]).mapped("model_id.model") + ) if config["test_enable"] and self.env.context.get("test_record_changeset"): if "res.partner" not in models: models += ["res.partner"] # Used in tests diff --git a/base_changeset/models/changeset_field_rule.py b/base_changeset/models/changeset_field_rule.py index b79293cda..c67b1c490 100644 --- a/base_changeset/models/changeset_field_rule.py +++ b/base_changeset/models/changeset_field_rule.py @@ -110,7 +110,7 @@ class ChangesetFieldRule(models.Model): """ domain = self._get_rules_search_domain(record_model_name, source_model_name) - model_rules = self.search( + model_rules = self.sudo().search( domain, # using 'ASC' means that 'NULLS LAST' is the default order="source_model_id ASC", diff --git a/base_changeset/models/record_changeset_change.py b/base_changeset/models/record_changeset_change.py index da20dc496..caceb2eef 100644 --- a/base_changeset/models/record_changeset_change.py +++ b/base_changeset/models/record_changeset_change.py @@ -347,11 +347,12 @@ class RecordChangesetChange(models.Model): :returns: dict of values, boolean """ - new_field_name = self.get_field_for_type(rule.field_id, "new") + field = rule.sudo().field_id + new_field_name = self.get_field_for_type(field, "new") new_value = self._value_for_changeset(record, field_name, value=value) change = { new_field_name: new_value, - "field_id": rule.field_id.id, + "field_id": field.id, "rule_id": rule.id, } if rule.action == "auto": @@ -368,7 +369,7 @@ class RecordChangesetChange(models.Model): # Normally the 'old' value is set when we use the 'apply' # button, but since we short circuit the 'apply', we # directly set the 'old' value here - old_field_name = self.get_field_for_type(rule.field_id, "old") + old_field_name = self.get_field_for_type(field, "old") # get values ready to write as expected by the changeset # (for instance, a many2one is written in a reference # field) diff --git a/base_changeset/tests/test_changeset_flow.py b/base_changeset/tests/test_changeset_flow.py index bf693eaa1..e9a347a15 100644 --- a/base_changeset/tests/test_changeset_flow.py +++ b/base_changeset/tests/test_changeset_flow.py @@ -46,8 +46,11 @@ class TestChangesetFlow(ChangesetTestCommon, TransactionCase): def setUp(self): super().setUp() self._setup_rules() - self.partner = self.env["res.partner"].create( - {"name": "X", "street": "street X", "street2": "street2 X"} + self.demo_user = self.env.ref("base.user_demo") + self.partner = ( + self.env["res.partner"] + .with_user(self.demo_user) + .create({"name": "X", "street": "street X", "street2": "street2 X"}) ) # Add context for this test for compatibility with other modules' tests self.partner = self.partner.with_context(test_record_changeset=True) @@ -64,7 +67,7 @@ class TestChangesetFlow(ChangesetTestCommon, TransactionCase): self.assertEqual(self.partner.count_pending_changeset_changes, 1) self.assert_changeset( self.partner, - self.env.user, + self.demo_user, [ (self.field_name, "X", "Y", "done"), (self.field_street, "street X", "street Y", "draft"), @@ -140,7 +143,7 @@ class TestChangesetFlow(ChangesetTestCommon, TransactionCase): self.assertEqual(self.partner.count_pending_changesets, 1) self.assert_changeset( self.partner, - self.env.user, + self.demo_user, [(self.field_street, "street X", False, "draft")], ) @@ -197,9 +200,9 @@ class TestChangesetFlow(ChangesetTestCommon, TransactionCase): self.assertEqual(self.partner.street, "street X") self.assertEqual(self.partner.changeset_ids.change_ids.state, "draft") - user = self.env.ref("base.user_demo") - user.groups_id += self.env.ref("base_changeset.group_changeset_user") - self.partner.changeset_ids.change_ids.with_user(user).apply() + other_demo_user = self.demo_user.copy() + other_demo_user.groups_id += self.env.ref("base_changeset.group_changeset_user") + self.partner.changeset_ids.change_ids.with_user(other_demo_user).apply() self.partner._compute_changeset_ids() self.partner._compute_count_pending_changesets() self.assertEqual(self.partner.count_pending_changesets, 0) @@ -406,7 +409,7 @@ class TestChangesetFlow(ChangesetTestCommon, TransactionCase): self.partner.write({"street": False}) self.partner._compute_changeset_ids() changeset = self.partner.changeset_ids - self.assertEqual(changeset.source, self.env.user) + self.assertEqual(changeset.source, self.demo_user) def test_new_changeset_source_other_model(self): """Define source from another model""" From e01ce3d4c0196e47388a8864267119c115afb6eb Mon Sep 17 00:00:00 2001 From: Stefan Rijnhart Date: Mon, 3 Jul 2023 13:24:14 +0200 Subject: [PATCH 2/2] [FIX] base_changeset: permission error in Pending Changes widget. --- base_changeset/models/record_changeset_change.py | 2 +- base_changeset/tests/test_changeset_flow.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/base_changeset/models/record_changeset_change.py b/base_changeset/models/record_changeset_change.py index caceb2eef..374ba4dac 100644 --- a/base_changeset/models/record_changeset_change.py +++ b/base_changeset/models/record_changeset_change.py @@ -188,7 +188,7 @@ class RecordChangesetChange(models.Model): @api.model def get_field_for_type(self, field, prefix): assert prefix in ("origin", "old", "new") - field_type = self._type_to_suffix.get(field.ttype) + field_type = self._type_to_suffix.get(field.sudo().ttype) if not field_type: raise NotImplementedError("field type %s is not supported" % field_type) return "{}_value_{}".format(prefix, field_type) diff --git a/base_changeset/tests/test_changeset_flow.py b/base_changeset/tests/test_changeset_flow.py index e9a347a15..c7ea41137 100644 --- a/base_changeset/tests/test_changeset_flow.py +++ b/base_changeset/tests/test_changeset_flow.py @@ -77,6 +77,11 @@ class TestChangesetFlow(ChangesetTestCommon, TransactionCase): self.assertEqual(self.partner.name, "Y") self.assertEqual(self.partner.street, "street X") self.assertEqual(self.partner.street2, "street2 X") + # Pending Changes widget can be rendered for the unprivileged user + self.env["record.changeset.change"].invalidate_cache() + self.env["record.changeset.change"].with_user( + self.demo_user + ).get_fields_changeset_changes(self.partner._name, self.partner.id) def test_create_new_changeset(self): """Create a new partner with a changeset"""