Merge "Added error msg when gets redirect to login page"
This commit is contained in:
commit
ba01268334
|
@ -22,7 +22,11 @@
|
|||
'horizon.framework.widgets'
|
||||
])
|
||||
.config(config)
|
||||
.run(run);
|
||||
.run(run)
|
||||
.factory('horizon.framework.redirect', httpRedirectLogin)
|
||||
.constant('horizon.framework.events', {
|
||||
FORCE_LOGOUT: 'FORCE_LOGOUT'
|
||||
});
|
||||
|
||||
config.$inject = [
|
||||
'$injector',
|
||||
|
@ -70,23 +74,9 @@
|
|||
// Global http error handler
|
||||
// if user is not authorized, log user out
|
||||
// this can happen when session expires
|
||||
$httpProvider.interceptors.push(redirect);
|
||||
$httpProvider.interceptors.push(httpRedirectLogin);
|
||||
$httpProvider.interceptors.push(stripAjaxHeaderForCORS);
|
||||
|
||||
redirect.$inject = ['$q'];
|
||||
|
||||
function redirect($q) {
|
||||
return {
|
||||
responseError: function (error) {
|
||||
if (error.status === 401) {
|
||||
var $window = $windowProvider.$get();
|
||||
$window.location.replace($window.WEBROOT + 'auth/logout');
|
||||
}
|
||||
return $q.reject(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
stripAjaxHeaderForCORS.$inject = [];
|
||||
// Standard CORS middleware used in OpenStack services doesn't expect
|
||||
// X-Requested-With header to be set for requests and rejects requests
|
||||
|
@ -125,4 +115,38 @@
|
|||
}
|
||||
}
|
||||
|
||||
httpRedirectLogin.$inject = [
|
||||
'$q',
|
||||
'$rootScope',
|
||||
'$window',
|
||||
'horizon.framework.events',
|
||||
'horizon.framework.widgets.toast.service'
|
||||
];
|
||||
|
||||
function httpRedirectLogin($q, $rootScope, $window, frameworkEvents, toastService) {
|
||||
return {
|
||||
responseError: function (error) {
|
||||
if (error.status === 401) {
|
||||
var msg = gettext('Unauthorized. Redirecting to login');
|
||||
handleRedirectMessage(msg, $rootScope, $window, frameworkEvents, toastService);
|
||||
}
|
||||
if (error.status === 403) {
|
||||
var msg2 = gettext('Forbidden. Redirecting to login');
|
||||
handleRedirectMessage(msg2, $rootScope, $window, frameworkEvents, toastService);
|
||||
}
|
||||
return $q.reject(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function handleRedirectMessage(msg, $rootScope, $window, frameworkEvents, toastService) {
|
||||
var toast = toastService.find('error', msg);
|
||||
//Suppress the multiple duplicate redirect toast messages.
|
||||
if (!toast) {
|
||||
toastService.add('error', msg);
|
||||
$rootScope.$broadcast(frameworkEvents.FORCE_LOGOUT, msg);
|
||||
}
|
||||
$window.location.replace($window.WEBROOT + 'auth/logout');
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
@ -35,15 +35,45 @@
|
|||
}));
|
||||
|
||||
describe('when unauthorized', function() {
|
||||
it('should redirect to /auth/logout', inject(function($http, $httpBackend, $window) {
|
||||
$window.WEBROOT = '/dashboard/';
|
||||
$httpBackend.when('GET', '/api').respond(401, '');
|
||||
it('should redirect to /auth/logout and add an unauthorized toast message ', inject(
|
||||
function($http, $httpBackend, $window, $injector, $rootScope) {
|
||||
$window.WEBROOT = '/dashboard/';
|
||||
$httpBackend.when('GET', '/api').respond(401, '');
|
||||
|
||||
$http.get('/api').error(function() {
|
||||
expect($window.location.replace).toHaveBeenCalledWith('/dashboard/auth/logout');
|
||||
});
|
||||
$httpBackend.flush();
|
||||
}));
|
||||
var toastService = $injector.get('horizon.framework.widgets.toast.service');
|
||||
spyOn(toastService, 'add');
|
||||
|
||||
spyOn($rootScope, '$broadcast').and.callThrough();
|
||||
|
||||
$http.get('/api').error(function() {
|
||||
expect(toastService.add).toHaveBeenCalled();
|
||||
expect($rootScope.$broadcast).toHaveBeenCalled();
|
||||
expect($window.location.replace).toHaveBeenCalledWith('/dashboard/auth/logout');
|
||||
});
|
||||
$httpBackend.flush();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('when forbidden', function() {
|
||||
it('should redirect to /auth/logout and add a forbidden toast message ', inject(
|
||||
function($http, $httpBackend, $window, $injector, $rootScope) {
|
||||
$window.WEBROOT = '/dashboard/';
|
||||
$httpBackend.when('GET', '/api').respond(403, '');
|
||||
|
||||
var toastService = $injector.get('horizon.framework.widgets.toast.service');
|
||||
spyOn(toastService, 'add');
|
||||
|
||||
spyOn($rootScope, '$broadcast').and.callThrough();
|
||||
|
||||
$http.get('/api').error(function() {
|
||||
expect(toastService.add).toHaveBeenCalled();
|
||||
expect($rootScope.$broadcast).toHaveBeenCalled();
|
||||
expect($window.location.replace).toHaveBeenCalledWith('/dashboard/auth/logout');
|
||||
});
|
||||
$httpBackend.flush();
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
types: {},
|
||||
add: add,
|
||||
get: get,
|
||||
find: find,
|
||||
cancel: cancel,
|
||||
clearAll: clearAll,
|
||||
clearErrors: clearErrors,
|
||||
|
@ -118,6 +119,20 @@
|
|||
return toasts;
|
||||
}
|
||||
|
||||
/**
|
||||
* find a matching existing toast based on type and message
|
||||
*
|
||||
* @param type type of the message
|
||||
* @param msg localized message of the toast
|
||||
* @returns {*} return toast object if find matching one
|
||||
*/
|
||||
function find(type, msg) {
|
||||
return toasts.find(function(toast) {
|
||||
var toastType = (type === 'error' ? 'danger' : type);
|
||||
return (toast.type === toastType && toast.msg.localeCompare(msg) === 0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all toasts.
|
||||
*/
|
||||
|
|
|
@ -67,6 +67,18 @@
|
|||
expect(service.get()[0].type).toBe('danger');
|
||||
});
|
||||
|
||||
it('should find the added toast message', function() {
|
||||
service.add('error', dangerMsg);
|
||||
var toast = service.find('error', dangerMsg);
|
||||
expect(toast.type).toBe('danger');
|
||||
expect(toast.msg).toBe(dangerMsg);
|
||||
|
||||
service.add('success', successMsg);
|
||||
toast = service.find('success', successMsg);
|
||||
expect(toast.type).toBe('success');
|
||||
expect(toast.msg).toBe(successMsg);
|
||||
});
|
||||
|
||||
it('should provide a function to clear all toasts', function() {
|
||||
service.add('success', successMsg);
|
||||
service.add('success', successMsg);
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
'$scope',
|
||||
'$q',
|
||||
'horizon.framework.widgets.wizard.labels',
|
||||
'horizon.framework.widgets.wizard.events'
|
||||
'horizon.framework.widgets.wizard.events',
|
||||
'horizon.framework.events'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -36,7 +37,8 @@
|
|||
* @description
|
||||
* Controller used by 'wizard'
|
||||
*/
|
||||
function WizardController($scope, $q, wizardLabels, wizardEvents) {
|
||||
function WizardController($scope, $q, wizardLabels, wizardEvents, frameworkEvents) {
|
||||
var ctrl = this;
|
||||
var viewModel = $scope.viewModel = {};
|
||||
var initTask = $q.defer();
|
||||
|
||||
|
@ -55,6 +57,10 @@
|
|||
|
||||
$scope.switchTo = switchTo;
|
||||
$scope.showError = showError;
|
||||
ctrl.toggleHelpBtn = toggleHelpBtn;
|
||||
ctrl.onInitSuccess = onInitSuccess;
|
||||
ctrl.onInitError = onInitError;
|
||||
|
||||
/*eslint-enable angular/controller-as */
|
||||
|
||||
viewModel.btnText = extend({}, wizardLabels, $scope.workflow.btnText);
|
||||
|
@ -85,7 +91,7 @@
|
|||
from: $scope.currentIndex,
|
||||
to: index
|
||||
});
|
||||
toggleHelpBtn(index);
|
||||
ctrl.toggleHelpBtn(index);
|
||||
/*eslint-disable angular/controller-as */
|
||||
$scope.currentIndex = index;
|
||||
$scope.openHelp = false;
|
||||
|
@ -122,9 +128,13 @@
|
|||
}
|
||||
|
||||
function onInitSuccess() {
|
||||
if (viewModel.hasError) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.$broadcast(wizardEvents.ON_INIT_SUCCESS);
|
||||
if (steps.length > 0) {
|
||||
toggleHelpBtn(0);
|
||||
ctrl.toggleHelpBtn(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +142,12 @@
|
|||
$scope.$broadcast(wizardEvents.ON_INIT_ERROR);
|
||||
}
|
||||
|
||||
$scope.$on(frameworkEvents.FORCE_LOGOUT, function(evt, arg) {
|
||||
viewModel.hasError = true;
|
||||
viewModel.errorMessage = arg;
|
||||
return;
|
||||
});
|
||||
|
||||
function toggleHelpBtn(index) {
|
||||
// Toggle help icon button if a step's helpUrl is not defined
|
||||
if (angular.isUndefined(steps[index].helpUrl)) {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* (c) Copyright 2017 SUSE Linux
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe("WizardController", function() {
|
||||
var ctrl, scope, wizardLabels, wizardEvents, frameworkEvents, rootScope;
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(inject(function($controller, $rootScope, $injector, $q) {
|
||||
scope = $rootScope.$new();
|
||||
rootScope = $rootScope;
|
||||
wizardLabels = $injector.get('horizon.framework.widgets.wizard.labels');
|
||||
wizardEvents = $injector.get('horizon.framework.widgets.wizard.events');
|
||||
frameworkEvents = $injector.get('horizon.framework.events');
|
||||
ctrl = $controller('WizardController', {
|
||||
$scope: scope,
|
||||
$q: $q,
|
||||
wizardLabels: wizardLabels,
|
||||
wizardEvents: wizardEvents,
|
||||
frameworkEvents: frameworkEvents
|
||||
});
|
||||
scope.$apply();
|
||||
}));
|
||||
|
||||
it('is defined', function() {
|
||||
expect(ctrl).toBeDefined();
|
||||
});
|
||||
|
||||
it('viewModel is defined', function() {
|
||||
expect(scope.viewModel).toBeDefined();
|
||||
});
|
||||
|
||||
it('call switchTo', function() {
|
||||
spyOn(ctrl, 'toggleHelpBtn');
|
||||
spyOn(scope, '$broadcast');
|
||||
scope.switchTo(1);
|
||||
scope.$apply();
|
||||
expect(ctrl.toggleHelpBtn).toHaveBeenCalled();
|
||||
expect(scope.currentIndex).toBe(1);
|
||||
expect(scope.openHelp).toBe(false);
|
||||
expect(scope.$broadcast).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('call showError', function() {
|
||||
spyOn(scope, 'showError').and.callThrough();
|
||||
scope.showError('in valid');
|
||||
scope.$apply();
|
||||
expect(scope.viewModel.hasError).toBe(true);
|
||||
expect(scope.viewModel.errorMessage).toBe('in valid');
|
||||
});
|
||||
|
||||
it('call onInitSuccess with logout event', function() {
|
||||
rootScope.$broadcast(frameworkEvents.FORCE_LOGOUT, 'logout');
|
||||
ctrl.onInitSuccess();
|
||||
scope.$apply();
|
||||
expect(scope.viewModel.hasError).toBe(true);
|
||||
});
|
||||
|
||||
it('call onInitSuccess without logout event', function() {
|
||||
spyOn(scope, '$broadcast');
|
||||
ctrl.onInitSuccess();
|
||||
scope.$apply();
|
||||
expect(scope.viewModel.hasError).toBe(false);
|
||||
expect(scope.$broadcast).toHaveBeenCalledWith(wizardEvents.ON_INIT_SUCCESS);
|
||||
});
|
||||
|
||||
it('call onInitError with logout event', function() {
|
||||
rootScope.$broadcast(frameworkEvents.FORCE_LOGOUT, 'logout');
|
||||
ctrl.onInitError();
|
||||
scope.$apply();
|
||||
expect(scope.viewModel.hasError).toBe(true);
|
||||
});
|
||||
|
||||
it('call onInitError without logout event', function() {
|
||||
spyOn(scope, '$broadcast');
|
||||
ctrl.onInitError();
|
||||
scope.$apply();
|
||||
expect(scope.viewModel.hasError).toBe(false);
|
||||
expect(scope.$broadcast).toHaveBeenCalledWith(wizardEvents.ON_INIT_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
Loading…
Reference in New Issue