From 88f4c4dd36fb0d74e8adf1ea2a9572c495dcce8c Mon Sep 17 00:00:00 2001 From: std-odoo Date: Wed, 19 Apr 2023 08:35:35 +0200 Subject: [PATCH] [IMP] base: properties, do not allow to select transient models Purpose ======= Do not allow to select transient models in relational properties. Task-3032464 Part-of: odoo/odoo#103510 --- addons/web/models/ir_model.py | 16 ++++++---- addons/web/tests/test_ir_model.py | 9 ++++++ .../test_new_api/models/test_new_api.py | 5 ++++ .../test_new_api/security/ir.model.access.csv | 1 + .../test_new_api/tests/test_properties.py | 30 +++++++++++++++++++ odoo/fields.py | 2 +- 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/addons/web/models/ir_model.py b/addons/web/models/ir_model.py index ade00f6ee89..44ce0e9c074 100644 --- a/addons/web/models/ir_model.py +++ b/addons/web/models/ir_model.py @@ -19,7 +19,7 @@ class IrModel(models.Model): accessible_models = [] not_accessible_models = [] for model in models: - if self._check_model_access(model): + if self._is_valid_for_model_selector(model): accessible_models.append(model) else: not_accessible_models.append({"display_name": model, "model": model}) @@ -34,9 +34,15 @@ class IrModel(models.Model): } for model in records] @api.model - def _check_model_access(self, model): - return (self.env.user._is_internal() and model in self.env - and self.env[model].check_access_rights("read", raise_exception=False)) + def _is_valid_for_model_selector(self, model): + model = self.env.get(model) + return ( + self.env.user._is_internal() + and model is not None + and model.check_access_rights("read", raise_exception=False) + and not model._transient + and not model._abstract + ) @api.model def get_available_models(self): @@ -44,5 +50,5 @@ class IrModel(models.Model): Return the list of models the current user has access to, with their corresponding display name. """ - accessible_models = [model for model in self.pool.keys() if self._check_model_access(model)] + accessible_models = [model for model in self.pool if self._is_valid_for_model_selector(model)] return self._display_name_for(accessible_models) diff --git a/addons/web/tests/test_ir_model.py b/addons/web/tests/test_ir_model.py index 8ba412761cb..3b718bbd3e9 100644 --- a/addons/web/tests/test_ir_model.py +++ b/addons/web/tests/test_ir_model.py @@ -63,3 +63,12 @@ class IrModelAccessTest(TransactionCase): # non existent model comes after existent model result = self.env['ir.model'].display_name_for(["res.company", "unexistent"]) self.assertEqual(result, [{"display_name": "Companies", "model": "res.company"}, {"display_name": "unexistent", "model": "unexistent"}]) + # transient models + result = self.env['ir.model'].display_name_for(["res.company", "base.language.export"]) + self.assertEqual(result, [{"display_name": "Companies", "model": "res.company"}, {"display_name": "base.language.export", "model": "base.language.export"}]) + + # do not return results for transient models + result = self.env['ir.model'].get_available_models() + result = {values["model"] for values in result} + self.assertIn("res.company", result) + self.assertNotIn("base.language.export", result) diff --git a/odoo/addons/test_new_api/models/test_new_api.py b/odoo/addons/test_new_api/models/test_new_api.py index 17c875fa9bf..bd3aa6d176a 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -962,6 +962,11 @@ class RequiredM2OTransient(models.TransientModel): bar = fields.Many2one('res.country', required=True) +class TestTransient(models.TransientModel): + _name = 'test_new_api.transient_model' + _description = 'Transient Model' + + class Attachment(models.Model): _name = 'test_new_api.attachment' _description = 'Attachment' diff --git a/odoo/addons/test_new_api/security/ir.model.access.csv b/odoo/addons/test_new_api/security/ir.model.access.csv index 1c25a03c3d1..8207897d07e 100644 --- a/odoo/addons/test_new_api/security/ir.model.access.csv +++ b/odoo/addons/test_new_api/security/ir.model.access.csv @@ -114,3 +114,4 @@ access_test_new_api_unsearchable_o2m_employee,access_test_new_api_unsearchable_o access_test_new_api_any_parent,access_test_new_api_any_parent,model_test_new_api_any_parent,base.group_user,1,0,0,0 access_test_new_api_any_child,access_test_new_api_any_child,model_test_new_api_any_child,base.group_user,1,0,0,0 access_test_new_api_any_tag,access_test_new_api_any_tag,model_test_new_api_any_tag,base.group_user,1,0,0,0 +access_test_new_api_transient_model,access_test_new_api_transient_model,model_test_new_api_transient_model,base.group_user,1,1,1,1 diff --git a/odoo/addons/test_new_api/tests/test_properties.py b/odoo/addons/test_new_api/tests/test_properties.py index 937ad908234..f3529c0c765 100644 --- a/odoo/addons/test_new_api/tests/test_properties.py +++ b/odoo/addons/test_new_api/tests/test_properties.py @@ -740,6 +740,21 @@ class PropertiesCase(TestPropertiesMixin): self.assertEqual(properties[1]['value'], (self.partner_2.id, self.partner_2.display_name)) self.assertEqual(properties[1]['comodel'], 'test_new_api.partner') + # should not be able to set a transient model + with self.assertRaises(ValueError): + self.message_2.attributes = [{ + "name": "moderator_partner_id", + "type": "many2one", + "comodel": "test_new_api.transient_model", + "definition_changed": True, + }] + with self.assertRaises(ValueError): + self.discussion_1.attributes_definition = [{ + "name": "moderator_partner_id", + "type": "many2one", + "comodel": "test_new_api.transient_model", + }] + @mute_logger('odoo.models.unlink', 'odoo.fields') def test_properties_field_many2one_unlink(self): """Test the case where we unlink the many2one record.""" @@ -1232,6 +1247,21 @@ class PropertiesCase(TestPropertiesMixin): 'value': [(partners[9].id, partners[9].display_name)], }]) + # should not be able to set a transient model + with self.assertRaises(ValueError): + self.message_2.attributes = [{ + "name": "partner_ids", + "type": "many2many", + "comodel": "test_new_api.transient_model", + "definition_changed": True, + }] + with self.assertRaises(ValueError): + self.discussion_1.attributes_definition = [{ + "name": "partner_ids", + "type": "many2many", + "comodel": "test_new_api.transient_model", + }] + @users('test') @mute_logger('odoo.addons.base.models.ir_rule', 'odoo.fields') def test_properties_field_many2many_filtering(self): diff --git a/odoo/fields.py b/odoo/fields.py index e6bb321c007..1d95386fe10 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -3964,7 +3964,7 @@ class PropertiesDefinition(Field): raise ValueError(f'Wrong property type {property_type!r}.') model = property_definition.get('comodel') - if model and model not in env: + if model and (model not in env or env[model].is_transient() or env[model]._abstract): raise ValueError(f'Invalid model name {model!r}') property_selection = property_definition.get('selection')