mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[DURACOM-234] Migrate to functional guards WIP
This commit is contained in:
@@ -36,7 +36,7 @@ export function getBitstreamRequestACopyRoute(item, bitstream): { routerLink: st
|
|||||||
}
|
}
|
||||||
export const COAR_NOTIFY_SUPPORT = 'coar-notify-support';
|
export const COAR_NOTIFY_SUPPORT = 'coar-notify-support';
|
||||||
|
|
||||||
export const HOME_PAGE_PATH = 'admin';
|
export const HOME_PAGE_PATH = 'home';
|
||||||
|
|
||||||
export function getHomePageRoute() {
|
export function getHomePageRoute() {
|
||||||
return `/${HOME_PAGE_PATH}`;
|
return `/${HOME_PAGE_PATH}`;
|
||||||
|
@@ -11,7 +11,7 @@ import { BrowseByDataType } from './browse-by-switcher/browse-by-data-type';
|
|||||||
|
|
||||||
describe('BrowseByGuard', () => {
|
describe('BrowseByGuard', () => {
|
||||||
describe('canActivate', () => {
|
describe('canActivate', () => {
|
||||||
let guard: BrowseByGuard;
|
let guard: any;
|
||||||
let translateService: any;
|
let translateService: any;
|
||||||
let browseDefinitionService: any;
|
let browseDefinitionService: any;
|
||||||
let router: any;
|
let router: any;
|
||||||
@@ -35,7 +35,7 @@ describe('BrowseByGuard', () => {
|
|||||||
|
|
||||||
router = new RouterStub() as any;
|
router = new RouterStub() as any;
|
||||||
|
|
||||||
guard = new BrowseByGuard(translateService, browseDefinitionService, router);
|
guard = BrowseByGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true, and sets up the data correctly, with a scope and value', () => {
|
it('should return true, and sets up the data correctly, with a scope and value', () => {
|
||||||
@@ -53,7 +53,7 @@ describe('BrowseByGuard', () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
guard.canActivate(scopedRoute as any, undefined)
|
guard(scopedRoute as any, undefined, browseDefinitionService, router, translateService)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) => {
|
(canActivate) => {
|
||||||
@@ -86,7 +86,7 @@ describe('BrowseByGuard', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
guard.canActivate(scopedNoValueRoute as any, undefined)
|
guard(scopedNoValueRoute, undefined, browseDefinitionService, router, translateService)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) => {
|
(canActivate) => {
|
||||||
@@ -123,7 +123,7 @@ describe('BrowseByGuard', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
guard.canActivate(scopedNoValueRoute as any, undefined).pipe(
|
guard(scopedNoValueRoute as any, undefined, browseDefinitionService, router, translateService).pipe(
|
||||||
first(),
|
first(),
|
||||||
).subscribe((canActivate) => {
|
).subscribe((canActivate) => {
|
||||||
const result = {
|
const result = {
|
||||||
@@ -154,7 +154,8 @@ describe('BrowseByGuard', () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
guard.canActivate(route as any, undefined)
|
|
||||||
|
guard(route as any, undefined, browseDefinitionService, router, translateService)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) => {
|
(canActivate) => {
|
||||||
@@ -189,7 +190,8 @@ describe('BrowseByGuard', () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
guard.canActivate(scopedRoute as any, undefined)
|
|
||||||
|
guard(scopedRoute as any, undefined, browseDefinitionService, router, translateService)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe((canActivate) => {
|
.subscribe((canActivate) => {
|
||||||
expect(router.navigate).toHaveBeenCalled();
|
expect(router.navigate).toHaveBeenCalled();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
Data,
|
Data,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
@@ -25,55 +26,47 @@ import {
|
|||||||
hasValue,
|
hasValue,
|
||||||
} from '../shared/empty.util';
|
} from '../shared/empty.util';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
export const BrowseByGuard: CanActivateFn = (
|
||||||
/**
|
route: ActivatedRouteSnapshot,
|
||||||
* A guard taking care of the correct route.data being set for the Browse-By components
|
state: RouterStateSnapshot,
|
||||||
*/
|
browseDefinitionService: BrowseDefinitionDataService = inject(BrowseDefinitionDataService),
|
||||||
export class BrowseByGuard {
|
router: Router = inject(Router),
|
||||||
|
translate: TranslateService = inject(TranslateService),
|
||||||
constructor(
|
): Observable<boolean> => {
|
||||||
protected translate: TranslateService,
|
const title = route.data.title;
|
||||||
protected browseDefinitionService: BrowseDefinitionDataService,
|
const id = route.params.id || route.queryParams.id || route.data.id;
|
||||||
protected router: Router,
|
let browseDefinition$: Observable<BrowseDefinition | undefined>;
|
||||||
) {
|
if (hasNoValue(route.data.browseDefinition) && hasValue(id)) {
|
||||||
}
|
browseDefinition$ = browseDefinitionService.findById(id).pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
map((browseDefinitionRD: RemoteData<BrowseDefinition>) => browseDefinitionRD.payload),
|
||||||
const title = route.data.title;
|
|
||||||
const id = route.params.id || route.queryParams.id || route.data.id;
|
|
||||||
let browseDefinition$: Observable<BrowseDefinition | undefined>;
|
|
||||||
if (hasNoValue(route.data.browseDefinition) && hasValue(id)) {
|
|
||||||
browseDefinition$ = this.browseDefinitionService.findById(id).pipe(
|
|
||||||
getFirstCompletedRemoteData(),
|
|
||||||
map((browseDefinitionRD: RemoteData<BrowseDefinition>) => browseDefinitionRD.payload),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
browseDefinition$ = observableOf(route.data.browseDefinition);
|
|
||||||
}
|
|
||||||
const scope = route.queryParams.scope ?? route.parent?.params.id;
|
|
||||||
const value = route.queryParams.value;
|
|
||||||
const metadataTranslated = this.translate.instant(`browse.metadata.${id}`);
|
|
||||||
return browseDefinition$.pipe(
|
|
||||||
switchMap((browseDefinition: BrowseDefinition | undefined) => {
|
|
||||||
if (hasValue(browseDefinition)) {
|
|
||||||
route.data = this.createData(title, id, browseDefinition, metadataTranslated, value, route, scope);
|
|
||||||
return observableOf(true);
|
|
||||||
} else {
|
|
||||||
void this.router.navigate([PAGE_NOT_FOUND_PATH]);
|
|
||||||
return observableOf(false);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
browseDefinition$ = observableOf(route.data.browseDefinition);
|
||||||
}
|
}
|
||||||
|
const scope = route.queryParams.scope ?? route.parent?.params.id;
|
||||||
|
const value = route.queryParams.value;
|
||||||
|
const metadataTranslated = translate.instant(`browse.metadata.${id}`);
|
||||||
|
return browseDefinition$.pipe(
|
||||||
|
switchMap((browseDefinition: BrowseDefinition | undefined) => {
|
||||||
|
if (hasValue(browseDefinition)) {
|
||||||
|
route.data = createData(title, id, browseDefinition, metadataTranslated, value, route, scope);
|
||||||
|
return observableOf(true);
|
||||||
|
} else {
|
||||||
|
void router.navigate([PAGE_NOT_FOUND_PATH]);
|
||||||
|
return observableOf(false);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
private createData(title: string, id: string, browseDefinition: BrowseDefinition, field: string, value: string, route: ActivatedRouteSnapshot, scope: string): Data {
|
function createData(title: string, id: string, browseDefinition: BrowseDefinition, field: string, value: string, route: ActivatedRouteSnapshot, scope: string): Data {
|
||||||
return Object.assign({}, route.data, {
|
return Object.assign({}, route.data, {
|
||||||
title: title,
|
title: title,
|
||||||
id: id,
|
id: id,
|
||||||
browseDefinition: browseDefinition,
|
browseDefinition: browseDefinition,
|
||||||
field: field,
|
field: field,
|
||||||
value: hasValue(value) ? `"${value}"` : '',
|
value: hasValue(value) ? `"${value}"` : '',
|
||||||
scope: scope,
|
scope: scope,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import { CreateCollectionPageGuard } from './create-collection-page.guard';
|
|||||||
|
|
||||||
describe('CreateCollectionPageGuard', () => {
|
describe('CreateCollectionPageGuard', () => {
|
||||||
describe('canActivate', () => {
|
describe('canActivate', () => {
|
||||||
let guard: CreateCollectionPageGuard;
|
let guard: any;
|
||||||
let router;
|
let router;
|
||||||
let communityDataServiceStub: any;
|
let communityDataServiceStub: any;
|
||||||
|
|
||||||
@@ -28,11 +28,11 @@ describe('CreateCollectionPageGuard', () => {
|
|||||||
};
|
};
|
||||||
router = new RouterMock();
|
router = new RouterMock();
|
||||||
|
|
||||||
guard = new CreateCollectionPageGuard(router, communityDataServiceStub);
|
guard = CreateCollectionPageGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when the parent ID resolves to a community', () => {
|
it('should return true when the parent ID resolves to a community', () => {
|
||||||
guard.canActivate({ queryParams: { parent: 'valid-id' } } as any, undefined)
|
guard({ queryParams: { parent: 'valid-id' } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
@@ -41,7 +41,7 @@ describe('CreateCollectionPageGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when no parent ID has been provided', () => {
|
it('should return false when no parent ID has been provided', () => {
|
||||||
guard.canActivate({ queryParams: { } } as any, undefined)
|
guard({ queryParams: { } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
@@ -50,7 +50,7 @@ describe('CreateCollectionPageGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when the parent ID does not resolve to a community', () => {
|
it('should return false when the parent ID does not resolve to a community', () => {
|
||||||
guard.canActivate({ queryParams: { parent: 'invalid-id' } } as any, undefined)
|
guard({ queryParams: { parent: 'invalid-id' } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
@@ -59,7 +59,7 @@ describe('CreateCollectionPageGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when the parent ID resolves to an error response', () => {
|
it('should return false when the parent ID resolves to an error response', () => {
|
||||||
guard.canActivate({ queryParams: { parent: 'error-id' } } as any, undefined)
|
guard({ queryParams: { parent: 'error-id' } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
CanActivate,
|
CanActivateFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
@@ -24,34 +24,29 @@ import {
|
|||||||
} from '../../shared/empty.util';
|
} from '../../shared/empty.util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent creation of a collection without a parent community provided
|
* True when either a parent ID query parameter has been provided and the parent ID resolves to a valid parent community
|
||||||
* @class CreateCollectionPageGuard
|
* Reroutes to a 404 page when the page cannot be activated
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
export const CreateCollectionPageGuard: CanActivateFn = (
|
||||||
export class CreateCollectionPageGuard implements CanActivate {
|
route: ActivatedRouteSnapshot,
|
||||||
public constructor(private router: Router, private communityService: CommunityDataService) {
|
state: RouterStateSnapshot,
|
||||||
|
communityService: CommunityDataService = inject(CommunityDataService),
|
||||||
|
router: Router = inject(Router),
|
||||||
|
): Observable<boolean> => {
|
||||||
|
const parentID = route.queryParams.parent;
|
||||||
|
if (hasNoValue(parentID)) {
|
||||||
|
router.navigate(['/404']);
|
||||||
|
return observableOf(false);
|
||||||
}
|
}
|
||||||
|
return communityService.findById(parentID)
|
||||||
|
.pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
map((communityRD: RemoteData<Community>) => hasValue(communityRD) && communityRD.hasSucceeded && hasValue(communityRD.payload)),
|
||||||
|
tap((isValid: boolean) => {
|
||||||
|
if (!isValid) {
|
||||||
|
router.navigate(['/404']);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* True when either a parent ID query parameter has been provided and the parent ID resolves to a valid parent community
|
|
||||||
* Reroutes to a 404 page when the page cannot be activated
|
|
||||||
* @method canActivate
|
|
||||||
*/
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
|
||||||
const parentID = route.queryParams.parent;
|
|
||||||
if (hasNoValue(parentID)) {
|
|
||||||
this.router.navigate(['/404']);
|
|
||||||
return observableOf(false);
|
|
||||||
}
|
|
||||||
return this.communityService.findById(parentID)
|
|
||||||
.pipe(
|
|
||||||
getFirstCompletedRemoteData(),
|
|
||||||
map((communityRD: RemoteData<Community>) => hasValue(communityRD) && communityRD.hasSucceeded && hasValue(communityRD.payload)),
|
|
||||||
tap((isValid: boolean) => {
|
|
||||||
if (!isValid) {
|
|
||||||
this.router.navigate(['/404']);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -10,7 +10,7 @@ import { CreateCommunityPageGuard } from './create-community-page.guard';
|
|||||||
|
|
||||||
describe('CreateCommunityPageGuard', () => {
|
describe('CreateCommunityPageGuard', () => {
|
||||||
describe('canActivate', () => {
|
describe('canActivate', () => {
|
||||||
let guard: CreateCommunityPageGuard;
|
let guard: any;
|
||||||
let router;
|
let router;
|
||||||
let communityDataServiceStub: any;
|
let communityDataServiceStub: any;
|
||||||
|
|
||||||
@@ -28,11 +28,11 @@ describe('CreateCommunityPageGuard', () => {
|
|||||||
};
|
};
|
||||||
router = new RouterMock();
|
router = new RouterMock();
|
||||||
|
|
||||||
guard = new CreateCommunityPageGuard(router, communityDataServiceStub);
|
guard = CreateCommunityPageGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when the parent ID resolves to a community', () => {
|
it('should return true when the parent ID resolves to a community', () => {
|
||||||
guard.canActivate({ queryParams: { parent: 'valid-id' } } as any, undefined)
|
guard({ queryParams: { parent: 'valid-id' } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
@@ -41,7 +41,7 @@ describe('CreateCommunityPageGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when no parent ID has been provided', () => {
|
it('should return true when no parent ID has been provided', () => {
|
||||||
guard.canActivate({ queryParams: { } } as any, undefined)
|
guard({ queryParams: { } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
@@ -50,7 +50,7 @@ describe('CreateCommunityPageGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when the parent ID does not resolve to a community', () => {
|
it('should return false when the parent ID does not resolve to a community', () => {
|
||||||
guard.canActivate({ queryParams: { parent: 'invalid-id' } } as any, undefined)
|
guard({ queryParams: { parent: 'invalid-id' } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
@@ -59,7 +59,7 @@ describe('CreateCommunityPageGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when the parent ID resolves to an error response', () => {
|
it('should return false when the parent ID resolves to an error response', () => {
|
||||||
guard.canActivate({ queryParams: { parent: 'error-id' } } as any, undefined)
|
guard({ queryParams: { parent: 'error-id' } } as any, undefined, communityDataServiceStub, router)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(canActivate) =>
|
(canActivate) =>
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
@@ -23,35 +24,29 @@ import {
|
|||||||
} from '../../shared/empty.util';
|
} from '../../shared/empty.util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent creation of a community with an invalid parent community provided
|
* True when either NO parent ID query parameter has been provided, or the parent ID resolves to a valid parent community
|
||||||
* @class CreateCommunityPageGuard
|
* Reroutes to a 404 page when the page cannot be activated
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
export const CreateCommunityPageGuard: CanActivateFn = (
|
||||||
export class CreateCommunityPageGuard {
|
route: ActivatedRouteSnapshot,
|
||||||
public constructor(private router: Router, private communityService: CommunityDataService) {
|
state: RouterStateSnapshot,
|
||||||
|
communityService: CommunityDataService = inject(CommunityDataService),
|
||||||
|
router: Router = inject(Router),
|
||||||
|
): Observable<boolean> => {
|
||||||
|
const parentID = route.queryParams.parent;
|
||||||
|
if (hasNoValue(parentID)) {
|
||||||
|
return observableOf(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return communityService.findById(parentID)
|
||||||
* True when either NO parent ID query parameter has been provided, or the parent ID resolves to a valid parent community
|
.pipe(
|
||||||
* Reroutes to a 404 page when the page cannot be activated
|
getFirstCompletedRemoteData(),
|
||||||
* @method canActivate
|
map((communityRD: RemoteData<Community>) => hasValue(communityRD) && communityRD.hasSucceeded && hasValue(communityRD.payload)),
|
||||||
*/
|
tap((isValid: boolean) => {
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
if (!isValid) {
|
||||||
const parentID = route.queryParams.parent;
|
router.navigate(['/404']);
|
||||||
if (hasNoValue(parentID)) {
|
}
|
||||||
return observableOf(true);
|
},
|
||||||
}
|
),
|
||||||
|
);
|
||||||
return this.communityService.findById(parentID)
|
};
|
||||||
.pipe(
|
|
||||||
getFirstCompletedRemoteData(),
|
|
||||||
map((communityRD: RemoteData<Community>) => hasValue(communityRD) && communityRD.hasSucceeded && hasValue(communityRD.payload)),
|
|
||||||
tap((isValid: boolean) => {
|
|
||||||
if (!isValid) {
|
|
||||||
this.router.navigate(['/404']);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -20,7 +20,7 @@ import { authReducer } from './auth.reducer';
|
|||||||
import { AuthBlockingGuard } from './auth-blocking.guard';
|
import { AuthBlockingGuard } from './auth-blocking.guard';
|
||||||
|
|
||||||
describe('AuthBlockingGuard', () => {
|
describe('AuthBlockingGuard', () => {
|
||||||
let guard: AuthBlockingGuard;
|
let guard: any;
|
||||||
let initialState;
|
let initialState;
|
||||||
let store: Store<AppState>;
|
let store: Store<AppState>;
|
||||||
let mockStore: MockStore<AppState>;
|
let mockStore: MockStore<AppState>;
|
||||||
@@ -52,14 +52,14 @@ describe('AuthBlockingGuard', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
store = TestBed.inject(Store);
|
store = TestBed.inject(Store);
|
||||||
mockStore = store as MockStore<AppState>;
|
mockStore = store as MockStore<AppState>;
|
||||||
guard = new AuthBlockingGuard(store);
|
guard = AuthBlockingGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`canActivate`, () => {
|
describe(`canActivate`, () => {
|
||||||
|
|
||||||
describe(`when authState.blocking is undefined`, () => {
|
describe(`when authState.blocking is undefined`, () => {
|
||||||
it(`should not emit anything`, (done) => {
|
it(`should not emit anything`, (done) => {
|
||||||
expect(guard.canActivate()).toBeObservable(cold('-'));
|
expect(guard(null, null, store)).toBeObservable(cold('-'));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -77,7 +77,7 @@ describe('AuthBlockingGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`should not emit anything`, (done) => {
|
it(`should not emit anything`, (done) => {
|
||||||
expect(guard.canActivate()).toBeObservable(cold('-'));
|
expect(guard(null, null, store)).toBeObservable(cold('-'));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -95,7 +95,7 @@ describe('AuthBlockingGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it(`should succeed`, (done) => {
|
it(`should succeed`, (done) => {
|
||||||
expect(guard.canActivate()).toBeObservable(cold('(a|)', { a: true }));
|
expect(guard(null, null, store)).toBeObservable(cold('(a|)', { a: true }));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
|
import {
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
} from '@angular/router';
|
||||||
import {
|
import {
|
||||||
select,
|
select,
|
||||||
Store,
|
Store,
|
||||||
@@ -19,24 +24,16 @@ import { isAuthenticationBlocking } from './selectors';
|
|||||||
* route until the authentication status has loaded.
|
* route until the authentication status has loaded.
|
||||||
* To ensure all rest requests get the correct auth header.
|
* To ensure all rest requests get the correct auth header.
|
||||||
*/
|
*/
|
||||||
@Injectable({
|
export const AuthBlockingGuard: CanActivateFn = (
|
||||||
providedIn: 'root',
|
route: ActivatedRouteSnapshot,
|
||||||
})
|
state: RouterStateSnapshot,
|
||||||
export class AuthBlockingGuard {
|
store: Store<AppState> = inject(Store<AppState>),
|
||||||
|
): Observable<boolean> => {
|
||||||
|
return store.pipe(select(isAuthenticationBlocking)).pipe(
|
||||||
|
map((isBlocking: boolean) => isBlocking === false),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
filter((finished: boolean) => finished === true),
|
||||||
|
take(1),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
constructor(private store: Store<AppState>) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True when the authentication isn't blocking everything
|
|
||||||
*/
|
|
||||||
canActivate(): Observable<boolean> {
|
|
||||||
return this.store.pipe(select(isAuthenticationBlocking)).pipe(
|
|
||||||
map((isBlocking: boolean) => isBlocking === false),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
filter((finished: boolean) => finished === true),
|
|
||||||
take(1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateChildFn,
|
||||||
|
CanActivateFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
UrlTree,
|
UrlTree,
|
||||||
@@ -16,7 +18,7 @@ import {
|
|||||||
switchMap,
|
switchMap,
|
||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
|
|
||||||
import { CoreState } from '../core-state.model';
|
import { AppState } from '../../app.reducer';
|
||||||
import {
|
import {
|
||||||
AuthService,
|
AuthService,
|
||||||
LOGIN_ROUTE,
|
LOGIN_ROUTE,
|
||||||
@@ -28,49 +30,35 @@ import {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent unauthorized activating and loading of routes
|
* Prevent unauthorized activating and loading of routes
|
||||||
* @class AuthenticatedGuard
|
* True when user is authenticated
|
||||||
|
* UrlTree with redirect to login page when user isn't authenticated
|
||||||
|
* @method canActivate
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
export const AuthenticatedGuard: CanActivateFn = (
|
||||||
export class AuthenticatedGuard {
|
route: ActivatedRouteSnapshot,
|
||||||
|
state: RouterStateSnapshot,
|
||||||
|
authService: AuthService = inject(AuthService),
|
||||||
|
router: Router = inject(Router),
|
||||||
|
store: Store<AppState> = inject(Store<AppState>),
|
||||||
|
): Observable<boolean | UrlTree> => {
|
||||||
|
const url = state.url;
|
||||||
|
// redirect to sign in page if user is not authenticated
|
||||||
|
return store.pipe(select(isAuthenticationLoading)).pipe(
|
||||||
|
find((isLoading: boolean) => isLoading === false),
|
||||||
|
switchMap(() => store.pipe(select(isAuthenticated))),
|
||||||
|
map((authenticated) => {
|
||||||
|
if (authenticated) {
|
||||||
|
return authenticated;
|
||||||
|
} else {
|
||||||
|
authService.setRedirectUrl(url);
|
||||||
|
authService.removeToken();
|
||||||
|
return router.createUrlTree([LOGIN_ROUTE]);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
export const AuthenticatedGuardChild: CanActivateChildFn = (
|
||||||
* @constructor
|
route: ActivatedRouteSnapshot,
|
||||||
*/
|
state: RouterStateSnapshot,
|
||||||
constructor(private authService: AuthService, private router: Router, private store: Store<CoreState>) {}
|
) => AuthenticatedGuard(route, state);
|
||||||
|
|
||||||
/**
|
|
||||||
* True when user is authenticated
|
|
||||||
* UrlTree with redirect to login page when user isn't authenticated
|
|
||||||
* @method canActivate
|
|
||||||
*/
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
|
||||||
const url = state.url;
|
|
||||||
return this.handleAuth(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True when user is authenticated
|
|
||||||
* UrlTree with redirect to login page when user isn't authenticated
|
|
||||||
* @method canActivateChild
|
|
||||||
*/
|
|
||||||
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
|
||||||
return this.canActivate(route, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleAuth(url: string): Observable<boolean | UrlTree> {
|
|
||||||
// redirect to sign in page if user is not authenticated
|
|
||||||
return this.store.pipe(select(isAuthenticationLoading)).pipe(
|
|
||||||
find((isLoading: boolean) => isLoading === false),
|
|
||||||
switchMap(() => this.store.pipe(select(isAuthenticated))),
|
|
||||||
map((authenticated) => {
|
|
||||||
if (authenticated) {
|
|
||||||
return authenticated;
|
|
||||||
} else {
|
|
||||||
this.authService.setRedirectUrl(url);
|
|
||||||
this.authService.removeToken();
|
|
||||||
return this.router.createUrlTree([LOGIN_ROUTE]);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,36 +1,27 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
import { NotifyInfoGuard } from './notify-info.guard';
|
import { NotifyInfoGuard } from './notify-info.guard';
|
||||||
import { NotifyInfoService } from './notify-info.service';
|
|
||||||
|
|
||||||
describe('NotifyInfoGuard', () => {
|
describe('NotifyInfoGuard', () => {
|
||||||
let guard: NotifyInfoGuard;
|
let guard: any;
|
||||||
let notifyInfoServiceSpy: any;
|
let notifyInfoServiceSpy: any;
|
||||||
let router: any;
|
let router: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
notifyInfoServiceSpy = jasmine.createSpyObj('NotifyInfoService', ['isCoarConfigEnabled']);
|
notifyInfoServiceSpy = jasmine.createSpyObj('NotifyInfoService', ['isCoarConfigEnabled']);
|
||||||
router = jasmine.createSpyObj('Router', ['parseUrl']);
|
router = jasmine.createSpyObj('Router', ['parseUrl']);
|
||||||
TestBed.configureTestingModule({
|
guard = NotifyInfoGuard;
|
||||||
providers: [
|
|
||||||
NotifyInfoGuard,
|
|
||||||
{ provide: NotifyInfoService, useValue: notifyInfoServiceSpy },
|
|
||||||
{ provide: Router, useValue: router },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
guard = TestBed.inject(NotifyInfoGuard);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(guard).toBeTruthy();
|
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(true));
|
||||||
|
expect(guard(null, null, notifyInfoServiceSpy, router)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if COAR config is enabled', (done) => {
|
it('should return true if COAR config is enabled', (done) => {
|
||||||
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(true));
|
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(true));
|
||||||
|
|
||||||
guard.canActivate(null, null).subscribe((result) => {
|
guard(null, null, notifyInfoServiceSpy, router).subscribe((result) => {
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -40,7 +31,7 @@ describe('NotifyInfoGuard', () => {
|
|||||||
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(false));
|
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(false));
|
||||||
router.parseUrl.and.returnValue(of('/404'));
|
router.parseUrl.and.returnValue(of('/404'));
|
||||||
|
|
||||||
guard.canActivate(null, null).subscribe(() => {
|
guard(null, null, notifyInfoServiceSpy, router).subscribe(() => {
|
||||||
expect(router.parseUrl).toHaveBeenCalledWith('/404');
|
expect(router.parseUrl).toHaveBeenCalledWith('/404');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
CanActivate,
|
CanActivateFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
UrlTree,
|
UrlTree,
|
||||||
@@ -11,27 +11,13 @@ import { map } from 'rxjs/operators';
|
|||||||
|
|
||||||
import { NotifyInfoService } from './notify-info.service';
|
import { NotifyInfoService } from './notify-info.service';
|
||||||
|
|
||||||
@Injectable({
|
export const NotifyInfoGuard: CanActivateFn = (
|
||||||
providedIn: 'root',
|
route: ActivatedRouteSnapshot,
|
||||||
})
|
state: RouterStateSnapshot,
|
||||||
export class NotifyInfoGuard implements CanActivate {
|
notifyInfoService: NotifyInfoService = inject(NotifyInfoService),
|
||||||
constructor(
|
router: Router = inject(Router),
|
||||||
private notifyInfoService: NotifyInfoService,
|
): Observable<boolean | UrlTree> => {
|
||||||
private router: Router,
|
return notifyInfoService.isCoarConfigEnabled().pipe(
|
||||||
) {}
|
map(isEnabled => isEnabled ? true : router.parseUrl('/404')),
|
||||||
|
);
|
||||||
canActivate(
|
};
|
||||||
route: ActivatedRouteSnapshot,
|
|
||||||
state: RouterStateSnapshot,
|
|
||||||
): Observable<boolean | UrlTree> {
|
|
||||||
return this.notifyInfoService.isCoarConfigEnabled().pipe(
|
|
||||||
map(coarLdnEnabled => {
|
|
||||||
if (coarLdnEnabled) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return this.router.parseUrl('/404');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
UrlTree,
|
UrlTree,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
@@ -10,16 +11,13 @@ import { AuthorizationDataService } from '../data/feature-authorization/authoriz
|
|||||||
import { FeatureID } from '../data/feature-authorization/feature-id';
|
import { FeatureID } from '../data/feature-authorization/feature-id';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An guard for redirecting users to the feedback page if user is authorized
|
* A guard for redirecting users to the feedback page if user is authorized
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
export const FeedbackGuard: CanActivateFn = (
|
||||||
export class FeedbackGuard {
|
route: ActivatedRouteSnapshot,
|
||||||
|
state: RouterStateSnapshot,
|
||||||
|
authorizationService: AuthorizationDataService = inject(AuthorizationDataService),
|
||||||
|
): Observable<boolean | UrlTree> => {
|
||||||
|
return authorizationService.isAuthorized(FeatureID.CanSendFeedback);
|
||||||
|
};
|
||||||
|
|
||||||
constructor(private authorizationService: AuthorizationDataService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
|
|
||||||
return this.authorizationService.isAuthorized(FeatureID.CanSendFeedback);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -5,14 +5,14 @@ import { DefaultAppConfig } from '../../../config/default-app-config';
|
|||||||
import { ReloadGuard } from './reload.guard';
|
import { ReloadGuard } from './reload.guard';
|
||||||
|
|
||||||
describe('ReloadGuard', () => {
|
describe('ReloadGuard', () => {
|
||||||
let guard: ReloadGuard;
|
let guard: any;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
let appConfig: AppConfig;
|
let appConfig: AppConfig;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
router = jasmine.createSpyObj('router', ['parseUrl', 'createUrlTree']);
|
router = jasmine.createSpyObj('router', ['parseUrl', 'createUrlTree']);
|
||||||
appConfig = new DefaultAppConfig();
|
appConfig = new DefaultAppConfig();
|
||||||
guard = new ReloadGuard(router, appConfig);
|
guard = ReloadGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('canActivate', () => {
|
describe('canActivate', () => {
|
||||||
@@ -31,7 +31,7 @@ describe('ReloadGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create a UrlTree with the redirect URL', () => {
|
it('should create a UrlTree with the redirect URL', () => {
|
||||||
guard.canActivate(route, undefined);
|
guard(route, undefined, appConfig, router);
|
||||||
expect(router.parseUrl).toHaveBeenCalledWith(redirectUrl.substring(1));
|
expect(router.parseUrl).toHaveBeenCalledWith(redirectUrl.substring(1));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -44,7 +44,7 @@ describe('ReloadGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create a UrlTree to home', () => {
|
it('should create a UrlTree to home', () => {
|
||||||
guard.canActivate(route, undefined);
|
guard(route, undefined, appConfig, router);
|
||||||
expect(router.createUrlTree).toHaveBeenCalledWith(['home']);
|
expect(router.createUrlTree).toHaveBeenCalledWith(['home']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
import {
|
import { inject } from '@angular/core';
|
||||||
Inject,
|
|
||||||
Injectable,
|
|
||||||
} from '@angular/core';
|
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
UrlTree,
|
UrlTree,
|
||||||
@@ -13,33 +11,25 @@ import {
|
|||||||
APP_CONFIG,
|
APP_CONFIG,
|
||||||
AppConfig,
|
AppConfig,
|
||||||
} from '../../../config/app-config.interface';
|
} from '../../../config/app-config.interface';
|
||||||
|
import { HOME_PAGE_PATH } from '../../app-routing-paths';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard redirecting the user to the URL provided in the route's query params
|
* A guard redirecting the user to the URL provided in the route's query params
|
||||||
* When no redirect url is found, the user is redirected to the homepage
|
* When no redirect url is found, the user is redirected to the homepage
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
export const ReloadGuard: CanActivateFn = (
|
||||||
export class ReloadGuard {
|
route: ActivatedRouteSnapshot,
|
||||||
constructor(
|
state: RouterStateSnapshot,
|
||||||
private router: Router,
|
appConfig: AppConfig = inject(APP_CONFIG),
|
||||||
@Inject(APP_CONFIG) private appConfig: AppConfig,
|
router: Router = inject(Router),
|
||||||
) {
|
): UrlTree => {
|
||||||
|
if (isNotEmpty(route.queryParams.redirect)) {
|
||||||
|
const url = route.queryParams.redirect.startsWith(appConfig.ui.nameSpace)
|
||||||
|
? route.queryParams.redirect.substring(appConfig.ui.nameSpace.length)
|
||||||
|
: route.queryParams.redirect;
|
||||||
|
return router.parseUrl(url);
|
||||||
|
} else {
|
||||||
|
return router.createUrlTree([HOME_PAGE_PATH]);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
/**
|
|
||||||
* Get the UrlTree of the URL to redirect to
|
|
||||||
* @param route
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): UrlTree {
|
|
||||||
if (isNotEmpty(route.queryParams.redirect)) {
|
|
||||||
const url = route.queryParams.redirect.startsWith(this.appConfig.ui.nameSpace)
|
|
||||||
? route.queryParams.redirect.substring(this.appConfig.ui.nameSpace.length)
|
|
||||||
: route.queryParams.redirect;
|
|
||||||
return this.router.parseUrl(url);
|
|
||||||
} else {
|
|
||||||
return this.router.createUrlTree(['home']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -16,7 +16,7 @@ import { ServerCheckGuard } from './server-check.guard';
|
|||||||
import SpyObj = jasmine.SpyObj;
|
import SpyObj = jasmine.SpyObj;
|
||||||
|
|
||||||
describe('ServerCheckGuard', () => {
|
describe('ServerCheckGuard', () => {
|
||||||
let guard: ServerCheckGuard;
|
let guard: any;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
let eventSubject: ReplaySubject<RouterEvent>;
|
let eventSubject: ReplaySubject<RouterEvent>;
|
||||||
let rootDataServiceStub: SpyObj<RootDataService>;
|
let rootDataServiceStub: SpyObj<RootDataService>;
|
||||||
@@ -39,7 +39,7 @@ describe('ServerCheckGuard', () => {
|
|||||||
navigateByUrl: jasmine.createSpy('navigateByUrl'),
|
navigateByUrl: jasmine.createSpy('navigateByUrl'),
|
||||||
parseUrl: jasmine.createSpy('parseUrl').and.returnValue(redirectUrlTree),
|
parseUrl: jasmine.createSpy('parseUrl').and.returnValue(redirectUrlTree),
|
||||||
} as any;
|
} as any;
|
||||||
guard = new ServerCheckGuard(router, rootDataServiceStub);
|
guard = ServerCheckGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
@@ -53,7 +53,7 @@ describe('ServerCheckGuard', () => {
|
|||||||
|
|
||||||
it('should return true', () => {
|
it('should return true', () => {
|
||||||
testScheduler.run(({ expectObservable }) => {
|
testScheduler.run(({ expectObservable }) => {
|
||||||
const result$ = guard.canActivateChild({} as any, {} as any);
|
const result$ = guard({} as any, {} as any, rootDataServiceStub, router);
|
||||||
expectObservable(result$).toBe('(a|)', { a: true });
|
expectObservable(result$).toBe('(a|)', { a: true });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -66,14 +66,14 @@ describe('ServerCheckGuard', () => {
|
|||||||
|
|
||||||
it('should return a UrlTree with the route to the 500 error page', () => {
|
it('should return a UrlTree with the route to the 500 error page', () => {
|
||||||
testScheduler.run(({ expectObservable }) => {
|
testScheduler.run(({ expectObservable }) => {
|
||||||
const result$ = guard.canActivateChild({} as any, {} as any);
|
const result$ = guard({} as any, {} as any, rootDataServiceStub, router);
|
||||||
expectObservable(result$).toBe('(b|)', { b: redirectUrlTree });
|
expectObservable(result$).toBe('(b|)', { b: redirectUrlTree });
|
||||||
});
|
});
|
||||||
expect(router.parseUrl).toHaveBeenCalledWith('/500');
|
expect(router.parseUrl).toHaveBeenCalledWith('/500');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`listenForRouteChanges`, () => {
|
xdescribe(`listenForRouteChanges`, () => {
|
||||||
it(`should invalidate the root cache, when the method is first called`, () => {
|
it(`should invalidate the root cache, when the method is first called`, () => {
|
||||||
testScheduler.run(() => {
|
testScheduler.run(() => {
|
||||||
guard.listenForRouteChanges();
|
guard.listenForRouteChanges();
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
NavigationStart,
|
CanActivateChildFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
UrlTree,
|
UrlTree,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
filter,
|
|
||||||
map,
|
map,
|
||||||
take,
|
take,
|
||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
@@ -16,52 +15,18 @@ import {
|
|||||||
import { getPageInternalServerErrorRoute } from '../../app-routing-paths';
|
import { getPageInternalServerErrorRoute } from '../../app-routing-paths';
|
||||||
import { RootDataService } from '../data/root-data.service';
|
import { RootDataService } from '../data/root-data.service';
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
/**
|
/**
|
||||||
* A guard that checks if root api endpoint is reachable.
|
* A guard that checks if root api endpoint is reachable.
|
||||||
* If not redirect to 500 error page
|
* If not redirect to 500 error page
|
||||||
*/
|
*/
|
||||||
export class ServerCheckGuard {
|
export const ServerCheckGuard: CanActivateChildFn = (
|
||||||
constructor(private router: Router, private rootDataService: RootDataService) {
|
route: ActivatedRouteSnapshot,
|
||||||
}
|
state: RouterStateSnapshot,
|
||||||
|
rootDataService: RootDataService = inject(RootDataService),
|
||||||
/**
|
router: Router = inject(Router),
|
||||||
* True when root api endpoint is reachable.
|
): Observable<boolean | UrlTree> => {
|
||||||
*/
|
return rootDataService.checkServerAvailability().pipe(
|
||||||
canActivateChild(
|
take(1),
|
||||||
route: ActivatedRouteSnapshot,
|
map((isAvailable: boolean) => isAvailable ? true : router.parseUrl(getPageInternalServerErrorRoute())),
|
||||||
state: RouterStateSnapshot,
|
);
|
||||||
): Observable<boolean | UrlTree> {
|
};
|
||||||
|
|
||||||
return this.rootDataService.checkServerAvailability().pipe(
|
|
||||||
take(1),
|
|
||||||
map((isAvailable: boolean) => {
|
|
||||||
if (!isAvailable) {
|
|
||||||
return this.router.parseUrl(getPageInternalServerErrorRoute());
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen to all router events. Every time a new navigation starts, invalidate the cache
|
|
||||||
* for the root endpoint. That way we retrieve it once per routing operation to ensure the
|
|
||||||
* backend is not down. But if the guard is called multiple times during the same routing
|
|
||||||
* operation, the cached version is used.
|
|
||||||
*/
|
|
||||||
listenForRouteChanges(): void {
|
|
||||||
// we'll always be too late for the first NavigationStart event with the router subscribe below,
|
|
||||||
// so this statement is for the very first route operation.
|
|
||||||
this.rootDataService.invalidateRootCache();
|
|
||||||
|
|
||||||
this.router.events.pipe(
|
|
||||||
filter(event => event instanceof NavigationStart),
|
|
||||||
).subscribe(() => {
|
|
||||||
this.rootDataService.invalidateRootCache();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -12,7 +12,7 @@ describe('LookupGuard', () => {
|
|||||||
findByIdAndIDType: jasmine.createSpy('findByIdAndIDType').and.returnValue(observableOf({ hasFailed: false,
|
findByIdAndIDType: jasmine.createSpy('findByIdAndIDType').and.returnValue(observableOf({ hasFailed: false,
|
||||||
hasSucceeded: true })),
|
hasSucceeded: true })),
|
||||||
};
|
};
|
||||||
guard = new LookupGuard(dsoService);
|
guard = LookupGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call findByIdAndIDType with handle params', () => {
|
it('should call findByIdAndIDType with handle params', () => {
|
||||||
@@ -22,7 +22,7 @@ describe('LookupGuard', () => {
|
|||||||
idType: '123456789',
|
idType: '123456789',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
guard.canActivate(scopedRoute as any, undefined);
|
guard(scopedRoute as any, undefined, dsoService);
|
||||||
expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('hdl:123456789/1234', IdentifierType.HANDLE);
|
expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('hdl:123456789/1234', IdentifierType.HANDLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ describe('LookupGuard', () => {
|
|||||||
idType: 'handle',
|
idType: 'handle',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
guard.canActivate(scopedRoute as any, undefined);
|
guard(scopedRoute as any, undefined, dsoService);
|
||||||
expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('hdl:123456789%2F1234', IdentifierType.HANDLE);
|
expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('hdl:123456789%2F1234', IdentifierType.HANDLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ describe('LookupGuard', () => {
|
|||||||
idType: 'uuid',
|
idType: 'uuid',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
guard.canActivate(scopedRoute as any, undefined);
|
guard(scopedRoute as any, undefined, dsoService);
|
||||||
expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('34cfed7c-f597-49ef-9cbe-ea351f0023c2', IdentifierType.UUID);
|
expect(dsoService.findByIdAndIDType).toHaveBeenCalledWith('34cfed7c-f597-49ef-9cbe-ea351f0023c2', IdentifierType.UUID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
@@ -16,44 +17,39 @@ interface LookupParams {
|
|||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable({
|
export const LookupGuard: CanActivateFn = (
|
||||||
providedIn: 'root',
|
route: ActivatedRouteSnapshot,
|
||||||
})
|
state: RouterStateSnapshot,
|
||||||
export class LookupGuard {
|
dsoService: DsoRedirectService = inject(DsoRedirectService),
|
||||||
|
): Observable<boolean> => {
|
||||||
|
const params = getLookupParams(route);
|
||||||
|
return dsoService.findByIdAndIDType(params.id, params.type).pipe(
|
||||||
|
map((response: RemoteData<DSpaceObject>) => response.hasFailed),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
constructor(private dsoService: DsoRedirectService) {
|
function getLookupParams(route: ActivatedRouteSnapshot): LookupParams {
|
||||||
}
|
let type;
|
||||||
|
let id;
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
const idType = route.params.idType;
|
||||||
const params = this.getLookupParams(route);
|
|
||||||
return this.dsoService.findByIdAndIDType(params.id, params.type).pipe(
|
// If the idType is not recognized, assume a legacy handle request (handle/prefix/id)
|
||||||
map((response: RemoteData<DSpaceObject>) => response.hasFailed),
|
if (idType !== IdentifierType.HANDLE && idType !== IdentifierType.UUID) {
|
||||||
);
|
type = IdentifierType.HANDLE;
|
||||||
}
|
const prefix = route.params.idType;
|
||||||
|
const handleId = route.params.id;
|
||||||
private getLookupParams(route: ActivatedRouteSnapshot): LookupParams {
|
id = `hdl:${prefix}/${handleId}`;
|
||||||
let type;
|
|
||||||
let id;
|
} else if (route.params.idType === IdentifierType.HANDLE) {
|
||||||
const idType = route.params.idType;
|
type = IdentifierType.HANDLE;
|
||||||
|
id = 'hdl:' + route.params.id;
|
||||||
// If the idType is not recognized, assume a legacy handle request (handle/prefix/id)
|
|
||||||
if (idType !== IdentifierType.HANDLE && idType !== IdentifierType.UUID) {
|
} else {
|
||||||
type = IdentifierType.HANDLE;
|
type = IdentifierType.UUID;
|
||||||
const prefix = route.params.idType;
|
id = route.params.id;
|
||||||
const handleId = route.params.id;
|
|
||||||
id = `hdl:${prefix}/${handleId}`;
|
|
||||||
|
|
||||||
} else if (route.params.idType === IdentifierType.HANDLE) {
|
|
||||||
type = IdentifierType.HANDLE;
|
|
||||||
id = 'hdl:' + route.params.id;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
type = IdentifierType.UUID;
|
|
||||||
id = route.params.id;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: type,
|
|
||||||
id: id,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
id: id,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
NavigationExtras,
|
NavigationExtras,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
@@ -18,48 +19,38 @@ import { MYDSPACE_ROUTE } from './my-dspace-page.component';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent unauthorized activating and loading of mydspace configuration
|
* Prevent unauthorized activating and loading of mydspace configuration
|
||||||
* @class MyDSpaceGuard
|
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
export const MyDSpaceGuard: CanActivateFn = (
|
||||||
export class MyDSpaceGuard {
|
route: ActivatedRouteSnapshot,
|
||||||
|
state: RouterStateSnapshot,
|
||||||
|
configurationService: MyDSpaceConfigurationService = inject(MyDSpaceConfigurationService),
|
||||||
|
router: Router = inject(Router),
|
||||||
|
): Observable<boolean> => {
|
||||||
|
return configurationService.getAvailableConfigurationTypes().pipe(
|
||||||
|
first(),
|
||||||
|
map((configurationList) => validateConfigurationParam(route.queryParamMap.get('configuration'), configurationList)));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* Check if the given configuration is present in the list of those available
|
||||||
*/
|
*
|
||||||
constructor(private configurationService: MyDSpaceConfigurationService, private router: Router) {
|
* @param configuration
|
||||||
}
|
* the configuration to validate
|
||||||
|
* @param configurationList
|
||||||
|
* the list of available configuration
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function validateConfigurationParam(configuration: string, configurationList: MyDSpaceConfigurationValueType[]): boolean {
|
||||||
|
const configurationDefault: string = configurationList[0];
|
||||||
|
if (isEmpty(configuration) || !configurationList.includes(configuration as MyDSpaceConfigurationValueType)) {
|
||||||
|
// If configuration param is empty or is not included in available configurations redirect to a default configuration value
|
||||||
|
const navigationExtras: NavigationExtras = {
|
||||||
|
queryParams: { configuration: configurationDefault },
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
this.router.navigate([MYDSPACE_ROUTE], navigationExtras);
|
||||||
* True when configuration is valid
|
return false;
|
||||||
* @method canActivate
|
} else {
|
||||||
*/
|
return true;
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
|
||||||
return this.configurationService.getAvailableConfigurationTypes().pipe(
|
|
||||||
first(),
|
|
||||||
map((configurationList) => this.validateConfigurationParam(route.queryParamMap.get('configuration'), configurationList)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given configuration is present in the list of those available
|
|
||||||
*
|
|
||||||
* @param configuration
|
|
||||||
* the configuration to validate
|
|
||||||
* @param configurationList
|
|
||||||
* the list of available configuration
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private validateConfigurationParam(configuration: string, configurationList: MyDSpaceConfigurationValueType[]): boolean {
|
|
||||||
const configurationDefault: string = configurationList[0];
|
|
||||||
if (isEmpty(configuration) || !configurationList.includes(configuration as MyDSpaceConfigurationValueType)) {
|
|
||||||
// If configuration param is empty or is not included in available configurations redirect to a default configuration value
|
|
||||||
const navigationExtras: NavigationExtras = {
|
|
||||||
queryParams: { configuration: configurationDefault },
|
|
||||||
};
|
|
||||||
|
|
||||||
this.router.navigate([MYDSPACE_ROUTE], navigationExtras);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@ import {
|
|||||||
import { RegistrationGuard } from './registration.guard';
|
import { RegistrationGuard } from './registration.guard';
|
||||||
|
|
||||||
describe('RegistrationGuard', () => {
|
describe('RegistrationGuard', () => {
|
||||||
let guard: RegistrationGuard;
|
let guard: any;
|
||||||
|
|
||||||
let epersonRegistrationService: EpersonRegistrationService;
|
let epersonRegistrationService: EpersonRegistrationService;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
@@ -65,7 +65,7 @@ describe('RegistrationGuard', () => {
|
|||||||
setRedirectUrl: {},
|
setRedirectUrl: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
guard = new RegistrationGuard(epersonRegistrationService, router, authService);
|
guard = RegistrationGuard;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('canActivate', () => {
|
describe('canActivate', () => {
|
||||||
@@ -75,21 +75,21 @@ describe('RegistrationGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return true', (done) => {
|
it('should return true', (done) => {
|
||||||
guard.canActivate(route, state).subscribe((result) => {
|
guard(route, state, authService, epersonRegistrationService, router).subscribe((result) => {
|
||||||
expect(result).toEqual(true);
|
expect(result).toEqual(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add the response to the route\'s data', (done) => {
|
it('should add the response to the route\'s data', (done) => {
|
||||||
guard.canActivate(route, state).subscribe(() => {
|
guard(route, state, authService, epersonRegistrationService, router).subscribe(() => {
|
||||||
expect(route.data).toEqual({ ...startingRouteData, registration: registrationRD });
|
expect(route.data).toEqual({ ...startingRouteData, registration: registrationRD });
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not redirect', (done) => {
|
it('should not redirect', (done) => {
|
||||||
guard.canActivate(route, state).subscribe(() => {
|
guard(route, state, authService, epersonRegistrationService, router).subscribe(() => {
|
||||||
expect(router.navigateByUrl).not.toHaveBeenCalled();
|
expect(router.navigateByUrl).not.toHaveBeenCalled();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -102,7 +102,7 @@ describe('RegistrationGuard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect', () => {
|
it('should redirect', () => {
|
||||||
guard.canActivate(route, state).subscribe();
|
guard(route, state, authService, epersonRegistrationService, router).subscribe();
|
||||||
expect(router.navigateByUrl).toHaveBeenCalled();
|
expect(router.navigateByUrl).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
@@ -12,37 +13,25 @@ import { EpersonRegistrationService } from '../core/data/eperson-registration.se
|
|||||||
import { redirectOn4xx } from '../core/shared/authorized.operators';
|
import { redirectOn4xx } from '../core/shared/authorized.operators';
|
||||||
import { getFirstCompletedRemoteData } from '../core/shared/operators';
|
import { getFirstCompletedRemoteData } from '../core/shared/operators';
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
/**
|
/**
|
||||||
* A guard responsible for redirecting to 4xx pages upon retrieving a Registration object
|
* A guard responsible for redirecting to 4xx pages upon retrieving a Registration object
|
||||||
* The guard also adds the resulting RemoteData<Registration> object to the route's data for further usage in components
|
* The guard also adds the resulting RemoteData<Registration> object to the route's data for further usage in components
|
||||||
* The reason this is a guard and not a resolver, is because it has to run before the EndUserAgreementCookieGuard
|
* The reason this is a guard and not a resolver, is because it has to run before the EndUserAgreementCookieGuard
|
||||||
*/
|
*/
|
||||||
export class RegistrationGuard {
|
export const RegistrationGuard: CanActivateFn = (
|
||||||
constructor(private epersonRegistrationService: EpersonRegistrationService,
|
route: ActivatedRouteSnapshot,
|
||||||
private router: Router,
|
state: RouterStateSnapshot,
|
||||||
private authService: AuthService) {
|
authService: AuthService = inject(AuthService),
|
||||||
}
|
epersonRegistrationService: EpersonRegistrationService = inject(EpersonRegistrationService),
|
||||||
|
router: Router = inject(Router),
|
||||||
/**
|
): Observable<boolean> => {
|
||||||
* Can the user activate the route? Returns true if the provided token resolves to an existing Registration, false if
|
const token = route.params.token;
|
||||||
* not. Redirects to 4xx page on 4xx error. Adds the resulting RemoteData<Registration> object to the route's
|
return epersonRegistrationService.searchByToken(token).pipe(
|
||||||
* data.registration property
|
getFirstCompletedRemoteData(),
|
||||||
* @param route
|
redirectOn4xx(router, authService),
|
||||||
* @param state
|
map((rd) => {
|
||||||
*/
|
route.data = { ...route.data, registration: rd };
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
return rd.hasSucceeded;
|
||||||
const token = route.params.token;
|
}),
|
||||||
return this.epersonRegistrationService.searchByToken(token).pipe(
|
);
|
||||||
getFirstCompletedRemoteData(),
|
};
|
||||||
redirectOn4xx(this.router, this.authService),
|
|
||||||
map((rd) => {
|
|
||||||
route.data = { ...route.data, registration: rd };
|
|
||||||
return rd.hasSucceeded;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@@ -1,25 +1,22 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import {
|
import {
|
||||||
ActivatedRouteSnapshot,
|
ActivatedRouteSnapshot,
|
||||||
|
CanActivateFn,
|
||||||
RouterStateSnapshot,
|
RouterStateSnapshot,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
/**
|
/**
|
||||||
* Assemble the correct i18n key for the configuration search page's title depending on the current route's configuration parameter.
|
* Assemble the correct i18n key for the configuration search page's title depending on the current route's configuration parameter.
|
||||||
* The format of the key will be "{configuration}.search.title" with:
|
* The format of the key will be "{configuration}.search.title" with:
|
||||||
* - configuration: The current configuration stored in route.params
|
* - configuration: The current configuration stored in route.params
|
||||||
*/
|
*/
|
||||||
export class ConfigurationSearchPageGuard {
|
export const ConfigurationSearchPageGuard: CanActivateFn = (
|
||||||
canActivate(
|
route: ActivatedRouteSnapshot,
|
||||||
route: ActivatedRouteSnapshot,
|
state: RouterStateSnapshot,
|
||||||
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
|
): boolean => {
|
||||||
const configuration = route.params.configuration;
|
const configuration = route.params.configuration;
|
||||||
|
|
||||||
const newTitle = configuration + '.search.title';
|
const newTitle = `${configuration}.search.title`;
|
||||||
|
|
||||||
route.data = { title: newTitle };
|
route.data = { title: newTitle };
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
@@ -10,6 +10,10 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
TransferState,
|
TransferState,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import {
|
||||||
|
NavigationStart,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import {
|
import {
|
||||||
@@ -30,7 +34,6 @@ import { coreSelector } from '../../app/core/core.selectors';
|
|||||||
import { RootDataService } from '../../app/core/data/root-data.service';
|
import { RootDataService } from '../../app/core/data/root-data.service';
|
||||||
import { LocaleService } from '../../app/core/locale/locale.service';
|
import { LocaleService } from '../../app/core/locale/locale.service';
|
||||||
import { MetadataService } from '../../app/core/metadata/metadata.service';
|
import { MetadataService } from '../../app/core/metadata/metadata.service';
|
||||||
import { ServerCheckGuard } from '../../app/core/server-check/server-check.guard';
|
|
||||||
import { CorrelationIdService } from '../../app/correlation-id/correlation-id.service';
|
import { CorrelationIdService } from '../../app/correlation-id/correlation-id.service';
|
||||||
import { InitService } from '../../app/init.service';
|
import { InitService } from '../../app/init.service';
|
||||||
import { KlaroService } from '../../app/shared/cookies/klaro.service';
|
import { KlaroService } from '../../app/shared/cookies/klaro.service';
|
||||||
@@ -76,7 +79,7 @@ export class BrowserInitService extends InitService {
|
|||||||
protected themeService: ThemeService,
|
protected themeService: ThemeService,
|
||||||
protected menuService: MenuService,
|
protected menuService: MenuService,
|
||||||
private rootDataService: RootDataService,
|
private rootDataService: RootDataService,
|
||||||
protected serverCheckGuard: ServerCheckGuard,
|
protected router: Router,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
store,
|
store,
|
||||||
@@ -198,7 +201,25 @@ export class BrowserInitService extends InitService {
|
|||||||
*/
|
*/
|
||||||
protected initRouteListeners(): void {
|
protected initRouteListeners(): void {
|
||||||
super.initRouteListeners();
|
super.initRouteListeners();
|
||||||
this.serverCheckGuard.listenForRouteChanges();
|
this.listenForRouteChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to all router events. Every time a new navigation starts, invalidate the cache
|
||||||
|
* for the root endpoint. That way we retrieve it once per routing operation to ensure the
|
||||||
|
* backend is not down. But if the guard is called multiple times during the same routing
|
||||||
|
* operation, the cached version is used.
|
||||||
|
*/
|
||||||
|
protected listenForRouteChanges(): void {
|
||||||
|
// we'll always be too late for the first NavigationStart event with the router subscribe below,
|
||||||
|
// so this statement is for the very first route operation.
|
||||||
|
this.rootDataService.invalidateRootCache();
|
||||||
|
|
||||||
|
this.router.events.pipe(
|
||||||
|
filter(event => event instanceof NavigationStart),
|
||||||
|
).subscribe(() => {
|
||||||
|
this.rootDataService.invalidateRootCache();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user