diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index 2548cfece6d..7b1395223c6 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -24,6 +24,13 @@ import { TreeNode } from '../utils/tree-utils'; export class DynamicLayoutComponent implements OnDestroy { layout: Type; + // TODO: Consider a shared enum (eThemeSharedComponents) for known layouts + readonly layouts = new Map([ + ['application', 'Theme.ApplicationLayoutComponent'], + ['account', 'Theme.AccountLayoutComponent'], + ['empty', 'Theme.EmptyLayoutComponent'], + ]); + isLayoutVisible = true; constructor( @@ -36,11 +43,6 @@ export class DynamicLayoutComponent implements OnDestroy { const route = injector.get(ActivatedRoute); const router = injector.get(Router); const routes = injector.get(RoutesService); - const layouts = { - application: this.getComponent('Theme.ApplicationLayoutComponent'), - account: this.getComponent('Theme.AccountLayoutComponent'), - empty: this.getComponent('Theme.EmptyLayoutComponent'), - }; router.events.pipe(takeUntilDestroy(this)).subscribe(event => { if (event instanceof NavigationEnd) { @@ -62,7 +64,8 @@ export class DynamicLayoutComponent implements OnDestroy { if (!expectedLayout) expectedLayout = eLayoutType.empty; - this.layout = layouts[expectedLayout].component; + const key = this.layouts.get(expectedLayout); + this.layout = this.getComponent(key).component; } }); diff --git a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts index 6ba6bd18b50..5de83fef7a5 100644 --- a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts +++ b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts @@ -1,12 +1,11 @@ import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { Store } from '@ngxs/store'; import { Observable, of } from 'rxjs'; import { tap } from 'rxjs/operators'; -import snq from 'snq'; import { RestOccurError } from '../actions/rest.actions'; -import { ConfigState } from '../states/config.state'; import { RoutesService } from '../services/routes.service'; +import { ConfigState } from '../states/config.state'; import { findRoute, getRoutePath } from '../utils/route-utils'; @Injectable({ @@ -15,18 +14,16 @@ import { findRoute, getRoutePath } from '../utils/route-utils'; export class PermissionGuard implements CanActivate { constructor(private router: Router, private routes: RoutesService, private store: Store) {} - canActivate( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot, - ): Observable | boolean { + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { let { requiredPolicy } = route.data || {}; if (!requiredPolicy) { - requiredPolicy = findRoute(this.routes, getRoutePath(this.router, state.url))?.requiredPolicy; - - if (!requiredPolicy) return true; + const route = findRoute(this.routes, getRoutePath(this.router, state.url)); + requiredPolicy = route?.requiredPolicy; } + if (!requiredPolicy) return of(true); + return this.store.select(ConfigState.getGrantedPolicy(requiredPolicy)).pipe( tap(access => { if (!access) { diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts index a995a4c8229..dcfd27ab69f 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts @@ -1,22 +1,57 @@ +import { APP_BASE_HREF } from '@angular/common'; +import { Component } from '@angular/core'; +import { RouterModule } from '@angular/router'; import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; -import { Store } from '@ngxs/store'; +import { Actions, Store } from '@ngxs/store'; import { of } from 'rxjs'; -import { PermissionGuard } from '../guards/permission.guard'; import { RestOccurError } from '../actions'; +import { PermissionGuard } from '../guards/permission.guard'; +import { RoutesService } from '../services/routes.service'; describe('PermissionGuard', () => { let spectator: SpectatorService; let guard: PermissionGuard; + let routes: SpyObject; let store: SpyObject; + @Component({ template: '' }) + class DummyComponent {} + const createService = createServiceFactory({ service: PermissionGuard, mocks: [Store], + declarations: [DummyComponent], + imports: [ + RouterModule.forRoot([ + { + path: 'test', + component: DummyComponent, + data: { + requiredPolicy: 'TestPolicy', + }, + }, + ]), + ], + providers: [ + { + provide: APP_BASE_HREF, + useValue: '/', + }, + { + provide: Actions, + useValue: { + pipe() { + return of(null); + }, + }, + }, + ], }); beforeEach(() => { spectator = createService(); guard = spectator.service; + routes = spectator.inject(RoutesService); store = spectator.get(Store); }); @@ -41,17 +76,32 @@ describe('PermissionGuard', () => { }); }); - it('should find the requiredPolicy from child route', done => { + it('should check the requiredPolicy from RoutesService', done => { + routes.add([ + { + path: '/test', + name: 'Test', + requiredPolicy: 'TestPolicy', + }, + ]); store.select.andReturn(of(false)); const spy = jest.spyOn(store, 'select'); - guard - .canActivate( - { data: {}, routeConfig: { children: [{ path: 'test', data: { requiredPolicy: 'TestPolicy' } }] } } as any, - { url: 'test' } as any, - ) - .subscribe(() => { - expect(spy.mock.calls[0][0]({ auth: { grantedPolicies: { TestPolicy: true } } })).toBe(true); - done(); - }); + guard.canActivate({ data: {} } as any, { url: 'test' } as any).subscribe(() => { + expect(spy.mock.calls[0][0]({ auth: { grantedPolicies: { TestPolicy: true } } })).toBe(true); + done(); + }); + }); + + it('should return Observable if RoutesService does not have requiredPolicy for given URL', done => { + routes.add([ + { + path: '/test', + name: 'Test', + }, + ]); + guard.canActivate({ data: {} } as any, { url: 'test' } as any).subscribe(result => { + expect(result).toBe(true); + done(); + }); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts index cb865787fa4..96bbc197d03 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts @@ -1,10 +1,10 @@ -import { ConfigState } from '@abp/ng.core'; import { createHttpFactory, HttpMethod, SpectatorHttp, SpyObject } from '@ngneat/spectator/jest'; import { NgxsModule, Store } from '@ngxs/store'; import { of, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { Rest } from '../models'; import { RestService } from '../services/rest.service'; +import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens'; describe('HttpClient testing', () => {