[FIX] ir.ui.view: properly validate newly created inheriting views
authorChristophe Simonis <chs@openerp.com>
Thu, 12 Sep 2013 14:10:18 +0000 (16:10 +0200)
committerChristophe Simonis <chs@openerp.com>
Thu, 12 Sep 2013 14:10:18 +0000 (16:10 +0200)
    When a new inheriting view is imported during a module
    installation, it is validated thanks to the _constraints
    on the ir.ui.view model. However the validation uses
    a rather convoluted system for validating the whole
    view tree at once (root view + all inherited changes)
    while only taking into account the views that belong
    to modules that are currently loaded.

    This complicated system is necessary to be able to
    operate on-the-fly at any point during the registry
    loading/initialization.

    Now because _constraints are checked during create()
    this particular validation happens *before* the
    external ID (ir.model.data entry) of that new view
    can be created (it obviously needs to wait until
    the view record is inserted). As a consequence the
    view validation cannot determine the module to
    which that new view belongs, and was erroneously
    ignoring it.
    Changing the view filtering to also include views
    that have triggered this check.
    Manually created views are not check during registry
    update.

bzr revid: chs@openerp.com-20130912141018-qmcyase8zqov9d01

openerp/addons/base/ir/ir_ui_view.py
openerp/addons/base/tests/__init__.py
openerp/addons/base/tests/test_views.py [new file with mode: 0644]
openerp/osv/orm.py

index 7a14bf5..393e5cf 100644 (file)
@@ -125,11 +125,15 @@ class view(osv.osv):
         try:
             fvg = self.pool.get(view.model).fields_view_get(cr, uid, view_id=view.id, view_type=view.type, context=context)
             return fvg['arch']
-        except:
+        except Exception:
             _logger.exception("Can't render view %s for model: %s", view.xml_id, view.model)
             return False
 
     def _check_xml(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        context['check_view_ids'] = ids
+
         for view in self.browse(cr, uid, ids, context):
             # Sanity check: the view should not break anything upon rendering!
             view_arch_utf8 = self._check_render_view(cr, uid, view, context=context)
@@ -175,13 +179,15 @@ class view(osv.osv):
            :rtype: list of tuples
            :return: [(view_arch,view_id), ...]
         """
+
         user_groups = frozenset(self.pool.get('res.users').browse(cr, 1, uid, context).groups_id)
         if self.pool._init:
             # Module init currently in progress, only consider views from modules whose code was already loaded 
+            check_view_ids = context and context.get('check_view_ids') or (0,)
             query = """SELECT v.id FROM ir_ui_view v LEFT JOIN ir_model_data md ON (md.model = 'ir.ui.view' AND md.res_id = v.id)
-                       WHERE v.inherit_id=%s AND v.model=%s AND (md.module IS NULL or md.module in %s)  
+                       WHERE v.inherit_id=%s AND v.model=%s AND (md.module in %s OR v.id in %s)
                        ORDER BY priority"""
-            query_params = (view_id, model, tuple(self.pool._init_modules))
+            query_params = (view_id, model, tuple(self.pool._init_modules), tuple(check_view_ids))
         else:
             # Modules fully loaded, consider all views
             query = """SELECT v.id FROM ir_ui_view v
index d891bc0..f4432f6 100644 (file)
@@ -4,6 +4,7 @@ import test_ir_attachment
 import test_ir_values
 import test_menu
 import test_search
+import test_views
 
 checks = [
     test_base,
@@ -12,4 +13,5 @@ checks = [
     test_ir_values,
     test_menu,
     test_search,
+    test_views,
 ]
diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py
new file mode 100644 (file)
index 0000000..74f6f84
--- /dev/null
@@ -0,0 +1,44 @@
+import unittest2
+
+import openerp.tests.common as common
+from openerp.osv.orm import except_orm
+from openerp.tools import mute_logger
+
+class test_views(common.TransactionCase):
+
+    @mute_logger('openerp.osv.orm', 'openerp.addons.base.ir.ir_ui_view')
+    def test_00_init_check_views(self):
+        Views = self.registry('ir.ui.view')
+
+        self.assertTrue(Views.pool._init)
+
+        error_msg = "Invalid XML for View Architecture"
+        # test arch check is call for views without xmlid during registry initialization
+        with self.assertRaisesRegexp(except_orm, error_msg):
+            Views.create(self.cr, self.uid, {
+                'name': 'Test View #1',
+                'model': 'ir.ui.view',
+                'arch': """<?xml version="1.0"?>
+                            <tree>
+                              <field name="test_1"/>
+                            </tree>
+                        """,
+            })
+
+        # same for inherited views
+        with self.assertRaisesRegexp(except_orm, error_msg):
+            # Views.pudb = True
+            Views.create(self.cr, self.uid, {
+                'name': 'Test View #2',
+                'model': 'ir.ui.view',
+                'inherit_id': self.browse_ref('base.view_view_tree').id,
+                'arch': """<?xml version="1.0"?>
+                            <xpath expr="//field[@name='name']" position="after">
+                              <field name="test_2"/>
+                            </xpath>
+                        """,
+            })
+
+
+if __name__ == '__main__':
+    unittest2.main()
index 9ee5d54..6dbc91d 100644 (file)
@@ -2190,7 +2190,7 @@ class BaseModel(object):
                 are applied
 
             """
-            sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, user, inherit_id, self._name)
+            sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, user, inherit_id, self._name, context=context)
             for (view_arch, view_id) in sql_inherit:
                 source = apply_inheritance_specs(source, view_arch, view_id)
                 source = apply_view_inheritance(cr, user, source, view_id)