[CORD-1504] Handling XOSPermissionDenied errors
Change-Id: Icc1c796505207469d7416457802a3b9090031f72
diff --git a/src/app/core/loader/loader.ts b/src/app/core/loader/loader.ts
index f12b17b..23acf6a 100644
--- a/src/app/core/loader/loader.ts
+++ b/src/app/core/loader/loader.ts
@@ -37,8 +37,8 @@
this.$state.go('xos.login');
}
else {
- this.XosModelDiscoverer.discover()
// NOTE loading XOS Models
+ this.XosModelDiscoverer.discover()
.then((res) => {
if (res) {
this.$log.info('[XosLoader] All models loaded');
@@ -46,9 +46,9 @@
else {
this.$log.info('[XosLoader] Failed to load some models, moving on.');
}
+ // NOTE loading GUI Extensions
return this.XosOnboarder.onboard();
})
- // NOTE loading GUI Extensions
.then(() => {
this.moveOnTo(this.XosConfig.lastVisitedUrl);
})
diff --git a/src/app/core/services/keyboard-shortcut.ts b/src/app/core/services/keyboard-shortcut.ts
index 35af07e..1907b0d 100644
--- a/src/app/core/services/keyboard-shortcut.ts
+++ b/src/app/core/services/keyboard-shortcut.ts
@@ -85,6 +85,10 @@
const pressedKey = this.whatKey(e.which);
+ if (!pressedKey) {
+ return;
+ }
+
if (this.allowedModifiers.indexOf(e.key) > -1) {
this.addActiveModifierKey(e.key);
return;
diff --git a/src/app/datasources/helpers/model-discoverer.service.ts b/src/app/datasources/helpers/model-discoverer.service.ts
index 4306825..1ef2904 100644
--- a/src/app/datasources/helpers/model-discoverer.service.ts
+++ b/src/app/datasources/helpers/model-discoverer.service.ts
@@ -8,6 +8,7 @@
import {IXosConfigHelpersService} from '../../core/services/helpers/config.helpers';
import {IXosRuntimeStatesService, IXosState} from '../../core/services/runtime-states';
import {IXosModelStoreService} from '../stores/model.store';
+import {IXosAuthService} from '../rest/auth.rest';
export interface IXosModel {
name: string; // the model name
@@ -37,7 +38,8 @@
'XosRuntimeStates',
'XosNavigationService',
'XosModelStore',
- 'ngProgressFactory'
+ 'ngProgressFactory',
+ 'AuthService'
];
private xosModels: IXosModel[] = []; // list of augmented model definitions;
private xosServices: string[] = []; // list of loaded services
@@ -52,7 +54,8 @@
private XosRuntimeStates: IXosRuntimeStatesService,
private XosNavigationService: IXosNavigationService,
private XosModelStore: IXosModelStoreService,
- private ngProgressFactory: any // check for type defs
+ private ngProgressFactory: any, // check for type defs
+ private AuthService: IXosAuthService
) {
this.progressBar = this.ngProgressFactory.createInstance();
this.progressBar.setColor('#f6a821');
@@ -236,6 +239,7 @@
return d.resolve(model);
},
err => {
+ this.AuthService.handleUnauthenticatedRequest(err);
return d.reject(err);
}
);
diff --git a/src/app/datasources/helpers/model.discoverer.service.spec.ts b/src/app/datasources/helpers/model.discoverer.service.spec.ts
index 8b17f34..d5a3232 100644
--- a/src/app/datasources/helpers/model.discoverer.service.spec.ts
+++ b/src/app/datasources/helpers/model.discoverer.service.spec.ts
@@ -78,7 +78,8 @@
.value('XosRuntimeStates', MockXosRuntimeStates)
.value('XosModelStore', MockXosModelStore)
.value('ngProgressFactory', MockngProgressFactory)
- .value('XosNavigationService', MockXosNavigationService);
+ .value('XosNavigationService', MockXosNavigationService)
+ .value('AuthService', {});
angular.mock.module('test');
});
diff --git a/src/app/datasources/rest/auth.rest.spec.ts b/src/app/datasources/rest/auth.rest.spec.ts
index 35732a3..7a406db 100644
--- a/src/app/datasources/rest/auth.rest.spec.ts
+++ b/src/app/datasources/rest/auth.rest.spec.ts
@@ -87,4 +87,37 @@
// httpBackend.flush();
});
});
+
+ describe('the handleUnauthenticatedRequest method', () => {
+
+ beforeEach(() => {
+ spyOn(service, 'clearUser');
+ });
+
+ it('should logout the user and redirect to login', () => {
+ service.handleUnauthenticatedRequest({
+ error: 'XOSPermissionDenied',
+ fields: {},
+ specific_error: 'test'
+ });
+ expect(service.clearUser).toHaveBeenCalled();
+ });
+
+ it('should catch errors from strings', () => {
+ service.handleUnauthenticatedRequest('{"fields": {}, "specific_error": "failed to authenticate token g09et150o2s25kdzg8t2n9wotvds9jyl", "error": "XOSPermissionDenied"}');
+ expect(service.clearUser).toHaveBeenCalled();
+ });
+
+ it('should not catch other errors', () => {
+ service.handleUnauthenticatedRequest({
+ error: 'XOSProgrammingError',
+ fields: {},
+ specific_error: 'test'
+ });
+ expect(service.clearUser).not.toHaveBeenCalled();
+
+ service.handleUnauthenticatedRequest('some error');
+ expect(service.clearUser).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/src/app/datasources/rest/auth.rest.ts b/src/app/datasources/rest/auth.rest.ts
index 81c4f7d..82f71b6 100644
--- a/src/app/datasources/rest/auth.rest.ts
+++ b/src/app/datasources/rest/auth.rest.ts
@@ -16,12 +16,19 @@
email: string;
}
+export interface IXosRestError {
+ error: string;
+ specific_error: string;
+ fields: any;
+}
+
export interface IXosAuthService {
login(data: IAuthRequestData): Promise<any>;
logout(): Promise<any>;
getUser(): any; // NOTE how to define return user || false ???
isAuthenticated(): boolean;
clearUser(): void;
+ handleUnauthenticatedRequest(error: IXosRestError | string): void;
}
export class AuthService {
@@ -29,7 +36,8 @@
private $http: angular.IHttpService,
private $q: angular.IQService,
private $cookies: angular.cookies.ICookiesService,
- private AppConfig: IXosAppConfig
+ private AppConfig: IXosAppConfig,
+ private $state: angular.ui.IStateService
) {
}
@@ -84,4 +92,29 @@
const session = this.$cookies.get('sessionid');
return angular.isDefined(session);
}
+
+ public handleUnauthenticatedRequest(res: IXosRestError | string): void {
+ let err;
+ if (angular.isString(res)) {
+ try {
+ err = JSON.parse(res);
+ } catch (e) {
+ // NOTE if it's not JSON it means that is not the error we're handling here
+ return;
+ }
+ }
+
+ if (angular.isObject(res)) {
+ err = res;
+ }
+
+ if (err && err.error) {
+ switch (err.error) {
+ case 'XOSPermissionDenied':
+ this.clearUser();
+ this.$state.go('login');
+ break;
+ }
+ }
+ }
}
diff --git a/src/app/datasources/stores/model.store.ts b/src/app/datasources/stores/model.store.ts
index 60d2473..950d441 100644
--- a/src/app/datasources/stores/model.store.ts
+++ b/src/app/datasources/stores/model.store.ts
@@ -33,7 +33,7 @@
this._collections[modelName] = new BehaviorSubject([]); // NOTE maybe this can be created when we get response from the resource
this.loadInitialData(modelName, apiUrl);
}
- // else manually trigger the next with the last know value to trigger the subscribe method of who's requestiong this data
+ // else manually trigger the next with the last know value to trigger the subscribe method of who's requesting this data
else {
this.efficientNext(this._collections[modelName]);
}
diff --git a/src/interceptors.ts b/src/interceptors.ts
index a1b5df8..82c5f34 100644
--- a/src/interceptors.ts
+++ b/src/interceptors.ts
@@ -8,9 +8,11 @@
export function userStatusInterceptor($state: angular.ui.IStateService, $cookies: ng.cookies.ICookiesService, $q: ng.IQService) {
const checkLogin = (res) => {
+ // NOTE this interceptor may never be called as the request is not rejected byt the "model-discoverer" service
switch (res.status) {
case -1:
case 401:
+ case 403:
$cookies.remove('sessionid', {path: '/'});
$state.go('login');
return $q.reject(res);
@@ -20,7 +22,6 @@
};
return {
- // response: checkLogin,
responseError: checkLogin
};
}