[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
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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):
|
||||
|
||||
+1
-1
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user