diff --git a/addons/board/static/src/js/dashboard.js b/addons/board/static/src/js/dashboard.js index 10818ef20a5..4bdf33c3d32 100644 --- a/addons/board/static/src/js/dashboard.js +++ b/addons/board/static/src/js/dashboard.js @@ -179,6 +179,8 @@ var DashBoard = form_common.FormWidget.extend({ action = result, view_mode = action_attrs.view_mode; + if (!action) { return; } + // evaluate action_attrs context and domain action_attrs.context_string = action_attrs.context; action_attrs.context = pyeval.eval( diff --git a/addons/fleet/fleet.py b/addons/fleet/fleet.py index 92b933df210..c77a6c54324 100644 --- a/addons/fleet/fleet.py +++ b/addons/fleet/fleet.py @@ -177,6 +177,7 @@ class fleet_vehicle(osv.Model): if context is None: context = {} if context.get('xml_id'): + context.pop('group_by', False) res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet', context['xml_id'], context=context) res['context'] = context res['context'].update({'default_vehicle_id': ids[0]}) diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index 8d49c129947..a52574a2710 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -133,6 +133,7 @@ TRANSLATED_ATTRS_RE = re.compile(r"@(%s)\b" % "|".join(TRANSLATED_ATTRS)) class view(osv.osv): _name = 'ir.ui.view' + _parent_name = 'inherit_id' # used for recursion check def _get_model_data(self, cr, uid, ids, fname, args, context=None): result = dict.fromkeys(ids, False) @@ -283,6 +284,10 @@ class view(osv.osv): return True def _check_xml(self, cr, uid, ids, context=None): + # As all constraints are verified on create/write, we must re-check that there is no + # recursion before calling `read_combined` to avoid an infinite loop. + if not self._check_recursion(cr, uid, ids, context=context): + return True # pretend arch is valid to avoid misleading user about the error. if context is None: context = {} context = dict(context, check_view_ids=ids) @@ -322,6 +327,7 @@ class view(osv.osv): ] _constraints = [ (_check_xml, 'Invalid view definition', ['arch', 'arch_base']), + (osv.osv._check_recursion, 'You cannot create recursive inherited views.', ['inherit_id']), ] def _auto_init(self, cr, context=None): diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index 74d36e0ad00..79c37cb18c6 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -9,6 +9,7 @@ from lxml.builder import E from psycopg2 import IntegrityError +from openerp.exceptions import ValidationError from openerp.tests import common import openerp.tools @@ -243,6 +244,25 @@ class TestViewInheritance(ViewCase): self.View.default_view( self.cr, self.uid, model=self.model, view_type='graph')) + def test_no_recursion(self): + r1 = self.makeView('R1') + with self.assertRaises(ValidationError), self.cr.savepoint(): + self.View.write(self.cr, self.uid, r1, {'inherit_id': r1}) + + r2 = self.makeView('R2', r1) + r3 = self.makeView('R3', r2) + with self.assertRaises(ValidationError), self.cr.savepoint(): + self.View.write(self.cr, self.uid, r2, {'inherit_id': r3}) + + with self.assertRaises(ValidationError), self.cr.savepoint(): + self.View.write(self.cr, self.uid, r1, {'inherit_id': r3}) + + with self.assertRaises(ValidationError), self.cr.savepoint(): + self.View.write(self.cr, self.uid, r1, { + 'inherit_id': r1, + 'arch': self.arch_for('itself', parent=True), + }) + class TestApplyInheritanceSpecs(ViewCase): """ Applies a sequence of inheritance specification nodes to a base architecture. IO state parameters (cr, uid, model, context) are used for