Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
const $ = require('jquery');
const _ = require('underscore');
/**
* Network Interceptors
*
* Tool to easily intercept network responses in order
* to override or add behaviours on top of the usual ones
*/
function NetworkResponseInterceptor () {
this._originalAjax = $.ajax;
this._successInterceptors = [];
this._errorInterceptors = [];
this._urlPatterns = [];
}
NetworkResponseInterceptor.prototype.start = function () {
let onRequestStart = this._onRequestStart.bind(this);
this._onRequestStart = onRequestStart;
$.ajax = onRequestStart;
};
NetworkResponseInterceptor.prototype.stop = function () {
$.ajax = this._originalAjax;
};
NetworkResponseInterceptor.prototype.addURLPattern = function (pattern) {
this._urlPatterns.push(pattern);
};
NetworkResponseInterceptor.prototype.addSuccessInterceptor = function (interceptorFn) {
this._successInterceptors.push(interceptorFn);
};
NetworkResponseInterceptor.prototype.addErrorInterceptor = function (interceptorFn) {
this._errorInterceptors.push(interceptorFn);
};
NetworkResponseInterceptor.prototype._shouldListenToRequest = function (url) {
let patternChecks = this._urlPatterns.map(function (pattern) {
return url.indexOf(pattern) > -1;
});
return _.some(patternChecks);
};
NetworkResponseInterceptor.prototype._onRequestStart = function (url, options) {
let requestUrl = null;
let requestOptions = {};
if (typeof url === 'string') {
requestUrl = url;
} else if (typeof url === 'object' && url.url) {
requestUrl = url.url;
}
if (options) {
requestOptions = options;
} else if (typeof url === 'object') {
requestOptions = url;
}
if (!this._shouldListenToRequest(requestUrl)) {
return this._originalAjax.apply(this, arguments);
}
if (requestOptions.error || requestOptions.success) {
const errorCallback = requestOptions.error;
const successCallback = requestOptions.success;
const interceptErrorFn = function () {
this._applyErrorInterceptors.apply(this, arguments);
errorCallback && errorCallback.apply(this, arguments);
};
const interceptSuccessFn = function () {
this._applySuccessInterceptors.apply(this, arguments);
successCallback && successCallback.apply(this, arguments);
};
requestOptions.error = interceptErrorFn.bind(this);
requestOptions.success = interceptSuccessFn.bind(this);
}
return this._originalAjax(requestUrl, requestOptions);
};
NetworkResponseInterceptor.prototype._applyErrorInterceptors = function (xhr, textStatus, errorThrown) {
if (!this._errorInterceptors.length) {
return;
}
this._errorInterceptors.map(function (interceptorFunction) {
interceptorFunction(xhr, textStatus, errorThrown);
});
};
NetworkResponseInterceptor.prototype._applySuccessInterceptors = function (response, textStatus, xhr) {
if (!this._successInterceptors.length) {
return;
}
this._successInterceptors.map(function (interceptorFunction) {
interceptorFunction(response, textStatus, xhr);
});
};
module.exports = new NetworkResponseInterceptor();
module.exports.NetworkResponseInterceptor = NetworkResponseInterceptor;

View File

@@ -0,0 +1,61 @@
/**
* 403 Forbidden Network Error Interceptor
*
* This interceptor redirects 403 errors
* to their corresponding routes
*/
const LOGIN_ROUTE = '/login?error=session_expired';
const SESSION_EXPIRED = 'session_expired';
const MFA_REQUIRED = 'mfa_required';
const MFA_ROUTE = '/multifactor_authentication';
const MAINTENANCE_MODE = 'maintenance_mode';
const MAINTENANCE_MODE_ROUTE = '/maintenance_mode';
const LOCKOUT = 'lockout';
const LOCKOUT_ROUTE = '/lockout';
const subdomainMatch = /https?:\/\/([^.]+)/;
const redirectRoutes = {
[SESSION_EXPIRED]: LOGIN_ROUTE,
[MFA_REQUIRED]: MFA_ROUTE,
[MAINTENANCE_MODE]: MAINTENANCE_MODE_ROUTE,
[LOCKOUT]: LOCKOUT_ROUTE
};
module.exports = function (username) {
return function (xhr, textStatus, errorThrown) {
if (xhr.status !== 403) return;
const error = xhr.responseJSON && xhr.responseJSON.error;
const redirectRoute = redirectRoutes[error];
if (!redirectRoute) {
return;
}
URLFunctions.redirectTo(
URLFunctions.getRedirectURL(window.location.origin, redirectRoute, username)
);
};
};
const URLFunctions = {
getRedirectURL: function getRedirectURL (currentURLOrigin, route, username) {
if (!username) {
return currentURLOrigin + route;
}
const newURL = currentURLOrigin.replace(subdomainMatch, function () {
return username;
});
return `${window.location.protocol}//${newURL}${route}`;
},
redirectTo: function redirectTo (url) {
window.location = url;
}
};
module.exports.URLFunctions = URLFunctions;

View File

@@ -0,0 +1,23 @@
var Backbone = require('backbone');
/**
* Custom sync method to only allow a single request at a time,
* any prev ongoing request at a time of a sync call will be aborted.
*
* @example
* var MyModel = Backbone.Model.extend({
* // …
* sync: syncAbort,
*/
module.exports = function (method, self, opts) {
if (this._xhr) {
this._xhr.abort();
}
var xhr = this._xhr = Backbone.Model.prototype.sync.apply(this, arguments);
xhr.always(function () {
self._xhr = null;
});
return xhr;
};