From db7470757392baf9da571fd86a0e17f354328fcd Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 13 Jan 2012 15:58:32 +0100 Subject: [PATCH 1/4] [IMP] make chs's http session cleanup spam less spammy bzr revid: xmo@openerp.com-20120113145832-q6ogcwqnghfylys8 --- addons/web/common/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/common/http.py b/addons/web/common/http.py index 6e4cbaacaaa..681a38384a2 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -334,7 +334,7 @@ def session_context(request, storage_path, session_cookie='sessionid'): and not value.jsonp_requests and value._creation_time + (60*5) < time.time() # FIXME do not use a fixed value ): - _logger.info('remove session %s', key) + _logger.debug('remove session %s', key) del request.session[key] with session_lock: From a76f6d2a4efd17906c6ef1b80e5e5e9830c9307a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 13 Jan 2012 16:01:10 +0100 Subject: [PATCH 2/4] [FIX] concatenated JS files blowing up when not terminated with a semicolon If the final semicolon of an openerp module is forgotten and the next file starts with an expression (such as a parens, because it's a third-party module using the module pattern, see Backbone.js or jQuery for examples), the JS parser will not perform semicolon insertion and will instead try to execute the module's wrapper/initializer function by passing it whatever follows it (generally an other function). This usually results in an error and stuff blowing out everywhere for no obvious reason. Concatenation of JS files now adds an explicit semicolon between files (ideally it should only add one if it's missing, but that would require backtracking in the file while skipping comments &etc, can't be arsed and double-semicolons don't hurt much) to avoid this issue. bzr revid: xmo@openerp.com-20120113150110-47j90oishtjrib7s --- addons/web/controllers/main.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 7081ce3ce32..ed515f5b4f1 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -56,12 +56,15 @@ def concat_xml(file_list): return ElementTree.tostring(root, 'utf-8'), files_timestamp -def concat_files(file_list, reader=None): +def concat_files(file_list, reader=None, intersperse=""): """ Concatenate file content return (concat,timestamp) concat: concatenation of file content, read by `reader` timestamp: max(os.path.getmtime of file_list) """ + if not file_list: + return '', None + if reader is None: def reader(f): with open(f) as fp: @@ -75,7 +78,7 @@ def concat_files(file_list, reader=None): files_timestamp = ftime files_content.append(reader(fname)) - files_concat = "".join(files_content) + files_concat = intersperse.join(files_content) return files_concat,files_timestamp html_template = """ @@ -180,7 +183,7 @@ class WebClient(openerpweb.Controller): @openerpweb.httprequest def js(self, req, mods=None): files = [f[0] for f in self.manifest_glob(req, mods, 'js')] - content,timestamp = concat_files(files) + content, timestamp = concat_files(files, intersperse=';') # TODO use timestamp to set Last mofified date and E-tag return req.make_response(content, [('Content-Type', 'application/javascript')]) @@ -431,7 +434,7 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def modules(self, req): # Compute available candidates module - loadable = openerpweb.addons_manifest.iterkeys() + loadable = openerpweb.addons_manifest loaded = req.config.server_wide_modules candidates = [mod for mod in loadable if mod not in loaded] From c54d3337e62aba92737a431648b9a352598c066c Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 13 Jan 2012 16:06:41 +0100 Subject: [PATCH 3/4] [FIX] avoid having the XML concatenator blow up when passed an empty list of files ~/projects/tiny/web/current turns out ElementTree has a hard time XML-serializing ``None`` (who'd have guessed...), which is what it gets told to do when concat_xml is called with an empty list of files. Return an empty string and no timestamp (should probably be one there at some point, but...) and fix the QWeb loader to not do anything when it gets an empty template file. bzr revid: xmo@openerp.com-20120113150641-6i3ot1jg7r3kpw3d --- addons/web/controllers/main.py | 3 +++ addons/web/static/src/js/core.js | 1 + 2 files changed, 4 insertions(+) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index ed515f5b4f1..191f184da5b 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -37,6 +37,9 @@ def concat_xml(file_list): concat: concatenation of file content timestamp: max(os.path.getmtime of file_list) """ + if not file_list: + return '', None + root = None files_timestamp = 0 for fname in file_list: diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 0584c49f6b2..81f13713543 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -738,6 +738,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. _.each(files, function(file) { self.qweb_mutex.exec(function() { return self.rpc('/web/proxy/load', {path: file}).pipe(function(xml) { + if (!xml) { return; } openerp.web.qweb.add_template(_.str.trim(xml)); }); }); From 1eff27c138e45cb868e1a665ad9f1eea01591dd5 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 13 Jan 2012 16:08:29 +0100 Subject: [PATCH 4/4] [FIX] remember to load not-yet-loaded modules after they've been installed, improve load_modules to be incremental (load only modules which are not installed) bzr revid: xmo@openerp.com-20120113150829-s7ejfivy5kyqvy3f --- addons/web/static/src/js/chrome.js | 7 +++++-- addons/web/static/src/js/core.js | 18 +++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 7af729205be..32a70d587a7 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -1124,8 +1124,11 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie this.$element.children().remove(); }, do_reload: function() { - return this.session.session_reload().pipe( - $.proxy(this.menu, 'do_reload')); + var self = this; + return this.session.session_reload().pipe(function () { + openerp.connection.load_modules(true).pipe( + self.menu.proxy('do_reload')); }); + }, do_notify: function() { var n = this.notification; diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 81f13713543..b36e576ae47 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -676,27 +676,31 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. }, /** * Load additional web addons of that instance and init them + * + * @param {Boolean} [no_session_valid_signal=false] prevents load_module from triggering ``on_session_valid``. */ - load_modules: function() { + load_modules: function(no_session_valid_signal) { var self = this; return this.rpc('/web/session/modules', {}).pipe(function(result) { - self.module_list = result; var lang = self.user_context.lang; var params = { mods: ["web"].concat(result), lang: lang}; - var modules = self.module_list.join(','); + var to_load = _.difference(result, self.module_list).join(','); + self.module_list = result; return $.when( - self.rpc('/web/webclient/csslist', {mods: modules}, self.do_load_css), - self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb), + self.rpc('/web/webclient/csslist', {mods: to_load}, self.do_load_css), + self.rpc('/web/webclient/qweblist', {mods: to_load}).pipe(self.do_load_qweb), self.rpc('/web/webclient/translations', params).pipe(function(trans) { openerp.web._t.database.set_bundle(trans); var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"]; - return self.rpc('/web/webclient/jslist', {mods: modules}).pipe(function(files) { + return self.rpc('/web/webclient/jslist', {mods: to_load}).pipe(function(files) { return self.do_load_js(file_list.concat(files)); }); }) ).then(function() { self.on_modules_loaded(); - self.on_session_valid(); + if (!no_session_valid_signal) { + self.on_session_valid(); + } }); }); },