From ebf13837858f3572f0d4959d639a4f47d32935ba Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 19 Jun 2012 12:14:25 +0200 Subject: [PATCH 01/85] ir.ui.view: type field can be a functional field. bzr revid: vmt@openerp.com-20120619101425-u73r47zdhsg7ecma --- openerp/addons/base/ir/ir_ui_view.py | 15 ++++++++++++--- openerp/addons/base/module/module.py | 9 ++++++--- openerp/tools/convert.py | 5 +++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index ac3644a28f7..d3b090c45d4 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -47,11 +47,20 @@ view_custom() class view(osv.osv): _name = 'ir.ui.view' + + def _type_field(self, cr, uid, ids, name, args, context=None): + records = self.browse(cr, uid, ids, context) + result = dict((r.id, etree.fromstring(r.arch.encode('utf8')).tag) for r in records) + return result + + def _set_type_field(self, cr, uid, ids, name, value, args, context=None): + print "ignoring", value + _columns = { 'name': fields.char('View Name',size=64, required=True), 'model': fields.char('Object', size=64, required=True, select=True), 'priority': fields.integer('Sequence', required=True), - 'type': fields.selection(( + 'type': fields.function(_type_field, fnct_inv=_set_type_field, type='selection', selection=[ ('tree','Tree'), ('form','Form'), ('mdx','mdx'), @@ -60,7 +69,7 @@ class view(osv.osv): ('diagram','Diagram'), ('gantt', 'Gantt'), ('kanban', 'Kanban'), - ('search','Search')), 'View Type', required=True, select=True), + ('search','Search')], string='View Type', required=True, select=True, store=True), 'arch': fields.text('View Architecture', required=True), 'inherit_id': fields.many2one('ir.ui.view', 'Inherited View', ondelete='cascade', select=True), 'field_parent': fields.char('Child Field',size=64), @@ -133,7 +142,7 @@ class view(osv.osv): super(view, self)._auto_init(cr, context) cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_ui_view_model_type_inherit_id\'') if not cr.fetchone(): - cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, type, inherit_id)') + cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)') def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None): """Retrieves the architecture of views that inherit from the given view, from the sets of diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index d75f330afa2..1a7b5a9f9ae 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -138,14 +138,17 @@ class module(osv.osv): # We use try except, because views or menus may not exist. try: res_mod_dic = res[module_rec.id] - for v in view_obj.browse(cr, uid, imd_models.get('ir.ui.view', []), context=context): + view_ids = filter(None, imd_models.get('ir.ui.view', [])) + for v in view_obj.browse(cr, uid, view_ids, context=context): aa = v.inherit_id and '* INHERIT ' or '' res_mod_dic['views_by_module'].append(aa + v.name + '('+v.type+')') - for rx in report_obj.browse(cr, uid, imd_models.get('ir.actions.report.xml', []), context=context): + report_ids = imd_models.get('ir.actions.report.xml', []) + for rx in report_obj.browse(cr, uid, filter(None, report_ids), context=context): res_mod_dic['reports_by_module'].append(rx.name) - for um in menu_obj.browse(cr, uid, imd_models.get('ir.ui.menu', []), context=context): + menu_ids = imd_models.get('ir.ui.menu', []) + for um in menu_obj.browse(cr, uid, filter(None, menu_ids), context=context): res_mod_dic['menus_by_module'].append(um.complete_name) except KeyError, e: _logger.warning( diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py index c2c610c16af..a46a6663217 100644 --- a/openerp/tools/convert.py +++ b/openerp/tools/convert.py @@ -605,8 +605,9 @@ form: module.record_id""" % (xml_id,) "Verify that this is a window action or add a type argument." % (a_action,) action_type,action_mode,action_name,view_id,target = rrres if view_id: - cr.execute('SELECT type FROM ir_ui_view WHERE id=%s', (int(view_id),)) - action_mode, = cr.fetchone() + cr.execute('SELECT arch FROM ir_ui_view WHERE id=%s', (int(view_id),)) + arch, = cr.fetchone() + action_mode = etree.fromstring(arch.encode('utf8')).tag cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%s ORDER BY sequence LIMIT 1', (int(a_id),)) if cr.rowcount: action_mode, = cr.fetchone() From 2666ab3fe024c162b2a9efacb540b214010fccc1 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 22 Jun 2012 15:10:04 +0200 Subject: [PATCH 02/85] [IMP] ir.ui.view: Added assertion-based checks. bzr revid: vmt@openerp.com-20120622131004-stn7tf68xph3f278 --- openerp/addons/base/ir/ir_ui_view.py | 13 +++++--- openerp/tests/__init__.py | 2 ++ openerp/tests/test_view_validation.py | 44 +++++++++++++++++++++++++++ openerp/tools/view_validation.py | 12 ++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 openerp/tests/test_view_validation.py create mode 100644 openerp/tools/view_validation.py diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index d3b090c45d4..7601c4f44fc 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -24,6 +24,7 @@ from lxml import etree from tools import graph from tools.safe_eval import safe_eval as eval import tools +from tools.view_validation import valid_view import os import logging @@ -53,14 +54,11 @@ class view(osv.osv): result = dict((r.id, etree.fromstring(r.arch.encode('utf8')).tag) for r in records) return result - def _set_type_field(self, cr, uid, ids, name, value, args, context=None): - print "ignoring", value - _columns = { 'name': fields.char('View Name',size=64, required=True), 'model': fields.char('Object', size=64, required=True, select=True), 'priority': fields.integer('Sequence', required=True), - 'type': fields.function(_type_field, fnct_inv=_set_type_field, type='selection', selection=[ + 'type': fields.function(_type_field, type='selection', selection=[ ('tree','Tree'), ('form','Form'), ('mdx','mdx'), @@ -85,6 +83,11 @@ class view(osv.osv): # Holds the RNG schema _relaxng_validator = None + def create(self, cr, uid, values, context=None): + if 'type' in values: + _logger.warning("Setting the `type` field is deprecated in the `ir.ui.view` model.") + return super(osv.osv, self).create(cr, uid, values, context) + def _relaxng(self): if not self._relaxng_validator: frng = tools.file_open(os.path.join('base','rng','view.rng')) @@ -132,6 +135,8 @@ class view(osv.osv): for error in validator.error_log: _logger.error(tools.ustr(error)) return False + if not valid_view(view_arch): + return False return True _constraints = [ diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py index 5fccb07a082..fb4b937208e 100644 --- a/openerp/tests/__init__.py +++ b/openerp/tests/__init__.py @@ -11,6 +11,7 @@ See the :ref:`test-framework` section in the :ref:`features` list. import test_expression import test_ir_sequence import test_orm +import test_view_validation fast_suite = [ test_ir_sequence, @@ -19,6 +20,7 @@ fast_suite = [ checks = [ test_expression, test_orm, + test_view_validation, ] # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tests/test_view_validation.py b/openerp/tests/test_view_validation.py new file mode 100644 index 00000000000..1773556d8ea --- /dev/null +++ b/openerp/tests/test_view_validation.py @@ -0,0 +1,44 @@ +# This test can be run stand-alone with something like: +# > PYTHONPATH=. python2 openerp/tests/test_view_validation.py + +from lxml import etree +from StringIO import StringIO +import unittest2 + +import openerp +from openerp.tools.view_validation import valid_page_in_book, valid_view + +invalid_page = etree.parse(StringIO('''\ +
+ +
+ + +
+
+
+''')).getroot() + +valid_page = etree.parse(StringIO('''\ +
+ +
+ + +
+
+
+''')).getroot() + +class test_view_validation(unittest2.TestCase): + """ Test the view validation code (but not the views themselves). """ + + def test_page_validation(self): + assert not valid_page_in_book(invalid_page) + assert valid_page_in_book(valid_page) + + assert not valid_view(invalid_page) + assert valid_view(valid_page) + +if __name__ == '__main__': + unittest2.main() diff --git a/openerp/tools/view_validation.py b/openerp/tools/view_validation.py new file mode 100644 index 00000000000..0f1609b8376 --- /dev/null +++ b/openerp/tools/view_validation.py @@ -0,0 +1,12 @@ +""" View validation code (using assertions, not the RNG schema). """ + +def valid_page_in_book(arch): + """A `page` node must be below a `book` node.""" + return not arch.xpath('//page[not(ancestor::notebook)]') + +def valid_view(arch): + if arch.tag == 'form': + for pred in [valid_page_in_book]: + if not pred(arch): + return False + return True From 78ba98baa0dec11cd0514abd27140f27acb8b352 Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Tue, 3 Jul 2012 11:37:37 +0530 Subject: [PATCH 03/85] [ADD]: Add validation for view bzr revid: aja@tinyerp.com-20120703060737-cnnuzzfc8yfa8rcd --- openerp/tests/test_view_validation.py | 163 +++++++++++++++++++++++--- openerp/tools/view_validation.py | 92 +++++++++++++++ 2 files changed, 238 insertions(+), 17 deletions(-) diff --git a/openerp/tests/test_view_validation.py b/openerp/tests/test_view_validation.py index 1773556d8ea..a9b6683492e 100644 --- a/openerp/tests/test_view_validation.py +++ b/openerp/tests/test_view_validation.py @@ -6,39 +6,168 @@ from StringIO import StringIO import unittest2 import openerp -from openerp.tools.view_validation import valid_page_in_book, valid_view +from openerp.tools.view_validation import * -invalid_page = etree.parse(StringIO('''\ -
+invalid_form = etree.parse(StringIO('''\ + +