72699: Hard redirect after log in - loading fixes

This commit is contained in:
Kristof De Langhe
2020-08-27 14:50:13 +02:00
parent 7fbae8997d
commit 55c45f5f6c
25 changed files with 204 additions and 146 deletions

View File

@@ -1,4 +1,7 @@
<div class="outer-wrapper">
<div class="text-center ds-full-screen-loader d-flex align-items-center flex-column justify-content-center" *ngIf="!(hasAuthFinishedLoading$ | async)">
<ds-loading [showMessage]="false"></ds-loading>
</div>
<div class="outer-wrapper" *ngIf="hasAuthFinishedLoading$ | async">
<ds-admin-sidebar></ds-admin-sidebar>
<div class="inner-wrapper" [@slideSidebarPadding]="{
value: (!(sidebarVisible | async) ? 'hidden' : (slideSidebarOver | async) ? 'shown' : 'expanded'),

View File

@@ -47,3 +47,7 @@ ds-admin-sidebar {
position: fixed;
z-index: $sidebar-z-index;
}
.ds-full-screen-loader {
height: 100vh;
}

View File

@@ -1,9 +1,8 @@
import * as ngrx from '@ngrx/store';
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { By } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { Store, StoreModule } from '@ngrx/store';
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga';
@@ -30,13 +29,13 @@ import { RouteService } from './core/services/route.service';
import { MockActivatedRoute } from './shared/mocks/active-router.mock';
import { RouterMock } from './shared/mocks/router.mock';
import { Angulartics2DSpace } from './statistics/angulartics/dspace-provider';
import { storeModuleConfig } from './app.reducer';
import { AppState, storeModuleConfig } from './app.reducer';
import { LocaleService } from './core/locale/locale.service';
import { authReducer } from './core/auth/auth.reducer';
import { cold } from 'jasmine-marbles';
let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let de: DebugElement;
let el: HTMLElement;
const menuService = new MenuServiceStub();
describe('App component', () => {
@@ -52,7 +51,7 @@ describe('App component', () => {
return TestBed.configureTestingModule({
imports: [
CommonModule,
StoreModule.forRoot({}, storeModuleConfig),
StoreModule.forRoot(authReducer, storeModuleConfig),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
@@ -82,12 +81,19 @@ describe('App component', () => {
// synchronous beforeEach
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
spyOnProperty(ngrx, 'select').and.callFake(() => {
return () => {
return () => cold('a', {
a: {
core: { auth: { loading: false } }
}
})
};
});
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance; // component test instance
// query for the <div class='outer-wrapper'> by CSS element selector
de = fixture.debugElement.query(By.css('div.outer-wrapper'));
el = de.nativeElement;
fixture.detectChanges();
});
it('should create component', inject([AppComponent], (app: AppComponent) => {

View File

@@ -1,4 +1,4 @@
import { delay, filter, map, take } from 'rxjs/operators';
import { delay, filter, map, take, distinctUntilChanged } from 'rxjs/operators';
import {
AfterViewInit,
ChangeDetectionStrategy,
@@ -19,7 +19,7 @@ import { MetadataService } from './core/metadata/metadata.service';
import { HostWindowResizeAction } from './shared/host-window.actions';
import { HostWindowState } from './shared/search/host-window.reducer';
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
import { isAuthenticated } from './core/auth/selectors';
import { isAuthenticated, isAuthenticationLoading } from './core/auth/selectors';
import { AuthService } from './core/auth/auth.service';
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
import { MenuService } from './shared/menu/menu.service';
@@ -52,6 +52,11 @@ export class AppComponent implements OnInit, AfterViewInit {
notificationOptions = environment.notifications;
models;
/**
* Whether or not the authenticated has finished loading
*/
hasAuthFinishedLoading$: Observable<boolean>;
constructor(
@Inject(NativeWindowService) private _window: NativeWindowRef,
private translate: TranslateService,
@@ -89,6 +94,10 @@ export class AppComponent implements OnInit, AfterViewInit {
}
ngOnInit() {
this.hasAuthFinishedLoading$ = this.store.pipe(select(isAuthenticationLoading)).pipe(
map((isLoading: boolean) => isLoading === false),
distinctUntilChanged()
);
const env: string = environment.production ? 'Production' : 'Development';
const color: string = environment.production ? 'red' : 'green';
console.info(`Environment: %c${env}`, `color: ${color}; font-weight: bold;`);

View File

@@ -34,6 +34,7 @@ export const AuthActionTypes = {
RETRIEVE_AUTHENTICATED_EPERSON: type('dspace/auth/RETRIEVE_AUTHENTICATED_EPERSON'),
RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS: type('dspace/auth/RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS'),
RETRIEVE_AUTHENTICATED_EPERSON_ERROR: type('dspace/auth/RETRIEVE_AUTHENTICATED_EPERSON_ERROR'),
REDIRECT_AFTER_LOGIN_SUCCESS: type('dspace/auth/REDIRECT_AFTER_LOGIN_SUCCESS')
};
/* tslint:disable:max-classes-per-file */
@@ -335,6 +336,20 @@ export class SetRedirectUrlAction implements Action {
}
}
/**
* Start loading for a hard redirect
* @class StartHardRedirectLoadingAction
* @implements {Action}
*/
export class RedirectAfterLoginSuccessAction implements Action {
public type: string = AuthActionTypes.REDIRECT_AFTER_LOGIN_SUCCESS;
payload: string;
constructor(url: string) {
this.payload = url;
}
}
/**
* Retrieve the authenticated eperson.
* @class RetrieveAuthenticatedEpersonAction
@@ -402,8 +417,8 @@ export type AuthActions
| RetrieveAuthMethodsSuccessAction
| RetrieveAuthMethodsErrorAction
| RetrieveTokenAction
| ResetAuthenticationMessagesAction
| RetrieveAuthenticatedEpersonAction
| RetrieveAuthenticatedEpersonErrorAction
| RetrieveAuthenticatedEpersonSuccessAction
| SetRedirectUrlAction;
| SetRedirectUrlAction
| RedirectAfterLoginSuccessAction;

View File

@@ -27,6 +27,7 @@ import {
CheckAuthenticationTokenCookieAction,
LogOutErrorAction,
LogOutSuccessAction,
RedirectAfterLoginSuccessAction,
RefreshTokenAction,
RefreshTokenErrorAction,
RefreshTokenSuccessAction,
@@ -79,7 +80,26 @@ export class AuthEffects {
public authenticatedSuccess$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.AUTHENTICATED_SUCCESS),
tap((action: AuthenticatedSuccessAction) => this.authService.storeToken(action.payload.authToken)),
map((action: AuthenticatedSuccessAction) => new RetrieveAuthenticatedEpersonAction(action.payload.userHref))
switchMap((action: AuthenticatedSuccessAction) => this.authService.getRedirectUrl().pipe(
take(1),
map((redirectUrl: string) => [action, redirectUrl])
)),
map(([action, redirectUrl]: [AuthenticatedSuccessAction, string]) => {
if (hasValue(redirectUrl)) {
return new RedirectAfterLoginSuccessAction(redirectUrl);
} else {
return new RetrieveAuthenticatedEpersonAction(action.payload.userHref);
}
})
);
@Effect({ dispatch: false })
public redirectAfterLoginSuccess$: Observable<Action> = this.actions$.pipe(
ofType(AuthActionTypes.REDIRECT_AFTER_LOGIN_SUCCESS),
tap((action: RedirectAfterLoginSuccessAction) => {
this.authService.clearRedirectUrl();
this.authService.navigateToRedirectUrl(action.payload);
})
);
// It means "reacts to this action but don't send another"

View File

@@ -62,7 +62,7 @@ export interface AuthState {
const initialState: AuthState = {
authenticated: false,
loaded: false,
loading: false,
loading: undefined,
authMethods: []
};
@@ -201,6 +201,11 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
redirectUrl: (action as SetRedirectUrlAction).payload,
});
case AuthActionTypes.REDIRECT_AFTER_LOGIN_SUCCESS:
return Object.assign({}, state, {
loading: true,
});
default:
return state;
}

View File

@@ -323,35 +323,30 @@ describe('AuthService test', () => {
});
it('should set redirect url to previous page', () => {
spyOn(routeServiceMock, 'getHistory').and.callThrough();
authService.redirectAfterLoginSuccess(true);
expect(routeServiceMock.getHistory).toHaveBeenCalled();
(storage.get as jasmine.Spy).and.returnValue('/collection/123');
authService.redirectAfterLoginSuccess();
// Reload with redirect URL set to /collection/123
expect(hardRedirectService.redirect).toHaveBeenCalledWith(jasmine.stringMatching(new RegExp('/reload/[0-9]*\\?redirect=' + encodeURIComponent('/collection/123'))));
});
it('should set redirect url to current page', () => {
spyOn(routeServiceMock, 'getHistory').and.callThrough();
authService.redirectAfterLoginSuccess(false);
expect(routeServiceMock.getHistory).toHaveBeenCalled();
(storage.get as jasmine.Spy).and.returnValue('/home');
authService.redirectAfterLoginSuccess();
// Reload with redirect URL set to /home
expect(hardRedirectService.redirect).toHaveBeenCalledWith(jasmine.stringMatching(new RegExp('/reload/[0-9]*\\?redirect=' + encodeURIComponent('/home'))));
});
it('should redirect to / and not to /login', () => {
spyOn(routeServiceMock, 'getHistory').and.returnValue(observableOf(['/login', '/login']));
authService.redirectAfterLoginSuccess(true);
expect(routeServiceMock.getHistory).toHaveBeenCalled();
it('should redirect to regular reload and not to /login', () => {
(storage.get as jasmine.Spy).and.returnValue('/login');
authService.redirectAfterLoginSuccess();
// Reload without a redirect URL
expect(hardRedirectService.redirect).toHaveBeenCalledWith(jasmine.stringMatching(new RegExp('/reload/[0-9]*(?!\\?)$')));
});
it('should redirect to / when no redirect url is found', () => {
spyOn(routeServiceMock, 'getHistory').and.returnValue(observableOf(['']));
authService.redirectAfterLoginSuccess(true);
expect(routeServiceMock.getHistory).toHaveBeenCalled();
it('should not redirect when no redirect url is found', () => {
authService.redirectAfterLoginSuccess();
// Reload without a redirect URL
expect(hardRedirectService.redirect).toHaveBeenCalledWith(jasmine.stringMatching(new RegExp('/reload/[0-9]*(?!\\?)$')));
expect(hardRedirectService.redirect).not.toHaveBeenCalled();
});
describe('impersonate', () => {

View File

@@ -14,7 +14,15 @@ import { AuthRequestService } from './auth-request.service';
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
import { AuthStatus } from './models/auth-status.model';
import { AuthTokenInfo, TOKENITEM } from './models/auth-token-info.model';
import { hasValue, hasValueOperator, isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../shared/empty.util';
import {
hasValue,
hasValueOperator,
isEmpty,
isNotEmpty,
isNotNull,
isNotUndefined,
hasNoValue
} from '../../shared/empty.util';
import { CookieService } from '../services/cookie.service';
import {
getAuthenticatedUserId,
@@ -413,35 +421,19 @@ export class AuthService {
/**
* Redirect to the route navigated before the login
*/
public redirectAfterLoginSuccess(isStandalonePage: boolean) {
public redirectAfterLoginSuccess() {
this.getRedirectUrl().pipe(
take(1))
.subscribe((redirectUrl) => {
if (isNotEmpty(redirectUrl)) {
if (hasValue(redirectUrl)) {
this.clearRedirectUrl();
this.router.onSameUrlNavigation = 'reload';
this.navigateToRedirectUrl(redirectUrl);
} else {
// If redirectUrl is empty use history.
this.routeService.getHistory().pipe(
take(1)
).subscribe((history) => {
let redirUrl;
if (isStandalonePage) {
// For standalone login pages, use the previous route.
redirUrl = history[history.length - 2] || '';
} else {
redirUrl = history[history.length - 1] || '';
}
this.navigateToRedirectUrl(redirUrl);
});
}
});
}
protected navigateToRedirectUrl(redirectUrl: string) {
public navigateToRedirectUrl(redirectUrl: string) {
let url = `/reload/${new Date().getTime()}`;
if (isNotEmpty(redirectUrl) && !redirectUrl.startsWith(LOGIN_ROUTE)) {
url += `?redirect=${encodeURIComponent(redirectUrl)}`;
@@ -460,12 +452,16 @@ export class AuthService {
* Get redirect url
*/
getRedirectUrl(): Observable<string> {
const redirectUrl = this.storage.get(REDIRECT_COOKIE);
if (isNotEmpty(redirectUrl)) {
return observableOf(redirectUrl);
return this.store.pipe(
select(getRedirectUrl),
map((urlFromStore: string) => {
if (hasValue(urlFromStore)) {
return urlFromStore;
} else {
return this.store.pipe(select(getRedirectUrl));
return this.storage.get(REDIRECT_COOKIE);
}
})
);
}
/**
@@ -482,6 +478,16 @@ export class AuthService {
this.store.dispatch(new SetRedirectUrlAction(isNotUndefined(url) ? url : ''));
}
setRedirectUrlIfNotSet(newRedirectUrl: string) {
this.getRedirectUrl().pipe(
take(1))
.subscribe((currentRedirectUrl) => {
if (hasNoValue(currentRedirectUrl)) {
this.setRedirectUrl(newRedirectUrl);
}
})
}
/**
* Clear redirect url
*/

View File

@@ -9,11 +9,11 @@ import {
} from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { map, find, switchMap } from 'rxjs/operators';
import { select, Store } from '@ngrx/store';
import { CoreState } from '../core.reducers';
import { isAuthenticated } from './selectors';
import { isAuthenticated, isAuthenticationLoading } from './selectors';
import { AuthService, LOGIN_ROUTE } from './auth.service';
/**
@@ -48,11 +48,10 @@ export class AuthenticatedGuard implements CanActivate {
}
private handleAuth(url: string): Observable<boolean | UrlTree> {
// get observable
const observable = this.store.pipe(select(isAuthenticated));
// redirect to sign in page if user is not authenticated
return observable.pipe(
return this.store.pipe(select(isAuthenticationLoading)).pipe(
find((isLoading: boolean) => isLoading === false),
switchMap(() => this.store.pipe(select(isAuthenticated))),
map((authenticated) => {
if (authenticated) {
return authenticated;

View File

@@ -58,32 +58,4 @@ export class ServerAuthService extends AuthService {
map((status: AuthStatus) => Object.assign(new AuthStatus(), status))
);
}
/**
* Redirect to the route navigated before the login
*/
public redirectAfterLoginSuccess(isStandalonePage: boolean) {
this.getRedirectUrl().pipe(
take(1))
.subscribe((redirectUrl) => {
if (isNotEmpty(redirectUrl)) {
// override the route reuse strategy
this.router.routeReuseStrategy.shouldReuseRoute = () => {
return false;
};
this.router.navigated = false;
const url = decodeURIComponent(redirectUrl);
this.router.navigateByUrl(url);
} else {
// If redirectUrl is empty use history. For ssr the history array should contain the requested url.
this.routeService.getHistory().pipe(
filter((history) => history.length > 0),
take(1)
).subscribe((history) => {
this.navigateToRedirectUrl(history[history.length - 1] || '');
});
}
})
}
}

View File

@@ -5,7 +5,8 @@ describe('BrowserHardRedirectService', () => {
const mockLocation = {
href: undefined,
origin: 'test origin',
pathname: '/pathname',
search: '/search',
} as Location;
const service: BrowserHardRedirectService = new BrowserHardRedirectService(mockLocation);
@@ -31,10 +32,10 @@ describe('BrowserHardRedirectService', () => {
})
});
describe('when requesting the origin', () => {
describe('when requesting the current route', () => {
it('should return the location origin', () => {
expect(service.getOriginFromUrl()).toEqual('test origin');
expect(service.getCurrentRoute()).toEqual(mockLocation.pathname + mockLocation.search);
});
});
});

View File

@@ -1,11 +1,12 @@
import {Inject, Injectable} from '@angular/core';
import {LocationToken} from '../../../modules/app/browser-app.module';
import { Inject, Injectable } from '@angular/core';
import { LocationToken } from '../../../modules/app/browser-app.module';
import { HardRedirectService } from './hard-redirect.service';
/**
* Service for performing hard redirects within the browser app module
*/
@Injectable()
export class BrowserHardRedirectService {
export class BrowserHardRedirectService implements HardRedirectService {
constructor(
@Inject(LocationToken) protected location: Location,
@@ -23,7 +24,7 @@ export class BrowserHardRedirectService {
/**
* Get the origin of a request
*/
getOriginFromUrl() {
return this.location.origin;
getCurrentRoute() {
return this.location.pathname + this.location.search;
}
}

View File

@@ -15,7 +15,8 @@ export abstract class HardRedirectService {
abstract redirect(url: string);
/**
* Get the origin of a request
* Get the current route, with query params included
* e.g. /search?page=1&query=open%20access&f.dateIssued.min=1980&f.dateIssued.max=2020
*/
abstract getOriginFromUrl();
abstract getCurrentRoute();
}

View File

@@ -30,19 +30,14 @@ describe('ServerHardRedirectService', () => {
})
});
describe('when requesting the origin', () => {
describe('when requesting the current route', () => {
beforeEach(() => {
mockRequest.protocol = 'test-protocol';
mockRequest.get.and.callFake((name) => {
if (name === 'hostname') {
return 'test-host';
}
});
mockRequest.originalUrl = 'original/url';
});
it('should return the location origin', () => {
expect(service.getOriginFromUrl()).toEqual('test-protocol://test-host');
expect(service.getCurrentRoute()).toEqual(mockRequest.originalUrl);
});
});
});

View File

@@ -1,12 +1,13 @@
import { Inject, Injectable } from '@angular/core';
import { Request, Response } from 'express';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
import { HardRedirectService } from './hard-redirect.service';
/**
* Service for performing hard redirects within the server app module
*/
@Injectable()
export class ServerHardRedirectService {
export class ServerHardRedirectService implements HardRedirectService {
constructor(
@Inject(REQUEST) protected req: Request,
@@ -55,8 +56,7 @@ export class ServerHardRedirectService {
/**
* Get the origin of a request
*/
getOriginFromUrl() {
return new URL(`${this.req.protocol}://${this.req.get('hostname')}`).toString();
getCurrentRoute() {
return this.req.originalUrl;
}
}

View File

@@ -12,6 +12,7 @@ import { AuthService } from '../../../core/auth/auth.service';
import { AuthMethod } from '../../../core/auth/models/auth.method';
import { AuthServiceStub } from '../../testing/auth-service.stub';
import { createTestComponent } from '../../testing/utils.test';
import { HardRedirectService } from '../../../core/services/hard-redirect.service';
describe('LogInContainerComponent', () => {
@@ -20,7 +21,13 @@ describe('LogInContainerComponent', () => {
const authMethod = new AuthMethod('password');
let hardRedirectService: HardRedirectService;
beforeEach(async(() => {
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
redirect: {},
getCurrentRoute: {}
});
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
@@ -35,6 +42,7 @@ describe('LogInContainerComponent', () => {
],
providers: [
{provide: AuthService, useClass: AuthServiceStub},
{ provide: HardRedirectService, useValue: hardRedirectService },
LogInContainerComponent
],
schemas: [

View File

@@ -18,6 +18,7 @@ import { NativeWindowService } from '../../core/services/window.service';
import { provideMockStore } from '@ngrx/store/testing';
import { createTestComponent } from '../testing/utils.test';
import { RouterTestingModule } from '@angular/router/testing';
import { HardRedirectService } from '../../core/services/hard-redirect.service';
describe('LogInComponent', () => {
@@ -33,8 +34,13 @@ describe('LogInComponent', () => {
}
}
};
let hardRedirectService: HardRedirectService;
beforeEach(async(() => {
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
redirect: {},
getCurrentRoute: {}
});
// refine the test module by declaring the test component
TestBed.configureTestingModule({
imports: [
@@ -58,6 +64,7 @@ describe('LogInComponent', () => {
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
// { provide: Router, useValue: new RouterStub() },
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
{ provide: HardRedirectService, useValue: hardRedirectService },
provideMockStore({ initialState }),
LogInComponent
],

View File

@@ -1,13 +1,9 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { filter, takeWhile, } from 'rxjs/operators';
import { select, Store } from '@ngrx/store';
import { AuthMethod } from '../../core/auth/models/auth.method';
import { getAuthenticationMethods, isAuthenticated, isAuthenticationLoading } from '../../core/auth/selectors';
import { CoreState } from '../../core/core.reducers';
import { AuthService } from '../../core/auth/auth.service';
import { getForgotPasswordPath, getRegisterPath } from '../../app-routing.module';
/**
@@ -19,7 +15,7 @@ import { getForgotPasswordPath, getRegisterPath } from '../../app-routing.module
templateUrl: './log-in.component.html',
styleUrls: ['./log-in.component.scss']
})
export class LogInComponent implements OnInit, OnDestroy {
export class LogInComponent implements OnInit {
/**
* A boolean representing if LogInComponent is in a standalone page
@@ -45,14 +41,7 @@ export class LogInComponent implements OnInit, OnDestroy {
*/
public loading: Observable<boolean>;
/**
* Component state.
* @type {boolean}
*/
private alive = true;
constructor(private store: Store<CoreState>,
private authService: AuthService,) {
constructor(private store: Store<CoreState>) {
}
ngOnInit(): void {
@@ -66,21 +55,6 @@ export class LogInComponent implements OnInit, OnDestroy {
// set isAuthenticated
this.isAuthenticated = this.store.pipe(select(isAuthenticated));
// subscribe to success
this.store.pipe(
select(isAuthenticated),
takeWhile(() => this.alive),
filter((authenticated) => authenticated))
.subscribe(() => {
this.authService.redirectAfterLoginSuccess(this.isStandalonePage);
}
);
}
ngOnDestroy(): void {
this.alive = false;
}
getRegisterPath() {

View File

@@ -15,6 +15,7 @@ import { AuthServiceStub } from '../../../testing/auth-service.stub';
import { AppState } from '../../../../app.reducer';
import { AuthMethod } from '../../../../core/auth/models/auth.method';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
describe('LogInPasswordComponent', () => {
@@ -29,8 +30,14 @@ describe('LogInPasswordComponent', () => {
loading: false,
};
let hardRedirectService: HardRedirectService;
beforeEach(() => {
user = EPersonMock;
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
getCurrentRoute: {}
});
});
beforeEach(async(() => {
@@ -47,7 +54,8 @@ describe('LogInPasswordComponent', () => {
],
providers: [
{ provide: AuthService, useClass: AuthServiceStub },
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password) }
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password) },
{ provide: HardRedirectService, useValue: hardRedirectService },
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA

View File

@@ -13,6 +13,8 @@ import { fadeOut } from '../../../animations/fade';
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
import { renderAuthMethodFor } from '../log-in.methods-decorator';
import { AuthMethod } from '../../../../core/auth/models/auth.method';
import { AuthService } from '../../../../core/auth/auth.service';
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
/**
* /users/sign-in
@@ -66,11 +68,15 @@ export class LogInPasswordComponent implements OnInit {
/**
* @constructor
* @param {AuthMethod} injectedAuthMethodModel
* @param {AuthService} authService
* @param {HardRedirectService} hardRedirectService
* @param {FormBuilder} formBuilder
* @param {Store<State>} store
*/
constructor(
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
private authService: AuthService,
private hardRedirectService: HardRedirectService,
private formBuilder: FormBuilder,
private store: Store<CoreState>
) {
@@ -134,6 +140,8 @@ export class LogInPasswordComponent implements OnInit {
email.trim();
password.trim();
this.authService.setRedirectUrlIfNotSet(this.hardRedirectService.getCurrentRoute());
// dispatch AuthenticationAction
this.store.dispatch(new AuthenticateAction(email, password));

View File

@@ -17,6 +17,7 @@ import { NativeWindowService } from '../../../../core/services/window.service';
import { RouterStub } from '../../../testing/router.stub';
import { ActivatedRouteStub } from '../../../testing/active-router.stub';
import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref';
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
describe('LogInShibbolethComponent', () => {
@@ -30,6 +31,7 @@ describe('LogInShibbolethComponent', () => {
let location;
let authState;
let hardRedirectService: HardRedirectService;
beforeEach(() => {
user = EPersonMock;
@@ -41,6 +43,10 @@ describe('LogInShibbolethComponent', () => {
loaded: false,
loading: false,
};
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
getCurrentRoute: {}
});
});
beforeEach(async(() => {
@@ -59,6 +65,7 @@ describe('LogInShibbolethComponent', () => {
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
{ provide: Router, useValue: new RouterStub() },
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
{ provide: HardRedirectService, useValue: hardRedirectService },
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA

View File

@@ -12,6 +12,8 @@ import { isAuthenticated, isAuthenticationLoading } from '../../../../core/auth/
import { RouteService } from '../../../../core/services/route.service';
import { NativeWindowRef, NativeWindowService } from '../../../../core/services/window.service';
import { isNotNull } from '../../../empty.util';
import { AuthService } from '../../../../core/auth/auth.service';
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
@Component({
selector: 'ds-log-in-shibboleth',
@@ -51,12 +53,16 @@ export class LogInShibbolethComponent implements OnInit {
* @param {AuthMethod} injectedAuthMethodModel
* @param {NativeWindowRef} _window
* @param {RouteService} route
* @param {AuthService} authService
* @param {HardRedirectService} hardRedirectService
* @param {Store<State>} store
*/
constructor(
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
@Inject(NativeWindowService) protected _window: NativeWindowRef,
private route: RouteService,
private authService: AuthService,
private hardRedirectService: HardRedirectService,
private store: Store<CoreState>
) {
this.authMethod = injectedAuthMethodModel;
@@ -75,6 +81,7 @@ export class LogInShibbolethComponent implements OnInit {
}
redirectToShibboleth() {
this.authService.setRedirectUrlIfNotSet(this.hardRedirectService.getCurrentRoute())
let newLocationUrl = this.location;
const currentUrl = this._window.nativeWindow.location.href;
const myRegexp = /\?redirectUrl=(.*)/g;

View File

@@ -154,4 +154,12 @@ export class AuthServiceStub {
resetAuthenticationError() {
return;
}
setRedirectUrlIfNotSet(url: string) {
return;
}
redirectAfterLoginSuccess() {
return;
}
}

View File

@@ -40,7 +40,6 @@ export function locationProvider(): Location {
return window.location;
}
@NgModule({
bootstrap: [AppComponent],
imports: [