From 14c4b7e699d044ea5aa69293bb92eaba612420e5 Mon Sep 17 00:00:00 2001 From: Tifenn Guillas Date: Fri, 23 Oct 2020 17:38:08 +0200 Subject: [PATCH 1/4] WIP: Implements navigation guard --- src/app/app-routing.module.ts | 4 ++- src/app/core/navigation.guard.spec.ts | 16 +++++++++ src/app/core/navigation.guard.ts | 49 +++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/app/core/navigation.guard.spec.ts create mode 100644 src/app/core/navigation.guard.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index bf5108c..092135e 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,13 +1,15 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule, PreloadAllModules } from '@angular/router'; +import { NavigationGuard } from './core/navigation.guard'; import { NotFoundPageComponent } from './core/containers/not-found-page.component'; const routes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: 'search', - loadChildren: () => import('./search/search.module').then(m => m.SearchModule) + loadChildren: () => import('./search/search.module').then(m => m.SearchModule), + canLoad: [NavigationGuard] }, { path: 'search-multiple', diff --git a/src/app/core/navigation.guard.spec.ts b/src/app/core/navigation.guard.spec.ts new file mode 100644 index 0000000..ec9c702 --- /dev/null +++ b/src/app/core/navigation.guard.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { NavigationGuard } from './navigation.guard'; + +describe('NavigationGuardGuard', () => { + let guard: NavigationGuard; + + beforeEach(() => { + TestBed.configureTestingModule({}); + guard = TestBed.inject(NavigationGuard); + }); + + it('should be created', () => { + expect(guard).toBeTruthy(); + }); +}); diff --git a/src/app/core/navigation.guard.ts b/src/app/core/navigation.guard.ts new file mode 100644 index 0000000..0a1c731 --- /dev/null +++ b/src/app/core/navigation.guard.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { CanLoad, Route, UrlSegment } from '@angular/router'; + +import { Observable, of } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { Actions } from '@ngrx/effects'; +import { SearchService } from '../search/store/search.service'; +import { ToastrService } from 'ngx-toastr'; +import { Store } from '@ngrx/store'; +import * as fromRouter from '@ngrx/router-store'; +import * as utils from '../shared/utils'; +import * as fromSearch from '../search/store/search.reducer'; +import * as fromMetamodel from '../metamodel/reducers'; +import * as fromConeSearch from '../shared/cone-search/store/cone-search.reducer'; +import { Instance } from '../metamodel/model'; + +@Injectable({ + providedIn: 'root' +}) +export class NavigationGuard implements CanLoad { + constructor(private store$: Store<{ metamodel: fromMetamodel.State }>) { } + + canLoad( + route: Route, + segments: UrlSegment[]): Observable | Promise | boolean { + // console.error(route.path); + switch (route.path) { + case 'search': + console.error(this.isSearchAllowed()); + return this.isSearchAllowed(); + break; + // default: + // return false; + } + } + + waitForDataToLoad(): Observable { + return this.store$.select(state => state.metamodel.instance.instance); + } + + isSearchAllowed(): Observable { + return this.waitForDataToLoad().pipe( + switchMap(instance => { + // console.error(instance.config.search); + return of(instance.config.search); + }) + ) + } +} -- GitLab From 2880adb5a35f9a9df4034dda532feb0339f026d8 Mon Sep 17 00:00:00 2001 From: Tifenn Guillas Date: Tue, 27 Oct 2020 17:42:57 +0100 Subject: [PATCH 2/4] Authorize access when allow access => DONE, WIP: tests --- src/app/app-routing.module.ts | 15 +++-- src/app/core/components/nav.component.spec.ts | 2 +- src/app/core/navigation.guard.spec.ts | 37 ++++++++--- src/app/core/navigation.guard.ts | 62 ++++++++++--------- src/settings/test-data/instance.ts | 2 +- 5 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 092135e..554e95a 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -9,19 +9,26 @@ const routes: Routes = [ { path: 'search', loadChildren: () => import('./search/search.module').then(m => m.SearchModule), - canLoad: [NavigationGuard] + // canLoad: [NavigationGuard] + canActivate: [NavigationGuard] }, { path: 'search-multiple', - loadChildren: () => import('./search-multiple/search-multiple.module').then(m => m.SearchMultipleModule) + loadChildren: () => import('./search-multiple/search-multiple.module').then(m => m.SearchMultipleModule), + // canLoad: [NavigationGuard] + canActivate: [NavigationGuard] }, { path: 'detail/:dname/:objectSelected', - loadChildren: () => import('./detail/detail.module').then(m => m.DetailModule) + loadChildren: () => import('./detail/detail.module').then(m => m.DetailModule), + // canLoad: [NavigationGuard] + canActivate: [NavigationGuard] }, { path: 'documentation', - loadChildren: () => import('./documentation/documentation.module').then(m => m.DocumentationModule) + loadChildren: () => import('./documentation/documentation.module').then(m => m.DocumentationModule), + // canLoad: [NavigationGuard] + canActivate: [NavigationGuard] }, { path: '**', component: NotFoundPageComponent } ]; diff --git a/src/app/core/components/nav.component.spec.ts b/src/app/core/components/nav.component.spec.ts index 125f0ca..de8c2a0 100644 --- a/src/app/core/components/nav.component.spec.ts +++ b/src/app/core/components/nav.component.spec.ts @@ -58,7 +58,7 @@ describe('[Core] Component: NavComponent', () => { const template = fixture.nativeElement; expect(template.querySelector('#search_link')).toBeTruthy(); expect(template.querySelector('#search_multiple_link')).toBeTruthy(); - expect(template.querySelector('#documentation_link')).toBeTruthy(); + expect(template.querySelector('#documentation_link')).toBeNull(); }); it('should not display search, search multiple and documentation links if instance config don\'t allows it', () => { diff --git a/src/app/core/navigation.guard.spec.ts b/src/app/core/navigation.guard.spec.ts index ec9c702..a297add 100644 --- a/src/app/core/navigation.guard.spec.ts +++ b/src/app/core/navigation.guard.spec.ts @@ -1,16 +1,35 @@ import { TestBed } from '@angular/core/testing'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; + import { NavigationGuard } from './navigation.guard'; +import * as fromMetamodel from '../metamodel/reducers'; +import { INSTANCE } from '../../settings/test-data/instance'; + +fdescribe('NavigationGuardGuard', () => { + let guard: NavigationGuard; + let store: MockStore; + const initialState = { metamodel: { + ...fromMetamodel, + instance: { instance: INSTANCE } + } }; -describe('NavigationGuardGuard', () => { - let guard: NavigationGuard; + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + provideMockStore({ initialState }) + ] + }); + guard = TestBed.inject(NavigationGuard); + }); - beforeEach(() => { - TestBed.configureTestingModule({}); - guard = TestBed.inject(NavigationGuard); - }); + it('should be created', () => { + expect(guard).toBeTruthy(); + }); - it('should be created', () => { - expect(guard).toBeTruthy(); - }); + it('#isModuleAllowed() should return if module is allowed or not', () => { + guard.isModuleAllowed('search').subscribe(allowed => expect(allowed).toBeTruthy()); + guard.isModuleAllowed('search-multiple').subscribe(allowed => expect(allowed).toBeTruthy()); + guard.isModuleAllowed('documentation').subscribe(allowed => expect(allowed).toBeFalsy()); + }); }); diff --git a/src/app/core/navigation.guard.ts b/src/app/core/navigation.guard.ts index 0a1c731..8b0dec5 100644 --- a/src/app/core/navigation.guard.ts +++ b/src/app/core/navigation.guard.ts @@ -1,49 +1,51 @@ import { Injectable } from '@angular/core'; -import { CanLoad, Route, UrlSegment } from '@angular/router'; +import { + ActivatedRouteSnapshot, + CanActivate, + CanLoad, + Route, + RouterStateSnapshot, + UrlSegment, + UrlTree +} from '@angular/router'; -import { Observable, of } from 'rxjs'; -import { map, switchMap } from 'rxjs/operators'; -import { Actions } from '@ngrx/effects'; -import { SearchService } from '../search/store/search.service'; -import { ToastrService } from 'ngx-toastr'; import { Store } from '@ngrx/store'; -import * as fromRouter from '@ngrx/router-store'; -import * as utils from '../shared/utils'; -import * as fromSearch from '../search/store/search.reducer'; +import { Observable } from 'rxjs'; +import { filter, map, take } from 'rxjs/operators'; + import * as fromMetamodel from '../metamodel/reducers'; -import * as fromConeSearch from '../shared/cone-search/store/cone-search.reducer'; -import { Instance } from '../metamodel/model'; @Injectable({ providedIn: 'root' }) -export class NavigationGuard implements CanLoad { +export class NavigationGuard implements CanLoad, CanActivate { constructor(private store$: Store<{ metamodel: fromMetamodel.State }>) { } canLoad( route: Route, segments: UrlSegment[]): Observable | Promise | boolean { - // console.error(route.path); - switch (route.path) { - case 'search': - console.error(this.isSearchAllowed()); - return this.isSearchAllowed(); - break; - // default: - // return false; - } + const module: string = route.path; + return this.isModuleAllowed(module).pipe(take(1)); } - waitForDataToLoad(): Observable { - return this.store$.select(state => state.metamodel.instance.instance); + canActivate( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { + const module: string = next.routeConfig.path; + return this.isModuleAllowed(module); } - isSearchAllowed(): Observable { - return this.waitForDataToLoad().pipe( - switchMap(instance => { - // console.error(instance.config.search); - return of(instance.config.search); - }) - ) + isModuleAllowed(module: string): Observable { + return this.store$.select(state => state.metamodel.instance.instance) + .pipe( + filter( instance => instance !== null), + map(instance => { + if (module === 'search-multiple') { + return instance.config.search_multiple.allowed; + } else { + return instance.config[module]; + } + }) + ); } } diff --git a/src/settings/test-data/instance.ts b/src/settings/test-data/instance.ts index a876cec..afb9dd1 100644 --- a/src/settings/test-data/instance.ts +++ b/src/settings/test-data/instance.ts @@ -12,6 +12,6 @@ export const INSTANCE: Instance = { allowed: true, all_datasets_selected: true, }, - documentation: true + documentation: false } }; -- GitLab From 8db00330863f8d093f4226c95293d5183d7338e2 Mon Sep 17 00:00:00 2001 From: Tifenn Guillas Date: Wed, 28 Oct 2020 13:48:47 +0100 Subject: [PATCH 3/4] Tests => DONE --- src/app/app-routing.module.ts | 4 ---- src/app/core/navigation.guard.spec.ts | 7 +++---- src/app/core/navigation.guard.ts | 26 +++++++++----------------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 554e95a..ed133f0 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -9,25 +9,21 @@ const routes: Routes = [ { path: 'search', loadChildren: () => import('./search/search.module').then(m => m.SearchModule), - // canLoad: [NavigationGuard] canActivate: [NavigationGuard] }, { path: 'search-multiple', loadChildren: () => import('./search-multiple/search-multiple.module').then(m => m.SearchMultipleModule), - // canLoad: [NavigationGuard] canActivate: [NavigationGuard] }, { path: 'detail/:dname/:objectSelected', loadChildren: () => import('./detail/detail.module').then(m => m.DetailModule), - // canLoad: [NavigationGuard] canActivate: [NavigationGuard] }, { path: 'documentation', loadChildren: () => import('./documentation/documentation.module').then(m => m.DocumentationModule), - // canLoad: [NavigationGuard] canActivate: [NavigationGuard] }, { path: '**', component: NotFoundPageComponent } diff --git a/src/app/core/navigation.guard.spec.ts b/src/app/core/navigation.guard.spec.ts index a297add..fe70d89 100644 --- a/src/app/core/navigation.guard.spec.ts +++ b/src/app/core/navigation.guard.spec.ts @@ -1,18 +1,17 @@ import { TestBed } from '@angular/core/testing'; -import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { provideMockStore } from '@ngrx/store/testing'; import { NavigationGuard } from './navigation.guard'; import * as fromMetamodel from '../metamodel/reducers'; import { INSTANCE } from '../../settings/test-data/instance'; -fdescribe('NavigationGuardGuard', () => { +describe('[Guard] NavigationGuard', () => { let guard: NavigationGuard; - let store: MockStore; const initialState = { metamodel: { ...fromMetamodel, instance: { instance: INSTANCE } - } }; + }}; beforeEach(() => { TestBed.configureTestingModule({ diff --git a/src/app/core/navigation.guard.ts b/src/app/core/navigation.guard.ts index 8b0dec5..eaae832 100644 --- a/src/app/core/navigation.guard.ts +++ b/src/app/core/navigation.guard.ts @@ -1,32 +1,24 @@ import { Injectable } from '@angular/core'; -import { - ActivatedRouteSnapshot, - CanActivate, - CanLoad, - Route, - RouterStateSnapshot, - UrlSegment, - UrlTree -} from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; -import { filter, map, take } from 'rxjs/operators'; +import { filter, map } from 'rxjs/operators'; import * as fromMetamodel from '../metamodel/reducers'; @Injectable({ providedIn: 'root' }) -export class NavigationGuard implements CanLoad, CanActivate { +export class NavigationGuard implements CanActivate { constructor(private store$: Store<{ metamodel: fromMetamodel.State }>) { } - canLoad( - route: Route, - segments: UrlSegment[]): Observable | Promise | boolean { - const module: string = route.path; - return this.isModuleAllowed(module).pipe(take(1)); - } + // canLoad( + // route: Route, + // segments: UrlSegment[]): Observable | Promise | boolean { + // const module: string = route.path; + // return this.isModuleAllowed(module).pipe(take(1)); + // } canActivate( next: ActivatedRouteSnapshot, -- GitLab From 27c8f8601a623360631e09fe4169d0c262cdee30 Mon Sep 17 00:00:00 2001 From: Tifenn Guillas Date: Wed, 28 Oct 2020 13:50:24 +0100 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc5c408..54bd23d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #138 => Sort attributes and put scrollbar if table too long in Documentation module - #133 => Change typo if only one dataset +### Security +- #127 => Restrict navigation depending on instance configuration + + ## [3.4.0] - 2020-10 ### Added - #132 => Add reset cone search button in search multiple -- GitLab