[IMP] base: constraint to check view root node is matching the view type
This PR follows odoo/odoo#108073 Just ensure the root node of the view architecture matches the view type. e.g. Valid: ```xml <form> ... </form> ``` Invalid: ```xml <data> <div> ... </div> <form> ... </form> </data> ``` closes odoo/odoo#108525 Related: odoo/upgrade#4155 Related: odoo/enterprise#35501 Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
This commit is contained in:
@@ -1394,7 +1394,7 @@ actual arch.
|
||||
# view validation
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
def _validate_view(self, node, model_name, editable=True, full=False):
|
||||
def _validate_view(self, node, model_name, view_type=None, editable=True, full=False):
|
||||
""" Validate the given architecture node, and return its corresponding
|
||||
NameManager.
|
||||
|
||||
@@ -1407,6 +1407,13 @@ actual arch.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
view_type = view_type or self.type
|
||||
if node.tag != view_type:
|
||||
self._raise_view_error(_(
|
||||
'The root node of a %(view_type)s view should be a <%(view_type)s>, not a <%(tag)s>',
|
||||
view_type=view_type, tag=node.tag,
|
||||
), node)
|
||||
|
||||
if model_name not in self.env:
|
||||
self._raise_view_error(_('Model not found: %(model)s', model=model_name), node)
|
||||
|
||||
@@ -1492,7 +1499,7 @@ actual arch.
|
||||
if len(searchpanels) > 1:
|
||||
self._raise_view_error(_('Search tag can only contain one search panel'), node)
|
||||
node.remove(searchpanels[0])
|
||||
self._validate_view(searchpanels[0], name_manager.model._name,
|
||||
self._validate_view(searchpanels[0], name_manager.model._name, view_type="searchpanel",
|
||||
editable=False, full=node_info['validate'])
|
||||
|
||||
def _validate_tag_field(self, node, name_manager, node_info):
|
||||
@@ -1531,7 +1538,7 @@ actual arch.
|
||||
continue
|
||||
node.remove(child)
|
||||
sub_manager = self._validate_view(
|
||||
child, field.comodel_name, editable=node_info['editable'], full=validate,
|
||||
child, field.comodel_name, view_type=child.tag, editable=node_info['editable'], full=validate,
|
||||
)
|
||||
for fname, groups_uses in sub_manager.mandatory_parent_fields.items():
|
||||
for groups, use in groups_uses.items():
|
||||
@@ -1645,7 +1652,7 @@ actual arch.
|
||||
groupby_node = E.groupby(*node)
|
||||
# validate the node as a nested view
|
||||
sub_manager = self._validate_view(
|
||||
groupby_node, field.comodel_name, editable=False, full=node_info['validate'],
|
||||
groupby_node, field.comodel_name, view_type="groupby", editable=False, full=node_info['validate'],
|
||||
)
|
||||
name_manager.has_field(node, name)
|
||||
for fname, groups_uses in sub_manager.mandatory_parent_fields.items():
|
||||
|
||||
@@ -1548,6 +1548,11 @@ class TestViews(ViewCase):
|
||||
kw.setdefault('active', True)
|
||||
if 'arch_db' in kw:
|
||||
arch_db = kw['arch_db']
|
||||
if kw.get('inherit_id'):
|
||||
self.cr.execute('SELECT type FROM ir_ui_view WHERE id = %s', [kw['inherit_id']])
|
||||
kw['type'] = self.cr.fetchone()[0]
|
||||
else:
|
||||
kw['type'] = etree.fromstring(arch_db).tag
|
||||
kw['arch_db'] = Json({'en_US': arch_db}) if self.env.lang == 'en_US' else Json({'en_US': arch_db, self.env.lang: arch_db})
|
||||
|
||||
keys = sorted(kw)
|
||||
@@ -1558,6 +1563,32 @@ class TestViews(ViewCase):
|
||||
self.cr.execute(query, kw)
|
||||
return self.cr.fetchone()[0]
|
||||
|
||||
def test_view_root_node_matches_view_type(self):
|
||||
view = self.View.create({
|
||||
'name': 'foo',
|
||||
'model': 'ir.ui.view',
|
||||
'arch': """
|
||||
<form>
|
||||
</form>
|
||||
""",
|
||||
})
|
||||
self.assertEqual(view.type, 'form')
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
self.View.create({
|
||||
'name': 'foo',
|
||||
'model': 'ir.ui.view',
|
||||
'type': 'form',
|
||||
'arch': """
|
||||
<data>
|
||||
<div>
|
||||
</div>
|
||||
<form>
|
||||
</form>
|
||||
</data>
|
||||
""",
|
||||
})
|
||||
|
||||
def test_custom_view_validation(self):
|
||||
model = 'ir.actions.act_url'
|
||||
validate = partial(self.View._validate_custom_views, model)
|
||||
|
||||
Reference in New Issue
Block a user