[FIX] web: checks rpc responses in web.ajax
Before this commit, load_action and load_views were never resolved in case of internet connection loss. It's because the call is triggered by web.rpc direcly who uses ajax.rpc without any response check. Now the rpc response is checked in web.ajax. Thereby all responses are handled whether they come from session.rpc or rpc.query. Plus, it was not the responsibility of the session to check the rpc responses. Steps to reproduce the issue: (1) load_action: - Go to the app switcher for the first time - Force disconnected from the network -> No notification appears and the user aren't notify (2) load_views (mobile only): - Go to Sales -> Quotation (In this case, the first call is 'load_views' because we need to force to load some views like kanban view) - Force disconnected from the network -> No notification appears and the user aren't notify Note: It's now important to notify the user about connection loss because a recent improvement in mobile app replaces the 'retry screen' and lets the webclient handle connection issues by itself. The single odoo mobile app is supposed to work with all databases from 10.0.
This commit is contained in:
@@ -170,7 +170,7 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
|
||||
core.bus.on('connection_restored', this, this._onConnectionRestored);
|
||||
|
||||
// crash manager integration
|
||||
session.on('error', crash_manager, crash_manager.rpc_error);
|
||||
core.bus.on('rpc_error', crash_manager, crash_manager.rpc_error);
|
||||
window.onerror = function (message, file, line, col, error) {
|
||||
// Scripts injected in DOM (eg: google API's js files) won't return a clean error on window.onerror.
|
||||
// The browser will just give you a 'Script error.' as message and nothing else for security issue.
|
||||
|
||||
@@ -26,9 +26,9 @@ var Loading = Widget.extend({
|
||||
this._super(parent);
|
||||
this.count = 0;
|
||||
this.blocked_ui = false;
|
||||
session.on("request", this, this.request_call);
|
||||
session.on("response", this, this.response_call);
|
||||
session.on("response_failed", this, this.response_call);
|
||||
core.bus.on('rpc_request', this, this.request_call);
|
||||
core.bus.on("rpc_response", this, this.response_call);
|
||||
core.bus.on("rpc_response_failed", this, this.response_call);
|
||||
},
|
||||
destroy: function() {
|
||||
this.on_rpc_event(-this.count);
|
||||
|
||||
@@ -5,7 +5,15 @@ var core = require('web.core');
|
||||
var utils = require('web.utils');
|
||||
var time = require('web.time');
|
||||
|
||||
function genericJsonRpc (fct_name, params, fct) {
|
||||
function genericJsonRpc (fct_name, params, settings, fct) {
|
||||
var shadow = settings.shadow || false;
|
||||
delete settings.shadow;
|
||||
if (!shadow) {
|
||||
core.bus.trigger('rpc_request');
|
||||
}
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var data = {
|
||||
jsonrpc: "2.0",
|
||||
method: fct_name,
|
||||
@@ -29,12 +37,56 @@ function genericJsonRpc (fct_name, params, fct) {
|
||||
return def.reject.apply(def, ["communication"].concat(_.toArray(arguments)));
|
||||
});
|
||||
// FIXME: jsonp?
|
||||
result.abort = function () { if (xhr.abort) xhr.abort(); };
|
||||
return result;
|
||||
deferred.abort = function () {
|
||||
deferred.reject('communication', $.Event(), 'abort', 'abort');
|
||||
if (xhr.abort) {
|
||||
xhr.abort();
|
||||
}
|
||||
};
|
||||
|
||||
result.then(function (result) {
|
||||
if (!shadow) {
|
||||
core.bus.trigger('rpc_response');
|
||||
}
|
||||
deferred.resolve(result);
|
||||
}, function (type, error, textStatus, errorThrown) {
|
||||
if (type === "server") {
|
||||
if (!shadow) {
|
||||
core.bus.trigger('rpc_response');
|
||||
}
|
||||
if (error.code === 100) {
|
||||
core.bus.trigger('invalidate_session');
|
||||
}
|
||||
deferred.reject(error, $.Event());
|
||||
} else {
|
||||
if (!shadow) {
|
||||
core.bus.trigger('rpc_response_failed');
|
||||
}
|
||||
var nerror = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
data: {
|
||||
type: "xhr"+textStatus,
|
||||
debug: error.responseText,
|
||||
objects: [error, errorThrown]
|
||||
},
|
||||
};
|
||||
deferred.reject(nerror, $.Event());
|
||||
}
|
||||
});
|
||||
deferred.fail(function () { // Allow deferred user to disable rpc_error call in fail
|
||||
deferred.fail(function (error, event) {
|
||||
if (!event.isDefaultPrevented()) {
|
||||
core.bus.trigger('rpc_error', error, event);
|
||||
}
|
||||
});
|
||||
});
|
||||
return deferred;
|
||||
}
|
||||
|
||||
function jsonRpc(url, fct_name, params, settings) {
|
||||
return genericJsonRpc(fct_name, params, function(data) {
|
||||
settings = settings || {};
|
||||
return genericJsonRpc(fct_name, params, settings, function(data) {
|
||||
return $.ajax(url, _.extend({}, settings, {
|
||||
url: url,
|
||||
dataType: 'json',
|
||||
@@ -47,7 +99,7 @@ function jsonRpc(url, fct_name, params, settings) {
|
||||
|
||||
function jsonpRpc(url, fct_name, params, settings) {
|
||||
settings = settings || {};
|
||||
return genericJsonRpc(fct_name, params, function(data) {
|
||||
return genericJsonRpc(fct_name, params, settings, function(data) {
|
||||
var payload_str = JSON.stringify(data, time.date_to_utc);
|
||||
var payload_url = $.param({r:payload_str});
|
||||
var force2step = settings.force2step || false;
|
||||
|
||||
@@ -49,6 +49,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
this.qweb_mutex = new concurrency.Mutex();
|
||||
this.currencies = {};
|
||||
this._groups_def = {};
|
||||
core.bus.on('invalidate_session', this, this._onInvalidateSession);
|
||||
},
|
||||
setup: function (origin, options) {
|
||||
// must be able to customize server
|
||||
@@ -327,31 +328,31 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
rpc: function (url, params, options) {
|
||||
var self = this;
|
||||
options = _.clone(options || {});
|
||||
var shadow = options.shadow || false;
|
||||
options.headers = _.extend({}, options.headers);
|
||||
if (odoo.debug) {
|
||||
options.headers["X-Debug-Mode"] = $.deparam($.param.querystring()).debug;
|
||||
}
|
||||
|
||||
delete options.shadow;
|
||||
|
||||
var deferred = $.Deferred();
|
||||
var deferred = self.check_session_id();
|
||||
var aborted = false;
|
||||
var xhrDef;
|
||||
deferred.abort = function () {
|
||||
aborted = true;
|
||||
if (xhrDef) {
|
||||
xhrDef.abort();
|
||||
} else {
|
||||
aborted = true;
|
||||
}
|
||||
};
|
||||
self.check_session_id().then(function () {
|
||||
|
||||
return deferred.then(function () {
|
||||
if (aborted) {
|
||||
return deferred.reject('communication', $.Event(), 'abort', 'abort');
|
||||
return $.Deferred().reject('communication', $.Event(), 'abort', 'abort');
|
||||
}
|
||||
// TODO: remove
|
||||
if (! _.isString(url)) {
|
||||
_.extend(options, url);
|
||||
url = url.url;
|
||||
}
|
||||
// TODO correct handling of timeouts
|
||||
if (! shadow)
|
||||
self.trigger('request');
|
||||
var fct;
|
||||
if (self.origin_server) {
|
||||
fct = ajax.jsonRpc;
|
||||
@@ -370,40 +371,9 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
url = self.url(url, null);
|
||||
options.session_id = self.session_id || '';
|
||||
}
|
||||
var p = fct(url, "call", params, options);
|
||||
deferred.abort = p.abort.bind(p); // Allow to abort the rpc call
|
||||
p = p.then(function (result) {
|
||||
if (! shadow)
|
||||
self.trigger('response');
|
||||
return deferred.resolve(result);
|
||||
}, function (type, error, textStatus, errorThrown) {
|
||||
if (type === "server") {
|
||||
if (! shadow)
|
||||
self.trigger('response');
|
||||
if (error.code === 100) {
|
||||
self.uid = false;
|
||||
}
|
||||
return deferred.reject(error, $.Event());
|
||||
} else {
|
||||
if (! shadow)
|
||||
self.trigger('response_failed');
|
||||
var nerror = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
data: {type: "xhr"+textStatus, debug: error.responseText, objects: [error, errorThrown] }
|
||||
};
|
||||
return deferred.reject(nerror, $.Event());
|
||||
}
|
||||
});
|
||||
return deferred.fail(function () { // Allow deferred user to disable rpc_error call in fail
|
||||
deferred.fail(function (error, event) {
|
||||
if (!event.isDefaultPrevented()) {
|
||||
self.trigger('error', error, event);
|
||||
}
|
||||
});
|
||||
});
|
||||
xhrDef = fct(url, "call", params, options);
|
||||
return xhrDef;
|
||||
});
|
||||
return deferred;
|
||||
},
|
||||
url: function (path, params) {
|
||||
params = _.extend(params || {});
|
||||
@@ -428,6 +398,17 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
getTZOffset: function (date) {
|
||||
return -new Date(date).getTimezoneOffset();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onInvalidateSession: function () {
|
||||
this.uid = false;
|
||||
},
|
||||
});
|
||||
|
||||
return Session;
|
||||
|
||||
Reference in New Issue
Block a user