mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Merge branch 'w2p-72699_Hard-redirect-after-log-in' into w2p-72541_User-agreement-and-Privacy-statement
Conflicts: src/app/app-routing.module.ts
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { AuthBlockingGuard } from './core/auth/auth-blocking.guard';
|
||||||
|
|
||||||
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
||||||
import { AuthenticatedGuard } from './core/auth/authenticated.guard';
|
import { AuthenticatedGuard } from './core/auth/authenticated.guard';
|
||||||
@@ -95,46 +96,49 @@ export function getInfoModulePath() {
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forRoot([
|
RouterModule.forRoot([
|
||||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
{ path: '', canActivate: [AuthBlockingGuard],
|
||||||
{ path: 'reload/:rnd', component: PageNotFoundComponent, pathMatch: 'full', canActivate: [ReloadGuard] },
|
children: [
|
||||||
{ path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule', data: { showBreadcrumbs: false } },
|
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||||
{ path: 'community-list', loadChildren: './community-list-page/community-list-page.module#CommunityListPageModule' },
|
{ path: 'reload/:rnd', component: PageNotFoundComponent, pathMatch: 'full', canActivate: [ReloadGuard] },
|
||||||
{ path: 'id', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
|
{ path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule', data: { showBreadcrumbs: false } },
|
||||||
{ path: 'handle', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
|
{ path: 'community-list', loadChildren: './community-list-page/community-list-page.module#CommunityListPageModule' },
|
||||||
{ path: REGISTER_PATH, loadChildren: './register-page/register-page.module#RegisterPageModule' },
|
{ path: 'id', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
|
||||||
{ path: FORGOT_PASSWORD_PATH, loadChildren: './forgot-password/forgot-password.module#ForgotPasswordModule' },
|
{ path: 'handle', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' },
|
||||||
{ path: COMMUNITY_MODULE_PATH, loadChildren: './+community-page/community-page.module#CommunityPageModule' },
|
{ path: REGISTER_PATH, loadChildren: './register-page/register-page.module#RegisterPageModule' },
|
||||||
{ path: COLLECTION_MODULE_PATH, loadChildren: './+collection-page/collection-page.module#CollectionPageModule' },
|
{ path: FORGOT_PASSWORD_PATH, loadChildren: './forgot-password/forgot-password.module#ForgotPasswordModule' },
|
||||||
{ path: ITEM_MODULE_PATH, loadChildren: './+item-page/item-page.module#ItemPageModule' },
|
{ path: COMMUNITY_MODULE_PATH, loadChildren: './+community-page/community-page.module#CommunityPageModule' },
|
||||||
{ path: BITSTREAM_MODULE_PATH, loadChildren: './+bitstream-page/bitstream-page.module#BitstreamPageModule' },
|
{ path: COLLECTION_MODULE_PATH, loadChildren: './+collection-page/collection-page.module#CollectionPageModule' },
|
||||||
{
|
{ path: ITEM_MODULE_PATH, loadChildren: './+item-page/item-page.module#ItemPageModule' },
|
||||||
path: 'mydspace',
|
{ path: BITSTREAM_MODULE_PATH, loadChildren: './+bitstream-page/bitstream-page.module#BitstreamPageModule' },
|
||||||
loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule',
|
{
|
||||||
canActivate: [AuthenticatedGuard, EndUserAgreementGuard]
|
path: 'mydspace',
|
||||||
},
|
loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule',
|
||||||
{ path: 'search', loadChildren: './+search-page/search-page-routing.module#SearchPageRoutingModule' },
|
canActivate: [AuthenticatedGuard, EndUserAgreementGuard]
|
||||||
{ path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule'},
|
},
|
||||||
{ path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [SiteAdministratorGuard, EndUserAgreementGuard] },
|
{ path: 'search', loadChildren: './+search-page/search-page-routing.module#SearchPageRoutingModule' },
|
||||||
{ path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
|
{ path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule'},
|
||||||
{ path: 'logout', loadChildren: './+logout-page/logout-page.module#LogoutPageModule' },
|
{ path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [SiteAdministratorGuard, EndUserAgreementGuard] },
|
||||||
{ path: 'submit', loadChildren: './+submit-page/submit-page.module#SubmitPageModule' },
|
{ path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
|
||||||
{
|
{ path: 'logout', loadChildren: './+logout-page/logout-page.module#LogoutPageModule' },
|
||||||
path: 'workspaceitems',
|
{ path: 'submit', loadChildren: './+submit-page/submit-page.module#SubmitPageModule' },
|
||||||
loadChildren: './+workspaceitems-edit-page/workspaceitems-edit-page.module#WorkspaceitemsEditPageModule'
|
{
|
||||||
},
|
path: 'workspaceitems',
|
||||||
{
|
loadChildren: './+workspaceitems-edit-page/workspaceitems-edit-page.module#WorkspaceitemsEditPageModule'
|
||||||
path: WORKFLOW_ITEM_MODULE_PATH,
|
},
|
||||||
loadChildren: './+workflowitems-edit-page/workflowitems-edit-page.module#WorkflowItemsEditPageModule'
|
{
|
||||||
},
|
path: WORKFLOW_ITEM_MODULE_PATH,
|
||||||
{
|
loadChildren: './+workflowitems-edit-page/workflowitems-edit-page.module#WorkflowItemsEditPageModule'
|
||||||
path: PROFILE_MODULE_PATH,
|
},
|
||||||
loadChildren: './profile-page/profile-page.module#ProfilePageModule', canActivate: [AuthenticatedGuard, EndUserAgreementGuard]
|
{
|
||||||
},
|
path: PROFILE_MODULE_PATH,
|
||||||
{ path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard, EndUserAgreementGuard] },
|
loadChildren: './profile-page/profile-page.module#ProfilePageModule', canActivate: [AuthenticatedGuard, EndUserAgreementGuard]
|
||||||
{ path: INFO_MODULE_PATH, loadChildren: './info/info.module#InfoModule' },
|
},
|
||||||
{ path: UNAUTHORIZED_PATH, component: UnauthorizedComponent },
|
{ path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard, EndUserAgreementGuard] },
|
||||||
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
{ path: INFO_MODULE_PATH, loadChildren: './info/info.module#InfoModule' },
|
||||||
],
|
{ path: UNAUTHORIZED_PATH, component: UnauthorizedComponent },
|
||||||
|
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
||||||
|
]}
|
||||||
|
],
|
||||||
{
|
{
|
||||||
onSameUrlNavigation: 'reload',
|
onSameUrlNavigation: 'reload',
|
||||||
})
|
})
|
||||||
|
@@ -1,7 +1,4 @@
|
|||||||
<div class="text-center ds-full-screen-loader d-flex align-items-center flex-column justify-content-center" *ngIf="!(hasAuthFinishedLoading$ | async)">
|
<div class="outer-wrapper" *ngIf="isAuthBlocking$ | async; else authLoader">
|
||||||
<ds-loading [showMessage]="false"></ds-loading>
|
|
||||||
</div>
|
|
||||||
<div class="outer-wrapper" *ngIf="hasAuthFinishedLoading$ | async">
|
|
||||||
<ds-admin-sidebar></ds-admin-sidebar>
|
<ds-admin-sidebar></ds-admin-sidebar>
|
||||||
<div class="inner-wrapper" [@slideSidebarPadding]="{
|
<div class="inner-wrapper" [@slideSidebarPadding]="{
|
||||||
value: (!(sidebarVisible | async) ? 'hidden' : (slideSidebarOver | async) ? 'shown' : 'expanded'),
|
value: (!(sidebarVisible | async) ? 'hidden' : (slideSidebarOver | async) ? 'shown' : 'expanded'),
|
||||||
@@ -26,3 +23,8 @@
|
|||||||
<ds-footer></ds-footer>
|
<ds-footer></ds-footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ng-template #authLoader>
|
||||||
|
<div class="text-center ds-full-screen-loader d-flex align-items-center flex-column justify-content-center">
|
||||||
|
<ds-loading [showMessage]="false"></ds-loading>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { delay, filter, map, take, distinctUntilChanged } from 'rxjs/operators';
|
import { delay, map, distinctUntilChanged } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
@@ -19,7 +19,7 @@ import { MetadataService } from './core/metadata/metadata.service';
|
|||||||
import { HostWindowResizeAction } from './shared/host-window.actions';
|
import { HostWindowResizeAction } from './shared/host-window.actions';
|
||||||
import { HostWindowState } from './shared/search/host-window.reducer';
|
import { HostWindowState } from './shared/search/host-window.reducer';
|
||||||
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
||||||
import { isAuthenticated, isAuthenticationLoading } from './core/auth/selectors';
|
import { isAuthenticationBlocking, isAuthenticationLoading } from './core/auth/selectors';
|
||||||
import { AuthService } from './core/auth/auth.service';
|
import { AuthService } from './core/auth/auth.service';
|
||||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
||||||
import { MenuService } from './shared/menu/menu.service';
|
import { MenuService } from './shared/menu/menu.service';
|
||||||
@@ -55,7 +55,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
/**
|
/**
|
||||||
* Whether or not the authenticated has finished loading
|
* Whether or not the authenticated has finished loading
|
||||||
*/
|
*/
|
||||||
hasAuthFinishedLoading$: Observable<boolean>;
|
isAuthBlocking$: Observable<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(NativeWindowService) private _window: NativeWindowRef,
|
@Inject(NativeWindowService) private _window: NativeWindowRef,
|
||||||
@@ -94,8 +94,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.hasAuthFinishedLoading$ = this.store.pipe(select(isAuthenticationLoading)).pipe(
|
this.isAuthBlocking$ = this.store.pipe(select(isAuthenticationBlocking)).pipe(
|
||||||
map((isLoading: boolean) => isLoading === false),
|
map((isBlocking: boolean) => isBlocking === false),
|
||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
);
|
);
|
||||||
const env: string = environment.production ? 'Production' : 'Development';
|
const env: string = environment.production ? 'Production' : 'Development';
|
||||||
@@ -103,11 +103,6 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
console.info(`Environment: %c${env}`, `color: ${color}; font-weight: bold;`);
|
console.info(`Environment: %c${env}`, `color: ${color}; font-weight: bold;`);
|
||||||
this.dispatchWindowSize(this._window.nativeWindow.innerWidth, this._window.nativeWindow.innerHeight);
|
this.dispatchWindowSize(this._window.nativeWindow.innerWidth, this._window.nativeWindow.innerHeight);
|
||||||
|
|
||||||
// Whether is not authenticathed try to retrieve a possible stored auth token
|
|
||||||
this.store.pipe(select(isAuthenticated),
|
|
||||||
take(1),
|
|
||||||
filter((authenticated) => !authenticated)
|
|
||||||
).subscribe((authenticated) => this.authService.checkAuthenticationToken());
|
|
||||||
this.sidebarVisible = this.menuService.isMenuVisible(MenuID.ADMIN);
|
this.sidebarVisible = this.menuService.isMenuVisible(MenuID.ADMIN);
|
||||||
|
|
||||||
this.collapsedSidebarWidth = this.cssService.getVariable('collapsedSidebarWidth');
|
this.collapsedSidebarWidth = this.cssService.getVariable('collapsedSidebarWidth');
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import { APP_BASE_HREF, CommonModule } from '@angular/common';
|
import { APP_BASE_HREF, CommonModule } from '@angular/common';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { NgModule } from '@angular/core';
|
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||||
|
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
|
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
|
||||||
import { MetaReducer, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
|
import { MetaReducer, Store, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
|
||||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||||
import { DYNAMIC_MATCHER_PROVIDERS } from '@ng-dynamic-forms/core';
|
import { DYNAMIC_MATCHER_PROVIDERS } from '@ng-dynamic-forms/core';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
@@ -21,6 +21,7 @@ import { AppComponent } from './app.component';
|
|||||||
import { appEffects } from './app.effects';
|
import { appEffects } from './app.effects';
|
||||||
import { appMetaReducers, debugMetaReducers } from './app.metareducers';
|
import { appMetaReducers, debugMetaReducers } from './app.metareducers';
|
||||||
import { appReducers, AppState, storeModuleConfig } from './app.reducer';
|
import { appReducers, AppState, storeModuleConfig } from './app.reducer';
|
||||||
|
import { CheckAuthenticationTokenAction } from './core/auth/auth.actions';
|
||||||
|
|
||||||
import { CoreModule } from './core/core.module';
|
import { CoreModule } from './core/core.module';
|
||||||
import { ClientCookieService } from './core/services/client-cookie.service';
|
import { ClientCookieService } from './core/services/client-cookie.service';
|
||||||
@@ -91,6 +92,15 @@ const PROVIDERS = [
|
|||||||
useClass: DSpaceRouterStateSerializer
|
useClass: DSpaceRouterStateSerializer
|
||||||
},
|
},
|
||||||
ClientCookieService,
|
ClientCookieService,
|
||||||
|
// Check the authentication token when the app initializes
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: (store: Store<AppState>,) => {
|
||||||
|
return () => store.dispatch(new CheckAuthenticationTokenAction());
|
||||||
|
},
|
||||||
|
deps: [ Store ],
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
...DYNAMIC_MATCHER_PROVIDERS,
|
...DYNAMIC_MATCHER_PROVIDERS,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
62
src/app/core/auth/auth-blocking.guard.spec.ts
Normal file
62
src/app/core/auth/auth-blocking.guard.spec.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import * as ngrx from '@ngrx/store';
|
||||||
|
import { cold, getTestScheduler, initTestScheduler, resetTestScheduler } from 'jasmine-marbles/es6';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { AppState } from '../../app.reducer';
|
||||||
|
import { AuthBlockingGuard } from './auth-blocking.guard';
|
||||||
|
|
||||||
|
describe('AuthBlockingGuard', () => {
|
||||||
|
let guard: AuthBlockingGuard;
|
||||||
|
beforeEach(() => {
|
||||||
|
guard = new AuthBlockingGuard(new Store<AppState>(undefined, undefined, undefined));
|
||||||
|
initTestScheduler();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
getTestScheduler().flush();
|
||||||
|
resetTestScheduler();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`canActivate`, () => {
|
||||||
|
|
||||||
|
describe(`when authState.loading is undefined`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||||
|
return () => {
|
||||||
|
return () => observableOf(undefined);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
it(`should not emit anything`, () => {
|
||||||
|
expect(guard.canActivate()).toBeObservable(cold('|'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when authState.loading is true`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||||
|
return () => {
|
||||||
|
return () => observableOf(true);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
it(`should not emit anything`, () => {
|
||||||
|
expect(guard.canActivate()).toBeObservable(cold('|'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`when authState.loading is false`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||||
|
return () => {
|
||||||
|
return () => observableOf(false);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
it(`should succeed`, () => {
|
||||||
|
expect(guard.canActivate()).toBeObservable(cold('(a|)', { a: true }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
31
src/app/core/auth/auth-blocking.guard.ts
Normal file
31
src/app/core/auth/auth-blocking.guard.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CanActivate } from '@angular/router';
|
||||||
|
import { select, Store } from '@ngrx/store';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { distinctUntilChanged, filter, map, take, tap } from 'rxjs/operators';
|
||||||
|
import { AppState } from '../../app.reducer';
|
||||||
|
import { isAuthenticationBlocking } from './selectors';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A guard that blocks the loading of any
|
||||||
|
* route until the authentication status has loaded.
|
||||||
|
* To ensure all rest requests get the correct auth header.
|
||||||
|
*/
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AuthBlockingGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
canActivate(): Observable<boolean> {
|
||||||
|
return this.store.pipe(select(isAuthenticationBlocking)).pipe(
|
||||||
|
map((isBlocking: boolean) => isBlocking === false),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
filter((finished: boolean) => finished === true),
|
||||||
|
take(1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -42,6 +42,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
const action = new AuthenticateAction('user', 'password');
|
const action = new AuthenticateAction('user', 'password');
|
||||||
@@ -49,6 +50,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
@@ -62,6 +64,7 @@ describe('authReducer', () => {
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -76,6 +79,7 @@ describe('authReducer', () => {
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -84,6 +88,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
@@ -96,6 +101,7 @@ describe('authReducer', () => {
|
|||||||
it('should properly set the state, in response to a AUTHENTICATED action', () => {
|
it('should properly set the state, in response to a AUTHENTICATED action', () => {
|
||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
|
blocking: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -103,8 +109,15 @@ describe('authReducer', () => {
|
|||||||
};
|
};
|
||||||
const action = new AuthenticatedAction(mockTokenInfo);
|
const action = new AuthenticatedAction(mockTokenInfo);
|
||||||
const newState = authReducer(initialState, action);
|
const newState = authReducer(initialState, action);
|
||||||
|
state = {
|
||||||
expect(newState).toEqual(initialState);
|
authenticated: false,
|
||||||
|
blocking: true,
|
||||||
|
loaded: false,
|
||||||
|
error: undefined,
|
||||||
|
loading: true,
|
||||||
|
info: undefined
|
||||||
|
};
|
||||||
|
expect(newState).toEqual(state);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly set the state, in response to a AUTHENTICATED_SUCCESS action', () => {
|
it('should properly set the state, in response to a AUTHENTICATED_SUCCESS action', () => {
|
||||||
@@ -112,6 +125,7 @@ describe('authReducer', () => {
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -122,6 +136,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -133,6 +148,7 @@ describe('authReducer', () => {
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -143,6 +159,7 @@ describe('authReducer', () => {
|
|||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: 'Test error message',
|
error: 'Test error message',
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -153,6 +170,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
const action = new CheckAuthenticationTokenAction();
|
const action = new CheckAuthenticationTokenAction();
|
||||||
@@ -160,6 +178,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
};
|
};
|
||||||
expect(newState).toEqual(state);
|
expect(newState).toEqual(state);
|
||||||
@@ -169,6 +188,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
};
|
};
|
||||||
const action = new CheckAuthenticationTokenCookieAction();
|
const action = new CheckAuthenticationTokenCookieAction();
|
||||||
@@ -176,6 +196,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
};
|
};
|
||||||
expect(newState).toEqual(state);
|
expect(newState).toEqual(state);
|
||||||
@@ -187,6 +208,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -204,6 +226,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -216,6 +239,7 @@ describe('authReducer', () => {
|
|||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
@@ -230,6 +254,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -242,6 +267,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: 'Test error message',
|
error: 'Test error message',
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -255,6 +281,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -265,6 +292,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -277,6 +305,7 @@ describe('authReducer', () => {
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -287,6 +316,7 @@ describe('authReducer', () => {
|
|||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: 'Test error message',
|
error: 'Test error message',
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined
|
info: undefined
|
||||||
};
|
};
|
||||||
@@ -299,6 +329,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -311,6 +342,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id,
|
userId: EPersonMock.id,
|
||||||
@@ -325,6 +357,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id,
|
userId: EPersonMock.id,
|
||||||
@@ -338,6 +371,7 @@ describe('authReducer', () => {
|
|||||||
authToken: newTokenInfo,
|
authToken: newTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id,
|
userId: EPersonMock.id,
|
||||||
@@ -352,6 +386,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id,
|
userId: EPersonMock.id,
|
||||||
@@ -364,6 +399,7 @@ describe('authReducer', () => {
|
|||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
@@ -378,6 +414,7 @@ describe('authReducer', () => {
|
|||||||
authToken: mockTokenInfo,
|
authToken: mockTokenInfo,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -387,6 +424,7 @@ describe('authReducer', () => {
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
info: 'Message',
|
info: 'Message',
|
||||||
@@ -410,6 +448,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
const action = new AddAuthenticationMessageAction('Message');
|
const action = new AddAuthenticationMessageAction('Message');
|
||||||
@@ -417,6 +456,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: 'Message'
|
info: 'Message'
|
||||||
};
|
};
|
||||||
@@ -427,6 +467,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
info: 'Message'
|
info: 'Message'
|
||||||
@@ -436,6 +477,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
info: undefined
|
info: undefined
|
||||||
@@ -447,6 +489,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false
|
loading: false
|
||||||
};
|
};
|
||||||
const action = new SetRedirectUrlAction('redirect.url');
|
const action = new SetRedirectUrlAction('redirect.url');
|
||||||
@@ -454,6 +497,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
redirectUrl: 'redirect.url'
|
redirectUrl: 'redirect.url'
|
||||||
};
|
};
|
||||||
@@ -464,6 +508,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
authMethods: []
|
authMethods: []
|
||||||
};
|
};
|
||||||
@@ -472,6 +517,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
authMethods: []
|
authMethods: []
|
||||||
};
|
};
|
||||||
@@ -482,6 +528,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
authMethods: []
|
authMethods: []
|
||||||
};
|
};
|
||||||
@@ -494,6 +541,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
authMethods: authMethods
|
authMethods: authMethods
|
||||||
};
|
};
|
||||||
@@ -504,6 +552,7 @@ describe('authReducer', () => {
|
|||||||
initialState = {
|
initialState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: true,
|
||||||
loading: true,
|
loading: true,
|
||||||
authMethods: []
|
authMethods: []
|
||||||
};
|
};
|
||||||
@@ -513,6 +562,7 @@ describe('authReducer', () => {
|
|||||||
state = {
|
state = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
authMethods: [new AuthMethod(AuthMethodType.Password)]
|
authMethods: [new AuthMethod(AuthMethodType.Password)]
|
||||||
};
|
};
|
||||||
|
@@ -39,6 +39,10 @@ export interface AuthState {
|
|||||||
// true when loading
|
// true when loading
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
|
||||||
|
// true when everything else should wait for authorization
|
||||||
|
// to complete
|
||||||
|
blocking: boolean;
|
||||||
|
|
||||||
// info message
|
// info message
|
||||||
info?: string;
|
info?: string;
|
||||||
|
|
||||||
@@ -62,7 +66,8 @@ export interface AuthState {
|
|||||||
const initialState: AuthState = {
|
const initialState: AuthState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
loading: undefined,
|
blocking: true,
|
||||||
|
loading: false,
|
||||||
authMethods: []
|
authMethods: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,7 +91,8 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
case AuthActionTypes.CHECK_AUTHENTICATION_TOKEN:
|
case AuthActionTypes.CHECK_AUTHENTICATION_TOKEN:
|
||||||
case AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE:
|
case AuthActionTypes.CHECK_AUTHENTICATION_TOKEN_COOKIE:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
loading: true
|
loading: true,
|
||||||
|
blocking: true
|
||||||
});
|
});
|
||||||
|
|
||||||
case AuthActionTypes.AUTHENTICATED_ERROR:
|
case AuthActionTypes.AUTHENTICATED_ERROR:
|
||||||
@@ -96,6 +102,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: (action as AuthenticationErrorAction).payload.message,
|
error: (action as AuthenticationErrorAction).payload.message,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: false
|
loading: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -110,6 +117,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
loaded: true,
|
loaded: true,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
blocking: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
userId: (action as RetrieveAuthenticatedEpersonSuccessAction).payload
|
userId: (action as RetrieveAuthenticatedEpersonSuccessAction).payload
|
||||||
});
|
});
|
||||||
@@ -119,6 +127,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: (action as AuthenticationErrorAction).payload.message,
|
error: (action as AuthenticationErrorAction).payload.message,
|
||||||
|
blocking: false,
|
||||||
loading: false
|
loading: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -139,6 +148,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: undefined,
|
info: undefined,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
@@ -151,6 +161,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
authenticated: false,
|
authenticated: false,
|
||||||
authToken: undefined,
|
authToken: undefined,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
info: (action as RedirectWhenTokenExpiredAction as RedirectWhenAuthenticationIsRequiredAction).payload,
|
info: (action as RedirectWhenTokenExpiredAction as RedirectWhenAuthenticationIsRequiredAction).payload,
|
||||||
userId: undefined
|
userId: undefined
|
||||||
@@ -181,18 +192,21 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
// next three cases are used by dynamic rendering of login methods
|
// next three cases are used by dynamic rendering of login methods
|
||||||
case AuthActionTypes.RETRIEVE_AUTH_METHODS:
|
case AuthActionTypes.RETRIEVE_AUTH_METHODS:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
loading: true
|
loading: true,
|
||||||
|
blocking: true
|
||||||
});
|
});
|
||||||
|
|
||||||
case AuthActionTypes.RETRIEVE_AUTH_METHODS_SUCCESS:
|
case AuthActionTypes.RETRIEVE_AUTH_METHODS_SUCCESS:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
blocking: false,
|
||||||
authMethods: (action as RetrieveAuthMethodsSuccessAction).payload
|
authMethods: (action as RetrieveAuthMethodsSuccessAction).payload
|
||||||
});
|
});
|
||||||
|
|
||||||
case AuthActionTypes.RETRIEVE_AUTH_METHODS_ERROR:
|
case AuthActionTypes.RETRIEVE_AUTH_METHODS_ERROR:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
blocking: false,
|
||||||
authMethods: [new AuthMethod(AuthMethodType.Password)]
|
authMethods: [new AuthMethod(AuthMethodType.Password)]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -204,6 +218,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut
|
|||||||
case AuthActionTypes.REDIRECT_AFTER_LOGIN_SUCCESS:
|
case AuthActionTypes.REDIRECT_AFTER_LOGIN_SUCCESS:
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
loading: true,
|
loading: true,
|
||||||
|
blocking: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@@ -436,6 +436,10 @@ export class AuthService {
|
|||||||
this.store.dispatch(new SetRedirectUrlAction(isNotUndefined(url) ? url : ''));
|
this.store.dispatch(new SetRedirectUrlAction(isNotUndefined(url) ? url : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the redirect url if the current one has not been set yet
|
||||||
|
* @param newRedirectUrl
|
||||||
|
*/
|
||||||
setRedirectUrlIfNotSet(newRedirectUrl: string) {
|
setRedirectUrlIfNotSet(newRedirectUrl: string) {
|
||||||
this.getRedirectUrl().pipe(
|
this.getRedirectUrl().pipe(
|
||||||
take(1))
|
take(1))
|
||||||
|
@@ -65,6 +65,14 @@ const _getAuthenticationInfo = (state: AuthState) => state.info;
|
|||||||
*/
|
*/
|
||||||
const _isLoading = (state: AuthState) => state.loading;
|
const _isLoading = (state: AuthState) => state.loading;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if everything else should wait for authentication.
|
||||||
|
* @function _isBlocking
|
||||||
|
* @param {State} state
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
const _isBlocking = (state: AuthState) => state.blocking;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if a refresh token request is in progress.
|
* Returns true if a refresh token request is in progress.
|
||||||
* @function _isRefreshing
|
* @function _isRefreshing
|
||||||
@@ -170,6 +178,16 @@ export const isAuthenticatedLoaded = createSelector(getAuthState, _isAuthenticat
|
|||||||
*/
|
*/
|
||||||
export const isAuthenticationLoading = createSelector(getAuthState, _isLoading);
|
export const isAuthenticationLoading = createSelector(getAuthState, _isLoading);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the authentication should block everything else
|
||||||
|
*
|
||||||
|
* @function isAuthenticationBlocking
|
||||||
|
* @param {AuthState} state
|
||||||
|
* @param {any} props
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export const isAuthenticationBlocking = createSelector(getAuthState, _isBlocking);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the refresh token request is loading.
|
* Returns true if the refresh token request is loading.
|
||||||
* @function isTokenRefreshing
|
* @function isTokenRefreshing
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<ul class="navbar-nav" [ngClass]="{'mr-auto': (isXsOrSm$ | async)}">
|
<ul class="navbar-nav" [ngClass]="{'mr-auto': (isXsOrSm$ | async)}">
|
||||||
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"
|
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"
|
||||||
(click)="$event.stopPropagation();">
|
(click)="$event.stopPropagation();">
|
||||||
<div ngbDropdown display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
<div ngbDropdown #loginDrop display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
||||||
<a href="#" id="dropdownLogin" (click)="$event.preventDefault()" ngbDropdownToggle
|
<a href="#" id="dropdownLogin" (click)="$event.preventDefault()" ngbDropdownToggle
|
||||||
class="px-1">{{ 'nav.login' | translate }}</a>
|
class="px-1">{{ 'nav.login' | translate }}</a>
|
||||||
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu
|
<div id="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu
|
||||||
|
@@ -43,11 +43,13 @@ describe('AuthNavMenuComponent', () => {
|
|||||||
notAuthState = {
|
notAuthState = {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
loading: false
|
loading: false
|
||||||
};
|
};
|
||||||
authState = {
|
authState = {
|
||||||
authenticated: true,
|
authenticated: true,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
authToken: new AuthTokenInfo('test_token'),
|
authToken: new AuthTokenInfo('test_token'),
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
|
@@ -34,6 +34,7 @@ describe('UserMenuComponent', () => {
|
|||||||
authState = {
|
authState = {
|
||||||
authenticated: true,
|
authenticated: true,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
authToken: new AuthTokenInfo('test_token'),
|
authToken: new AuthTokenInfo('test_token'),
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
@@ -41,6 +42,7 @@ describe('UserMenuComponent', () => {
|
|||||||
authStateLoading = {
|
authStateLoading = {
|
||||||
authenticated: true,
|
authenticated: true,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
authToken: null,
|
authToken: null,
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
|
@@ -26,6 +26,7 @@ describe('ImpersonateNavbarComponent', () => {
|
|||||||
authState = {
|
authState = {
|
||||||
authenticated: true,
|
authenticated: true,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
|
blocking: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
authToken: new AuthTokenInfo('test_token'),
|
authToken: new AuthTokenInfo('test_token'),
|
||||||
userId: EPersonMock.id
|
userId: EPersonMock.id
|
||||||
|
@@ -15,6 +15,12 @@ export class LogInContainerComponent implements OnInit {
|
|||||||
|
|
||||||
@Input() authMethod: AuthMethod;
|
@Input() authMethod: AuthMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if LogInContainerComponent is in a standalone page
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
@Input() isStandalonePage: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injector to inject a section component with the @Input parameters
|
* Injector to inject a section component with the @Input parameters
|
||||||
* @type {Injector}
|
* @type {Injector}
|
||||||
@@ -36,6 +42,7 @@ export class LogInContainerComponent implements OnInit {
|
|||||||
this.objectInjector = Injector.create({
|
this.objectInjector = Injector.create({
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: 'authMethodProvider', useFactory: () => (this.authMethod), deps: [] },
|
{ provide: 'authMethodProvider', useFactory: () => (this.authMethod), deps: [] },
|
||||||
|
{ provide: 'isStandalonePage', useFactory: () => (this.isStandalonePage), deps: [] },
|
||||||
],
|
],
|
||||||
parent: this.injector
|
parent: this.injector
|
||||||
});
|
});
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<div *ngIf="i === 1" class="text-center mt-2">
|
<div *ngIf="i === 1" class="text-center mt-2">
|
||||||
<span class="align-middle">{{"login.form.or-divider" | translate}}</span>
|
<span class="align-middle">{{"login.form.or-divider" | translate}}</span>
|
||||||
</div>
|
</div>
|
||||||
<ds-log-in-container [authMethod]="authMethod"></ds-log-in-container>
|
<ds-log-in-container [authMethod]="authMethod" [isStandalonePage]="isStandalonePage"></ds-log-in-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
|
@@ -2,9 +2,16 @@ import { Component, Input, OnInit } from '@angular/core';
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { select, Store } from '@ngrx/store';
|
import { select, Store } from '@ngrx/store';
|
||||||
import { AuthMethod } from '../../core/auth/models/auth.method';
|
import { AuthMethod } from '../../core/auth/models/auth.method';
|
||||||
import { getAuthenticationMethods, isAuthenticated, isAuthenticationLoading } from '../../core/auth/selectors';
|
import {
|
||||||
|
getAuthenticationError,
|
||||||
|
getAuthenticationMethods,
|
||||||
|
isAuthenticated,
|
||||||
|
isAuthenticationLoading
|
||||||
|
} from '../../core/auth/selectors';
|
||||||
import { CoreState } from '../../core/core.reducers';
|
import { CoreState } from '../../core/core.reducers';
|
||||||
import { getForgotPasswordPath, getRegisterPath } from '../../app-routing.module';
|
import { getForgotPasswordPath, getRegisterPath } from '../../app-routing.module';
|
||||||
|
import { hasValue } from '../empty.util';
|
||||||
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* /users/sign-in
|
* /users/sign-in
|
||||||
@@ -41,7 +48,8 @@ export class LogInComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
public loading: Observable<boolean>;
|
public loading: Observable<boolean>;
|
||||||
|
|
||||||
constructor(private store: Store<CoreState>) {
|
constructor(private store: Store<CoreState>,
|
||||||
|
private authService: AuthService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -55,6 +63,13 @@ export class LogInComponent implements OnInit {
|
|||||||
|
|
||||||
// set isAuthenticated
|
// set isAuthenticated
|
||||||
this.isAuthenticated = this.store.pipe(select(isAuthenticated));
|
this.isAuthenticated = this.store.pipe(select(isAuthenticated));
|
||||||
|
|
||||||
|
// Clear the redirect URL if an authentication error occurs and this is not a standalone page
|
||||||
|
this.store.pipe(select(getAuthenticationError)).subscribe((error) => {
|
||||||
|
if (hasValue(error) && !this.isStandalonePage) {
|
||||||
|
this.authService.clearRedirectUrl();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getRegisterPath() {
|
getRegisterPath() {
|
||||||
|
@@ -55,6 +55,7 @@ describe('LogInPasswordComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: AuthService, useClass: AuthServiceStub },
|
{ provide: AuthService, useClass: AuthServiceStub },
|
||||||
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password) },
|
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Password) },
|
||||||
|
{ provide: 'isStandalonePage', useValue: true },
|
||||||
{ provide: HardRedirectService, useValue: hardRedirectService },
|
{ provide: HardRedirectService, useValue: hardRedirectService },
|
||||||
],
|
],
|
||||||
schemas: [
|
schemas: [
|
||||||
|
@@ -68,6 +68,7 @@ export class LogInPasswordComponent implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {AuthMethod} injectedAuthMethodModel
|
* @param {AuthMethod} injectedAuthMethodModel
|
||||||
|
* @param {boolean} isStandalonePage
|
||||||
* @param {AuthService} authService
|
* @param {AuthService} authService
|
||||||
* @param {HardRedirectService} hardRedirectService
|
* @param {HardRedirectService} hardRedirectService
|
||||||
* @param {FormBuilder} formBuilder
|
* @param {FormBuilder} formBuilder
|
||||||
@@ -75,6 +76,7 @@ export class LogInPasswordComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
|
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
|
||||||
|
@Inject('isStandalonePage') public isStandalonePage: boolean,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private hardRedirectService: HardRedirectService,
|
private hardRedirectService: HardRedirectService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
@@ -140,7 +142,11 @@ export class LogInPasswordComponent implements OnInit {
|
|||||||
email.trim();
|
email.trim();
|
||||||
password.trim();
|
password.trim();
|
||||||
|
|
||||||
this.authService.setRedirectUrlIfNotSet(this.hardRedirectService.getCurrentRoute());
|
if (!this.isStandalonePage) {
|
||||||
|
this.authService.setRedirectUrl(this.hardRedirectService.getCurrentRoute());
|
||||||
|
} else {
|
||||||
|
this.authService.setRedirectUrlIfNotSet('/');
|
||||||
|
}
|
||||||
|
|
||||||
// dispatch AuthenticationAction
|
// dispatch AuthenticationAction
|
||||||
this.store.dispatch(new AuthenticateAction(email, password));
|
this.store.dispatch(new AuthenticateAction(email, password));
|
||||||
|
@@ -62,6 +62,7 @@ describe('LogInShibbolethComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: AuthService, useClass: AuthServiceStub },
|
{ provide: AuthService, useClass: AuthServiceStub },
|
||||||
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Shibboleth, location) },
|
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Shibboleth, location) },
|
||||||
|
{ provide: 'isStandalonePage', useValue: true },
|
||||||
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
|
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
|
||||||
{ provide: Router, useValue: new RouterStub() },
|
{ provide: Router, useValue: new RouterStub() },
|
||||||
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
|
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
|
||||||
|
@@ -51,6 +51,7 @@ export class LogInShibbolethComponent implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {AuthMethod} injectedAuthMethodModel
|
* @param {AuthMethod} injectedAuthMethodModel
|
||||||
|
* @param {boolean} isStandalonePage
|
||||||
* @param {NativeWindowRef} _window
|
* @param {NativeWindowRef} _window
|
||||||
* @param {RouteService} route
|
* @param {RouteService} route
|
||||||
* @param {AuthService} authService
|
* @param {AuthService} authService
|
||||||
@@ -59,6 +60,7 @@ export class LogInShibbolethComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
|
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
|
||||||
|
@Inject('isStandalonePage') public isStandalonePage: boolean,
|
||||||
@Inject(NativeWindowService) protected _window: NativeWindowRef,
|
@Inject(NativeWindowService) protected _window: NativeWindowRef,
|
||||||
private route: RouteService,
|
private route: RouteService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
@@ -81,7 +83,11 @@ export class LogInShibbolethComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
redirectToShibboleth() {
|
redirectToShibboleth() {
|
||||||
this.authService.setRedirectUrlIfNotSet(this.hardRedirectService.getCurrentRoute())
|
if (!this.isStandalonePage) {
|
||||||
|
this.authService.setRedirectUrl(this.hardRedirectService.getCurrentRoute());
|
||||||
|
} else {
|
||||||
|
this.authService.setRedirectUrlIfNotSet('/');
|
||||||
|
}
|
||||||
let newLocationUrl = this.location;
|
let newLocationUrl = this.location;
|
||||||
const currentUrl = this._window.nativeWindow.location.href;
|
const currentUrl = this._window.nativeWindow.location.href;
|
||||||
const myRegexp = /\?redirectUrl=(.*)/g;
|
const myRegexp = /\?redirectUrl=(.*)/g;
|
||||||
|
@@ -162,4 +162,8 @@ export class AuthServiceStub {
|
|||||||
redirectAfterLoginSuccess() {
|
redirectAfterLoginSuccess() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearRedirectUrl() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user