Commit fcce0554 authored by Pedro Eduardo Trujillo's avatar Pedro Eduardo Trujillo
Browse files

Crea RestManager desde el inicio, intercepta reqs

Ahora RestManager está disponible para toda la app, no solo para la
parte interna (antes y después del login). Esto hace posible integrar
las peticiones del módulo Credentials con RestManager.
Del mismo modo, RestManager ahora es el encargado de interceptar todas
las peticiones externas, para evaluar si ha de añadir cabeceras de
autentificación antes de lanzarlas.
parent 22cdaf62
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ define([
	, 'redmic/modules/base/MetaTags'
	, 'redmic/modules/base/_Module'
	, 'redmic/modules/base/Loading'
	, 'redmic/modules/store/RestManagerImpl'
	, 'templates/LoadingCustom'
], function(
	InnerApp
@@ -49,6 +50,7 @@ define([
	, MetaTags
	, _Module
	, Loading
	, RestManagerImpl
	, LoadingCustomTemplate
) {

@@ -145,6 +147,10 @@ define([

		_initialize: function() {

			new RestManagerImpl({
				parentChannel: this.ownChannel
			});

			new CommunicationCenter({
				parentChannel: this.ownChannel
			});
+0 −7
Original line number Diff line number Diff line
@@ -10,7 +10,6 @@ define([
	, 'redmic/base/Credentials'
	, 'redmic/modules/selector/Selector'
	, 'redmic/modules/components/Sidebar/MainSidebarImpl'
	, 'redmic/modules/store/RestManagerImpl'
	, 'redmic/modules/notification/Notification'
	, 'redmic/modules/socket/_IngestData'
	, 'redmic/modules/socket/_Report'
@@ -29,7 +28,6 @@ define([
	, Credentials
	, Selector
	, MainSidebarImpl
	, RestManagerImpl
	, Notification
	, _IngestData
	, _Report
@@ -177,10 +175,6 @@ define([
			//	tags:
			//		private

			new RestManagerImpl({
				parentChannel: this.ownChannel
			});

			new Selector({
				parentChannel: this.ownChannel
			});
@@ -297,7 +291,6 @@ define([
			// TODO reemplazo a destroy de todo 'app', eliminar cuando router no comparta canal y destruir solo 'app'
			this._publish(this.topbar.getChannel('DESTROY'));
			this._publish(this.sidebar.getChannel('DESTROY'));
			this._publish(this._buildChannel(this.storeChannel, this.actions.DESTROY));
			this._publish(this._buildChannel(this.selectorChannel, this.actions.DESTROY));
			this._publish(this._buildChannel(this.managerChannel, this.actions.DESTROY));
			this._publish(this._buildChannel(this.taskChannel, this.actions.DESTROY));
+26 −128
Original line number Diff line number Diff line
@@ -2,35 +2,26 @@ define([
	'app/redmicConfig'
	, 'dojo/_base/declare'
	, 'dojo/_base/lang'
	, 'dojo/request'
	, 'dojo/request/notify'
	, 'dojo/request/registry'
	, 'redmic/modules/base/_Module'
	, 'redmic/modules/base/_Store'
	, 'redmic/base/Credentials'
], function(
	redmicConfig
	, declare
	, lang
	, request
	, notify
	, registry
	, _Module
	, _Store
	, Credentials
) {
	return declare(_Module, {

	return declare([_Module, _Store], {
		//	Summary:
		//		Módulo para manejar las credenciales de los usuarios.
		//	Description:
		//		Obtiene las credenciales del servidor y escucha las peticiones para obtener información de las mismas,
		//		además de publicar cambios.
		//		También maneja errores de permisos en peticiones y les añade cabeceras de autentificación.
		//		Obtiene las credenciales del servidor y escucha cambios relativos a las mismas, publicando los cambios.

		//	_filteredUrls: Array
		//		Define las URLs a las que no hay que añadirle caberas de autentificación
		//	_loginPath: String
		//		Ruta correspondiente a la vista de acceso
		//	_serverUrlPrefix: String
		//		Prefijo de rutas hacia el servidor

		constructor: function(args) {

@@ -55,31 +46,15 @@ define([
					REQUEST_FAILED: 'requestFailed'
				},

				_filteredUrls: [
					'token',
					'reCaptcha',
					'register',
					'resettingRequest',
					'resettingSetPassword',
					'activateAccount'
				],
				_loginPath: '/login',
				_apiUrl: 'api'
				_loginPath: '/login'
			};

			lang.mixin(this, this.config, args);

			this._prepareRequestHandlers();
			this._initializeCredentials();
			this._listenCredentials();
		},

		_prepareRequestHandlers: function() {

			notify('error', lang.hitch(this, this._requestErrorHandler));
			registry.register(lang.hitch(this, this._preRequestHandler), request);
		},

		_initializeCredentials: function() {

			if (!Credentials.get('selectIds')) {
@@ -201,39 +176,30 @@ define([
			//	tags:
			//		private

			var headers = {
				'Content-Type': 'application/json',
				'Accept': 'application/javascript, application/json'
			};

			var envDfd = window.env;
			if (envDfd) {
				envDfd.then(lang.hitch(this, function(envData) {

					this._apiUrl = envData.apiUrl;
					this.target = redmicConfig.getServiceUrl(redmicConfig.services.profile, envData) + '/';

					var target = redmicConfig.getServiceUrl(redmicConfig.services.profile, envData) + '/';
					request(target, {
						method: 'GET',
						handleAs: 'json',
						headers: headers
					}).then(
						lang.hitch(this, this._onGetCredentialsSuccess),
						lang.hitch(this, this._onGetCredentialsError));
					this._emitEvt('GET', {
						target: this.target
					});
				}));
			}
		},

		_onGetCredentialsSuccess: function(res) {
		_itemAvailable: function(res) {

			var data = res.data[0];

			var success = res.success,
				data = res.body[0];
			if (!data) {
				Credentials.set('accessToken', null);
				return;
			}

			this.dataCredentials = data;

			if (!success) {
				Credentials.set('accessToken', null);
			} else {
			Credentials.set('userId', data.id.toString());
			Credentials.set('userName', data.firstName);
			Credentials.set('userEmail', data.email);
@@ -243,79 +209,11 @@ define([
			this._emitEvt('GET_CREDENTIALS', {
				found: !!Credentials.get('accessToken')
			});
			}
		},

		_onGetCredentialsError: function(err) {
		_errorAvailable: function(err) {

			this._emitEvt('REQUEST_FAILED');
		},

		_requestErrorHandler: function(err) {
			//	summary:
			//		Se ejecuta cuando un request produce un error y permite manejarlo
			//	tags:
			//		private
			//	err:
			//		respuesta con el error del request

			var res = err.response,
				status = res.status;

			if (status === 401) {
				this._onRequestPermissionError(res);
			} else if (status === 502) {
				this._onRequestReachabilityError(res);
			}
		},

		_onRequestPermissionError: function(res) {

			// TODO notificar al usuario que intentó acceder a algo para lo que no tenía permiso (token caducado o con
			// privilegios insuficientes)
			Credentials.set('accessToken', null);
		},

		_onRequestReachabilityError: function(res) {

			// TODO notificar al usuario que hubo un error de conexión y ofrecerle recargar (para que pueda actuar
			// sobre la página actual antes de recargar)
		},

		_preRequestHandler: function(url, options) {
			//	summary:
			//		Se ejecuta antes de hacer un request y nos permite añadir cabeceras
			//	tags:
			//		private
			//	url:
			//		url del servicio
			//	options:
			//		opciones del request (headers...)

			var urlSplitted = url.split('/'),
				lastUrlItem = urlSplitted.pop();

			if (!lastUrlItem.length) {
				lastUrlItem = urlSplitted.pop();
			}

			var lastUrlItemWithoutParams = lastUrlItem.split('?')[0],
				isFilteredUrlItem = this._filteredUrls.indexOf(lastUrlItemWithoutParams) !== -1,
				isUrlToServer = url.indexOf(this._apiUrl) !== -1,
				urlNeedsAuth = isUrlToServer && !isFilteredUrlItem;

			if (urlNeedsAuth) {
				if (!options.headers) {
					options.headers = {};
				}

				var accessToken = Credentials.get('accessToken');
				if (accessToken) {
					options.headers.Authorization = 'Bearer ' + accessToken;
				}
			}

			return !!options.useXHR;
		}
	});
});
+106 −1
Original line number Diff line number Diff line
@@ -2,11 +2,17 @@ define([
	'dojo/_base/declare'
	, 'dojo/_base/lang'
	, 'dojo/request'
	, 'dojo/request/notify'
	, 'dojo/request/registry'
	, 'redmic/base/Credentials'
	, './RestManager'
], function(
	declare
	, lang
	, request
	, notify
	, registry
	, Credentials
	, RestManager
) {

@@ -14,9 +20,15 @@ define([
		//	summary:
		//		Implementación del módulo RestManager, que provee métodos de comunicación mediante dojo/request.
		//	description:
		//		También maneja errores de permisos en peticiones y les añade cabeceras de autentificación.
		//		Importante: el campo 'options' recibido en las peticiones desde otros módulos, sobreescribe directamente
		//		las opciones que se usarán a su vez para realizar la petición HTTP.

		//	_apiUrl: String
		//		Prefijo de rutas hacia el servidor
		//	_filteredUrls: Array
		//		Define las URLs a las que no hay que añadirle caberas de autentificación

		constructor: function(args) {

			this.config = {
@@ -32,10 +44,36 @@ define([
				sync: false,
				preventCache: false,
				timeout: 45000,
				handleAs: 'json'
				handleAs: 'json',

				_apiUrl: 'api',
				_filteredUrls: [
					'token',
					'reCaptcha',
					'register',
					'resettingRequest',
					'resettingSetPassword',
					'activateAccount'
				]
			};

			lang.mixin(this, this.config, args);

			this._prepareRequestHandlers();
		},

		_prepareRequestHandlers: function() {

			notify('error', lang.hitch(this, this._requestErrorHandler));
			registry.register(lang.hitch(this, this._preRequestHandler), request);

			var envDfd = window.env;
			if (envDfd) {
				envDfd.then(lang.hitch(this, function(envData) {

					this._apiUrl = envData.apiUrl;
				}));
			}
		},

		_getTargetWithEndingSlash: function(target) {
@@ -326,6 +364,73 @@ define([
				options: response.options,
				error: res.message
			};
		},

		_requestErrorHandler: function(err) {
			//	summary:
			//		Se ejecuta cuando un request produce un error y permite manejarlo
			//	tags:
			//		private
			//	err:
			//		respuesta con el error del request

			var res = err.response,
				status = res.status;

			if (status === 401) {
				this._onRequestPermissionError(res);
			} else if (status === 502) {
				this._onRequestReachabilityError(res);
			}
		},

		_onRequestPermissionError: function(res) {

			// TODO notificar al usuario que intentó acceder a algo para lo que no tenía permiso (token caducado o con
			// privilegios insuficientes)
			Credentials.set('accessToken', null);
		},

		_onRequestReachabilityError: function(res) {

			// TODO notificar al usuario que hubo un error de conexión y ofrecerle recargar (para que pueda actuar
			// sobre la página actual antes de recargar)
		},

		_preRequestHandler: function(url, options) {
			//	summary:
			//		Se ejecuta antes de hacer un request y nos permite añadir cabeceras
			//	tags:
			//		private
			//	url:
			//		url del servicio
			//	options:
			//		opciones del request (headers...)

			var urlSplitted = url.split('/'),
				lastUrlItem = urlSplitted.pop();

			if (!lastUrlItem.length) {
				lastUrlItem = urlSplitted.pop();
			}

			var lastUrlItemWithoutParams = lastUrlItem.split('?')[0],
				isFilteredUrlItem = this._filteredUrls.indexOf(lastUrlItemWithoutParams) !== -1,
				isUrlToServer = url.indexOf(this._apiUrl) !== -1,
				urlNeedsAuth = isUrlToServer && !isFilteredUrlItem;

			if (urlNeedsAuth) {
				if (!options.headers) {
					options.headers = {};
				}

				var accessToken = Credentials.get('accessToken');
				if (accessToken) {
					options.headers.Authorization = 'Bearer ' + accessToken;
				}
			}

			return !!options.useXHR;
		}
	});
});