standalone permissions

This commit is contained in:
Dan Percic 2023-03-19 13:58:34 +02:00
parent c9c2f3e0f9
commit 1a4e79529b
15 changed files with 54 additions and 59 deletions

21
jest.config.ts Normal file
View File

@ -0,0 +1,21 @@
export default {
displayName: 'common-ui',
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['./setup-jest.ts'],
coverageDirectory: '../../coverage/libs/common-ui',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: './tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};

1
setup-jest.ts Normal file
View File

@ -0,0 +1 @@
import 'jest-preset-angular/setup-jest';

View File

@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, Component, Type } from '@angular/core';
import { IqserPermissionsModule } from '../../index';
import { ComponentFixture, ComponentFixtureAutoDetect, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { IqserPermissionsService } from '../../services/permissions.service';
import { IqserRolesService } from '../../services/roles.service';
import { IqserPermissionsService } from '../services/permissions.service';
import { IqserRolesService } from '../services/roles.service';
import { BehaviorSubject } from 'rxjs';
import { IqserAllowDirective } from './allow.directive';
class BaseTestComponent {
isAuthorized() {}
@ -23,7 +23,7 @@ let isUnauthorizedSpy: jest.SpyInstance;
function configureTestBed(component: Type<BaseTestComponent>) {
TestBed.configureTestingModule({
declarations: [component],
imports: [IqserPermissionsModule.forRoot()],
imports: [IqserAllowDirective],
providers: [{ provide: ComponentFixtureAutoDetect, useValue: true }],
});

View File

@ -1,11 +1,12 @@
import { Directive, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import { Observable } from 'rxjs';
import { List } from '../../../utils';
import { assertTemplate, IqserPermissionsDirective } from '../permissions.directive';
import { List } from '../../utils';
import { assertTemplate, IqserPermissionsDirective } from './permissions.directive';
@Directive({
selector: '[allow]',
standalone: true,
})
export class IqserAllowDirective extends IqserPermissionsDirective implements OnDestroy, OnInit {
/**

View File

@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, Component, Type } from '@angular/core';
import { IqserPermissionsModule } from '../../index';
import { ComponentFixture, ComponentFixtureAutoDetect, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { IqserPermissionsService } from '../../services/permissions.service';
import { IqserRolesService } from '../../services/roles.service';
import { IqserPermissionsService } from '../services/permissions.service';
import { IqserRolesService } from '../services/roles.service';
import { BehaviorSubject } from 'rxjs';
import { IqserDenyDirective } from './deny.directive';
class BaseTestComponent {
isAuthorized() {}
@ -23,7 +23,7 @@ let isUnauthorizedSpy: jest.SpyInstance;
function configureTestBed(component: Type<BaseTestComponent>) {
TestBed.configureTestingModule({
declarations: [component],
imports: [IqserPermissionsModule.forRoot()],
imports: [IqserDenyDirective],
providers: [{ provide: ComponentFixtureAutoDetect, useValue: true }],
});

View File

@ -1,11 +1,12 @@
import { Directive, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import { Observable } from 'rxjs';
import { List } from '../../../utils';
import { assertTemplate, IqserPermissionsDirective } from '../permissions.directive';
import { List } from '../../utils';
import { assertTemplate, IqserPermissionsDirective } from './permissions.directive';
@Directive({
selector: '[deny]',
standalone: true,
})
export class IqserDenyDirective extends IqserPermissionsDirective implements OnDestroy, OnInit {
/**

View File

@ -3,5 +3,4 @@ export * from './services/permissions-guard.service';
export * from './services/permissions.service';
export * from './services/roles.service';
export * from './directives/permissions.directive';
export * from './permissions.module';
export * from './utils';

View File

@ -1,25 +0,0 @@
import { NgModule, Optional } from '@angular/core';
import { IqserAllowDirective } from './directives/allow/allow.directive';
import { IqserPermissionsService } from './services/permissions.service';
import { IqserPermissionsGuard } from './services/permissions-guard.service';
import { IqserRolesService } from './services/roles.service';
import { IqserDenyDirective } from './directives/deny/deny.directive';
@NgModule({
declarations: [IqserAllowDirective, IqserDenyDirective],
exports: [IqserAllowDirective, IqserDenyDirective],
})
export class IqserPermissionsModule {
constructor(@Optional() permissionsService: IqserPermissionsService) {
if (!permissionsService) {
throw new Error('Call forRoot() in AppModule to use IqserPermissionsModule');
}
}
static forRoot() {
return {
ngModule: IqserPermissionsModule,
providers: [IqserPermissionsService, IqserPermissionsGuard, IqserRolesService],
};
}
}

View File

@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { IqserActivatedRouteSnapshot, IqserPermissionsModule } from '..';
import { IqserActivatedRouteSnapshot } from '..';
import { IqserPermissionsService } from './permissions.service';
import { IqserRolesService } from './roles.service';
import { IqserPermissionsGuard } from './permissions-guard.service';
@ -23,7 +23,6 @@ function configureTestBed() {
routerNavigationSpy = jest.spyOn(router, 'navigate');
TestBed.configureTestingModule({
imports: [IqserPermissionsModule.forRoot()],
providers: [
{
provide: Router,

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, Router, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanMatch, Route, Router, RouterStateSnapshot } from '@angular/router';
import { firstValueFrom, from, of } from 'rxjs';
import { first, mergeMap } from 'rxjs/operators';
@ -19,12 +19,14 @@ import { isArray, isFunction, isRedirectWithParameters, isString, transformPermi
import { List } from '../../utils';
export interface IqserPermissionsData {
allow: string | List;
redirectTo?: RedirectTo | RedirectToFn;
readonly allow: string | List;
readonly redirectTo?: RedirectTo | RedirectToFn;
}
@Injectable()
export class IqserPermissionsGuard implements CanActivate, CanLoad, CanActivateChild {
@Injectable({
providedIn: 'root',
})
export class IqserPermissionsGuard implements CanActivate, CanMatch, CanActivateChild {
constructor(
private readonly _permissionsService: IqserPermissionsService,
private readonly _rolesService: IqserRolesService,
@ -39,7 +41,7 @@ export class IqserPermissionsGuard implements CanActivate, CanLoad, CanActivateC
return this.#checkPermissions(childRoute, state);
}
canLoad(route: IqserRoute) {
canMatch(route: IqserRoute) {
return this.#checkPermissions(route);
}

View File

@ -1,5 +1,4 @@
import { TestBed } from '@angular/core/testing';
import { IqserPermissionsModule } from '../permissions.module';
import { IqserPermissionsService } from './permissions.service';
const ADMIN = 'ADMIN' as const;
@ -12,11 +11,7 @@ describe('Permissions Service', () => {
return Object.keys(permissionsService.get()).length;
}
beforeEach(() => {
TestBed.configureTestingModule({
imports: [IqserPermissionsModule.forRoot()],
});
beforeEach(async () => {
permissionsService = TestBed.inject(IqserPermissionsService);
});

View File

@ -7,7 +7,9 @@ import { IqserPermissions, PermissionValidationFn } from '../types';
import { List } from '../../utils';
import { map } from 'rxjs/operators';
@Injectable()
@Injectable({
providedIn: 'root',
})
export class IqserPermissionsService {
readonly permissions$: Observable<IqserPermissions>;
readonly #permissions$ = new BehaviorSubject<IqserPermissions>({});

View File

@ -2,7 +2,6 @@ import { TestBed } from '@angular/core/testing';
import { RoleValidationFn } from '../types';
import { IqserRolesService } from './roles.service';
import { IqserPermissionsService } from './permissions.service';
import { IqserPermissionsModule } from '../permissions.module';
const ADMIN = 'ADMIN' as const;
@ -19,10 +18,6 @@ describe('Roles Service', () => {
}
beforeEach(() => {
TestBed.configureTestingModule({
imports: [IqserPermissionsModule.forRoot()],
});
rolesService = TestBed.inject(IqserRolesService);
permissionsService = TestBed.inject(IqserPermissionsService);
});

View File

@ -6,7 +6,9 @@ import { isArray, isBoolean, isString, toArray } from '../utils';
import { List } from '../../utils';
import { IqserPermissionsService } from './permissions.service';
@Injectable()
@Injectable({
providedIn: 'root',
})
export class IqserRolesService {
readonly roles$: Observable<IqserRoles>;
readonly #roles$ = new BehaviorSubject<IqserRoles>({});

View File

@ -31,12 +31,14 @@ export type PermissionValidationFn = (name: string, store: IqserPermissions) =>
export type IqserActivatedRouteSnapshot = ActivatedRouteSnapshot & {
data?: {
permissions?: IqserPermissionsRouterData;
reuse?: boolean;
};
};
export type IqserRoute = Route & {
data?: {
permissions?: IqserPermissionsRouterData;
reuse?: boolean;
};
children?: List<IqserRoute>;