diff --git a/application/.editorconfig b/.editorconfig similarity index 100% rename from application/.editorconfig rename to .editorconfig diff --git a/.gitignore b/.gitignore index cdb5bf8..5ea3b12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,49 @@ -# Node -node_modules/* -npm-debug.log +# See http://help.github.com/ignore-files/ for more about ignoring files. -# TypeScript -src/*.js -src/*.map -src/*.d.ts +# compiled output +/dist +/tmp +/out-tsc -# JetBrains -.idea +# dependencies +/node_modules + +# IDEs and editors +/.idea .project -.settings -.idea/* -*.iml +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace -# VS Code +# IDE - VSCode .vscode/* -# Windows +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store Thumbs.db Desktop.ini -# Mac -.DS_Store -**/.DS_Store +# JetBrains +.idea +.project +.settings +.idea/* +*.iml # Ngc generated files **/*.ngfactory.ts -# Build files -dist/* # Tests coverage/* \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 489b08c..0000000 --- a/.npmignore +++ /dev/null @@ -1,38 +0,0 @@ -# Node -node_modules/* -npm-debug.log -docs/* -# DO NOT IGNORE TYPESCRIPT FILES FOR NPM -# TypeScript -# *.js -# *.map -# *.d.ts - -# JetBrains -.idea -.project -.settings -.idea/* -*.iml - -# VS Code -.vscode/* - -# Windows -Thumbs.db -Desktop.ini - -# Mac -.DS_Store -**/.DS_Store - -# Ngc generated files -**/*.ngfactory.ts - -# Library files -src/* -build/* -application/* - -# Tests -coverage/* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 9cb7234..c71a95a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js sudo: true node_js: -- '6.11.2' +- '8.11.1' script: npm run test:single diff --git a/.yo-rc.json b/.yo-rc.json deleted file mode 100644 index 9b477f2..0000000 --- a/.yo-rc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "generator-angular2-library": { - "promptValues": { - "gitRepositoryUrl": "https://github.com/AlexKhymenko/ngx-permissions" - } - } -} \ No newline at end of file diff --git a/README.md b/README.md index c15902a..e806274 100644 --- a/README.md +++ b/README.md @@ -1140,6 +1140,54 @@ const appRoutes: Routes = [ ``` ---------------------------- +### Unit Testing of Component ( ByPassing Directive ) + +```typescript +import { Component, OnInit } from '@angular/core'; +import { NgxPermissionsService } from 'ngx-permissions'; +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent implements OnInit { + + title = 'app'; + + constructor(private permissionsService: NgxPermissionsService) {} + + ngOnInit(): void { + const perm = ["ADMIN", "EDITOR"]; + this.permissionsService.loadPermissions(perm); + } +} +``` +```html +
Hey! You can see me.
+
+
+ e2e/src/app.po.ts
+
+ navigateTo + | +
+ navigateTo()
+ |
+
+ Defined in e2e/src/app.po.ts:4
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ getParagraphText + | +
+ getParagraphText()
+ |
+
+ Defined in e2e/src/app.po.ts:8
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
import { browser, by, element } from 'protractor';
+
+export class AppPage {
+ navigateTo() {
+ return browser.get('/');
+ }
+
+ getParagraphText() {
+ return element(by.css('app-root h1')).getText();
+ }
+}
+
+ +
+ projects/ngx-permissions/src/lib/model/permission.model.ts
+
+ constructor(name: string, validationFunction: any)
+ |
+
+ + | +
+ name + | +
+ name: |
+
+ + | +
+ validationFunction + | +
+ validationFunction: |
+
+ + | +
export class NgxPermission {
+ name: string;
+ validationFunction?: Function;
+
+ constructor(name: string, validationFunction: Function) {
+ this.name = name;
+ this.validationFunction = validationFunction;
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/model/role.model.ts
+
+ constructor(name: string, validationFunction: any)
+ |
+
+ + | +
+ name + | +
+ name: |
+
+ + | +
+ validationFunction + | +
+ validationFunction: |
+
+ + | +
export class NgxRole {
+ name: string;
+ validationFunction: Function | string[];
+
+ constructor(name: string, validationFunction: Function | string[]) {
+ this.name = name;
+ this.validationFunction = validationFunction;
+ }
+}
+
+ +
+ projects/ngx-permissions/src/lib/store/roles.store.ts
+
+ Public roles$ + | +
+ roles$: |
+
+ + | +
+ Public rolesSource + | +
+ rolesSource: |
+
+ + | +
import { BehaviorSubject, Observable } from 'rxjs';
+
+export class NgxRolesStore {
+
+ public rolesSource = new BehaviorSubject<{}>({});
+
+ public roles$: Observable<{}> = this.rolesSource.asObservable();
+
+}
+
+ +
+ src/app/app.component.ts
+
+
+ OnInit
+
selector | +app-root |
+
styleUrls | +app.component.css |
+
templateUrl | +./app.component.html |
+
+ constructor(permissionsService: any)
+ |
+
+ Defined in src/app/app.component.ts:10
+ |
+
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ Defined in src/app/app.component.ts:15
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ Public unAuthorized + | +
+
+ unAuthorized()
+ |
+
+ Defined in src/app/app.component.ts:19
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ Public authorized + | +
+
+ authorized()
+ |
+
+ Defined in src/app/app.component.ts:23
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ Public addPermission + | +
+
+ addPermission()
+ |
+
+ Defined in src/app/app.component.ts:27
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
+ title + | +
+ title: |
+
+ Default value : app
+ |
+
+ Defined in src/app/app.component.ts:10
+ |
+
import { Component, OnInit } from '@angular/core';
+import { NgxPermissionsService } from 'ngx-permissions';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit {
+ title = 'app';
+ constructor(private permissionsService: NgxPermissionsService) {
+
+ }
+
+ ngOnInit(): void {
+ this.permissionsService.loadPermissions(['ADMIN']);
+ }
+
+ public unAuthorized() {
+ console.log('unAuthorized');
+ }
+
+ public authorized() {
+ console.log('authorizes');
+ }
+
+ public addPermission() {
+ this.permissionsService.addPermission('CHECK_LOAD');
+ }
+}
+
+ <!--The content below is only a placeholder and can be replaced.-->
+<div style="text-align:center">
+ <h1>
+ Welcome to {{title}}!
+ </h1>
+ <img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo=">
+</div>
+
+
+
+
+
+<br>
+<br>
+<br>
+
+
+
+
+<button *ngxPermissionsOnly="['CHECK_LOAD']">Check Load</button>
+<button *ngxPermissionsOnly="['ADMIN']">Create Users</button>
+
+
+<br>
+<br>
+<br>
+<hr>
+
+
+
+
+
+
+
+<h2>
+ <a routerLink="/home">Only should go Home Page</a>
+</h2>
+<h2>
+ <a routerLink="/home1">Only should not go Home Page</a>
+</h2>
+<h2>
+ <a routerLink="/home3">Except should not go through</a>
+</h2>
+<h2>
+ <a routerLink="/home4">Except should go through</a>
+</h2>
+<h2>
+ <a routerLink="/dynamic/33">Dynamic routes</a>
+</h2>
+
+<a routerLink="/lazy">Lazy module</a>
+<a routerLink="/lazy-isolate">Lazy ISOLATE</a>
+<a routerLink="/lazy-roles-isolate">Lazy ROLES ISOLATE</a>
+<a routerLink="/lazy-roles-async-isolate">Lazy ROLES ASYNC ISOLATE</a>
+
+
+<button (click)="addPermission()">Add load</button>
+<div>
+</div>
+<app-initial-load *ngxPermissionsOnly="['CHECK_LOAD']"></app-initial-load>
+
+<router-outlet></router-outlet>
+
+<div style="background-color: green">
+ I SHOULD SEE it (
+ <ng-template permissions [ngxPermissionsOnly]="['ADMIN']">
+ I SHOULD SEE see it only admin
+ </ng-template>
+</div>
+
+
+<div style="background-color: green">
+ I SHOULD SEE it 2 (
+ <ng-template [ngxPermissionsOnly]="['ADMIN']">
+ I SHOULD SEE see it only admin
+ </ng-template>
+</div>
+
+<div style="background-color: green">
+ <div *ngxPermissionsOnly="['ADMIN']">
+ I SHOULD SEE see it only admin
+ </div>
+</div>
+
+<div style="background-color: green">
+ THis USES BOTH only and except
+
+ <ng-template [ngxPermissionsOnly]="['ADMIN']" [ngxPermissionsExcept]="'HHHH'">
+ Usage on both only and except I SHOULD SEE see it only admin
+ </ng-template>
+</div>
+
+
+<ng-template permissions [ngxPermissionsOnly]="['GUEST']">
+ <div>I will not see it only guest</div>
+</ng-template>
+
+<ng-template permissions [ngxPermissionsExcept]="['ADMINNNN']" (permissionsAuthorized)="authorized()" (permissionsUnauthorized)="unAuthorized()">
+ <div>I will see it except adminnnnnnn</div>
+</ng-template>
+
+<ng-template permissions [ngxPermissionsExcept]="['ADMIN']">
+ <div>I Should not see it except admin gggggggggg87687687687gggggggggg</div>
+</ng-template>
+
+
+<div *ngxPermissionsOnly="['ADMIN']; else a; then a2">
+ <div>Testing templatest</div>
+</div>
+
+<div *ngxPermissionsExcept="['ADMIN']; else a; then a2">
+ <div>Testing templatest234234</div>
+</div>
+
+
+<ng-template #a>
+ else block
+</ng-template>
+<ng-template #a2>
+ then block
+</ng-template>
+ +
+ src/app/home/home.component.ts
+
+
+ OnInit
+
selector | +app-home |
+
styleUrls | +home.component.css |
+
templateUrl | +./home.component.html |
+
+ constructor()
+ |
+
+ Defined in src/app/home/home.component.ts:8
+ |
+
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ Defined in src/app/home/home.component.ts:12
+ |
+
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.css']
+})
+export class HomeComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+}
+
+ <p>
+ home works!
+</p>
+<button routerLink="../">Bank</button>
+
+ +
+ src/app/initial-load/initial-load.component.ts
+
+
+ OnInit
+
selector | +app-initial-load |
+
styleUrls | +initial-load.component.css |
+
templateUrl | +./initial-load.component.html |
+
+ constructor()
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-initial-load',
+ templateUrl: './initial-load.component.html',
+ styleUrls: ['./initial-load.component.css']
+})
+export class InitialLoadComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ console.log('i m loged')
+ }
+
+}
+
+ <p>
+ initial-load works!
+</p>
+
+ +
+ src/app/lazy-isolate/isolate/isolate.component.ts
+
+
+ OnInit
+
selector | +app-isolate |
+
styleUrls | +isolate.component.css |
+
templateUrl | +./isolate.component.html |
+
+ constructor()
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+import { NgxPermissionsService } from 'ngx-permissions';
+import { NgxRolesService } from 'ngx-permissions';
+
+@Component({
+ selector: 'app-isolate',
+ templateUrl: './isolate.component.html',
+ styleUrls: ['./isolate.component.css']
+})
+export class IsolateComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+}
+
+ <p>
+ LAZY Isolate works!
+</p>
+<button routerLink="/">Back</button>
+<button routerLink="/lazy-isolate/except-should">SHOULD go to isolate except should page testing except</button>
+<button routerLink="/lazy-isolate/except-should-not">SHOULD NOT go to isolate except should page testing except</button>
+<button routerLink="/lazy-isolate/only-should">SHOULD go to isolate except should page testing only</button>
+<button routerLink="/lazy-isolate/only-should-not">SHOULD NOT go to only-should-not except should page testing only</button>
+
+<div style="background-color: green">
+ Should see something
+ <ng-template [ngxPermissionsOnly]="['GUEST']">
+ <div> LAZY I will see it only GUEST</div>
+ </ng-template>
+</div>
+
+
+<ng-template [ngxPermissionsOnly]="['ADMIN']">
+ <div style="color: red">LAZY I SHOULD not see it only guest</div>
+</ng-template>
+
+<ng-template [ngxPermissionsExcept]="['GUESTTTT']">
+ <div>LAZY I will see it except guestttt</div>
+</ng-template>
+
+<ng-template [ngxPermissionsExcept]="['GUEST']">
+ <div style="color: red">LAZY I Should not see it except admin</div>
+</ng-template>
+
+
+<div> ENd on lazy ISOLATE Module</div>
+
+ +
+ src/app/lazy-module/lazy-component/lazy-component.component.ts
+
+
+ OnInit
+
selector | +app-lazy-component |
+
styleUrls | +lazy-component.component.css |
+
templateUrl | +./lazy-component.component.html |
+
+ constructor()
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-lazy-component',
+ templateUrl: './lazy-component.component.html',
+ styleUrls: ['./lazy-component.component.css']
+})
+export class LazyComponentComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {
+ }
+
+}
+
+ <h1>
+ Lazy Module Works
+ </h1>
+
+<button routerLink="/">Back</button>
+<button routerLink="/lazy/except-should">SHOULD go to isolate except should page testing except</button>
+<button routerLink="/lazy/except-should-not">SHOULD NOT go to isolate except should page testing except</button>
+<button routerLink="/lazy/only-should">SHOULD go to isolate except should page testing only</button>
+<button routerLink="/lazy/only-should-not">SHOULD NOT go to only-should-not except should page testing only</button>
+
+<ng-template [ngxPermissionsOnly]="['ADMIN']">
+ <div> LAZY I will see it only admin</div>
+</ng-template>
+
+<ng-template [ngxPermissionsOnly]="['GUEST']">
+ <div style="color: red">LAZY I SHOULD not see it only guest</div>
+</ng-template>
+
+<ng-template [ngxPermissionsExcept]="['ADMINNNN']">
+ <div>LAZY I will see it except adminnnnnnn</div>
+</ng-template>
+
+<ng-template [ngxPermissionsExcept]="['ADMIN']">
+ <div style="color: red">LAZY I Should not see it except admin</div>
+</ng-template>
+
+
+<div> ENd on lazy Module</div>
+
+ +
+ src/app/lazy-role-isolate/lazy-role-isolate-test/lazy-role-isolate-test.component.ts
+
+
+ OnInit
+
selector | +app-lazy-role-isolate-test |
+
styleUrls | +lazy-role-isolate-test.component.css |
+
templateUrl | +./lazy-role-isolate-test.component.html |
+
+ constructor(rolesService: any, permissionsService: any, renderer: any, configService: any)
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit, Renderer2, TemplateRef } from '@angular/core';
+import { NgxRolesService, NgxPermissionsConfigurationService, NgxPermissionsService } from 'ngx-permissions';
+
+@Component({
+ selector: 'app-lazy-role-isolate-test',
+ templateUrl: './lazy-role-isolate-test.component.html',
+ styleUrls: ['./lazy-role-isolate-test.component.css']
+})
+export class LazyRoleIsolateTestComponent implements OnInit {
+
+ constructor(private rolesService: NgxRolesService,
+ private permissionsService: NgxPermissionsService,
+ private renderer: Renderer2,
+ private configService: NgxPermissionsConfigurationService) { }
+
+ ngOnInit() {
+ this.configService.addPermissionStrategy('lol', (tf: any) => {
+ this.renderer.setAttribute(tf.elementRef.nativeElement.nextSibling, 'disabled', 'true');
+ });
+
+ this.configService.setDefaultOnUnauthorizedStrategy('lol');
+ this.permissionsService.addPermission('ADMIN')
+ this.rolesService.addRole('ADMIN', ['NICE']);
+ }
+
+}
+
+ <p>
+ LAZY Isolate works!
+</p>
+<button routerLink="/">Back</button>
+<button routerLink="/lazy-roles-isolate/except-should">SHOULD go to isolate except should page testing except</button>
+<button routerLink="/lazy-roles-isolate/except-should-not">SHOULD NOT go to isolate except should page testing except</button>
+<button routerLink="/lazy-roles-isolate/only-should">SHOULD go to isolate except should page testing only</button>
+<button routerLink="/lazy-roles-isolate/only-should-not">SHOULD NOT go to only-should-not except should page testing only</button>
+<button routerLink="/lazy-roles-isolate/only-permissions-should">SHOULD go to only-should-not except should page testing only</button>
+<!--<button routerLink="/lazy-roles-isolate/only-permissions-not-should">SHOULD NOT go to only-should-not except should page testing only</button>-->
+<button routerLink="/lazy-roles-isolate/except-permissions-should-not">SHOULD NOT go to only-should-not except should page testing only</button>
+
+<div style="background-color: green">
+ Should see something
+ <ng-template permissions [ngxPermissionsOnly]="['GUEST']">
+ <div> LAZY I will see it only GUEST</div>
+ </ng-template>
+</div>
+
+
+<ng-template permissions [ngxPermissionsOnly]="['ADMIN']">
+ <div style="color: red">LAZY I SHOULD not see it only guest</div>
+</ng-template>
+
+<ng-template permissions [ngxPermissionsExcept]="['GUESTTTT']">
+ <div>LAZY I will see it except guestttt</div>
+</ng-template>
+
+<ng-template permissions [ngxPermissionsExcept]="['GUEST']">
+ <div style="color: red">LAZY I Should not see it except admin</div>
+</ng-template>
+
+
+<button *ngxPermissionsOnly="'NEVER EXIST'"> SHOULD BE DISABLES</button>
+<button *ngxPermissionsOnly="'ADMIN'"> SHOULD NOt BE DISABLES</button>
+
+
+<div> ENd on lazy ISOLATE Module</div>
+
+ +
+ src/app/lazy-roles-async-isolate/lazy-roles-async-test/lazy-roles-async-test.component.ts
+
+
+ OnInit
+
selector | +app-lazy-roles-async-test |
+
styleUrls | +lazy-roles-async-test.component.css |
+
templateUrl | +./lazy-roles-async-test.component.html |
+
+ constructor(rolesServices: any, asyncTest: any)
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Component, OnInit } from '@angular/core';
+import { NgxRolesService } from 'ngx-permissions';
+import { AsyncTestService } from '../async-test.service';
+
+@Component({
+ selector: 'app-lazy-roles-async-test',
+ templateUrl: './lazy-roles-async-test.component.html',
+ styleUrls: ['./lazy-roles-async-test.component.css']
+})
+export class LazyRolesAsyncTestComponent implements OnInit {
+
+ constructor(private rolesServices: NgxRolesService, private asyncTest: AsyncTestService) { }
+
+ ngOnInit() {
+ this.rolesServices.addRole("ADMIN_TRUE", () => {
+ return true;
+ });
+
+ this.rolesServices.addRole("ADMIN_FALSE", () => {
+ return false;
+ });
+
+ this.rolesServices.addRole("ADMIN_RESOLVE_TRUE", () => {
+ return this.asyncTest.promiseResolveTrue();
+ });
+
+ this.rolesServices.addRole("ADMIN_RESOLVE_FALSE", () => {
+ return this.asyncTest.promiseResolveFalse();
+ });
+
+ this.rolesServices.addRole("ADMIN_REJECT", () => {
+ return this.asyncTest.promiseReject();
+ })
+
+ console.log(this.rolesServices.getRoles());
+ }
+
+}
+
+ <p>
+ LAZY Isolate works!
+</p>
+<button routerLink="/">Back</button>
+<button routerLink="/lazy-roles-isolate/except-should">SHOULD go to isolate except should page testing except</button>
+<button routerLink="/lazy-roles-isolate/except-should-not">SHOULD NOT go to isolate except should page testing except</button>
+<button routerLink="/lazy-roles-isolate/only-should">SHOULD go to isolate except should page testing only</button>
+<button routerLink="/lazy-roles-isolate/only-should-not">SHOULD NOT go to only-should-not except should page testing only</button>
+<button routerLink="/lazy-roles-isolate/only-permissions-should">SHOULD go to only-should-not except should page testing only</button>
+<!--<button routerLink="/lazy-roles-isolate/only-permissions-not-should">SHOULD NOT go to only-should-not except should page testing only</button>-->
+<button routerLink="/lazy-roles-isolate/except-permissions-should-not">SHOULD NOT go to only-should-not except should page testing only</button>
+
+<div style="background-color: green">
+ Should see something
+ <ng-template permissions [ngxPermissionsOnly]="'ADMIN_TRUE'">
+ LAZY I will see it only GUEST
+ </ng-template>
+</div>
+
+
+<div style="background-color: red">
+ <ng-template permissions [ngxPermissionsOnly]="'ADMIN_FALSE'">
+ <div>LAZY I SHOULD not see it only guest</div>
+ </ng-template>
+</div>
+
+<div style="background-color: green">
+ la
+ <ng-template permissions [ngxPermissionsOnly]="'ADMIN_RESOLVE_TRUE'">
+ LAZY I SHOULD not see it ADMIN RESOLVE TRUE guest
+ </ng-template>
+</div>
+
+<div class="background-color: red">
+ <ng-template permissions [ngxPermissionsOnly]="'ADMIN_RESOLVE_FALSE'">
+ <div style="color: red"> I SHOULD NOT SEE RESOLVE FALSE</div>
+ </ng-template>
+</div>
+
+<div style="background-color: red">
+ <ng-template permissions [ngxPermissionsOnly]="'ADMIN_REJECT'">
+ <div>LAZY I Should not see it ADMIN REJECT admin</div>
+ </ng-template>
+</div>
+
+
+<div> ENd on lazy ISOLATE Module</div>
+
+ File | +Type | +Identifier | +Statements | +
---|---|---|---|
+ e2e/src/app.po.ts + | ++ class + | ++ AppPage + | ++ 33 % + (1/3) + | +
+ projects/ngx-permissions/src/lib/index.ts + | ++ interface + | ++ NgxPermissionsModuleConfig + | ++ 25 % + (1/4) + | +
+ projects/ngx-permissions/src/lib/model/permission.model.ts + | ++ class + | ++ NgxPermission + | ++ 25 % + (1/4) + | +
+ projects/ngx-permissions/src/lib/model/permissions-router-data.model.ts + | ++ interface + | ++ NgxPermissionsRouterData + | ++ 25 % + (1/4) + | +
+ projects/ngx-permissions/src/lib/model/role.model.ts + | ++ class + | ++ NgxRole + | ++ 25 % + (1/4) + | +
+ projects/ngx-permissions/src/lib/router/permissions-guard.service.ts + | ++ injectable + | ++ NgxPermissionsGuard + | ++ 0 % + (0/18) + | +
+ projects/ngx-permissions/src/lib/router/permissions-guard.service.ts + | ++ interface + | ++ NgxRedirectToNavigationParameters + | ++ 33 % + (1/3) + | +
+ projects/ngx-permissions/src/lib/service/configuration.service.ts + | ++ injectable + | ++ NgxPermissionsConfigurationService + | ++ 0 % + (0/12) + | +
+ projects/ngx-permissions/src/lib/service/permissions.service.ts + | ++ injectable + | ++ NgxPermissionsService + | ++ 7 % + (1/14) + | +
+ projects/ngx-permissions/src/lib/service/roles.service.ts + | ++ injectable + | ++ NgxRolesService + | ++ 0 % + (0/13) + | +
+ projects/ngx-permissions/src/lib/store/configuration.store.ts + | ++ injectable + | ++ NgxPermissionsConfigurationStore + | ++ 0 % + (0/6) + | +
+ projects/ngx-permissions/src/lib/store/permissions.store.ts + | ++ injectable + | ++ NgxPermissionsStore + | ++ 0 % + (0/4) + | +
+ projects/ngx-permissions/src/lib/store/roles.store.ts + | ++ class + | ++ NgxRolesStore + | ++ 33 % + (1/3) + | +
+ src/app/app.component.ts + | ++ component + | ++ AppComponent + | ++ 0 % + (0/7) + | +
+ src/app/home/home.component.ts + | ++ component + | ++ HomeComponent + | ++ 0 % + (0/3) + | +
+ src/app/initial-load/initial-load.component.ts + | ++ component + | ++ InitialLoadComponent + | ++ 0 % + (0/3) + | +
+ src/app/lazy-isolate/isolate/isolate.component.ts + | ++ component + | ++ IsolateComponent + | ++ 0 % + (0/3) + | +
+ src/app/lazy-module/lazy-component/lazy-component.component.ts + | ++ component + | ++ LazyComponentComponent + | ++ 0 % + (0/3) + | +
+ src/app/lazy-role-isolate/lazy-role-isolate-test/lazy-role-isolate-test.component.ts + | ++ component + | ++ LazyRoleIsolateTestComponent + | ++ 0 % + (0/3) + | +
+ src/app/lazy-roles-async-isolate/async-test.service.ts + | ++ injectable + | ++ AsyncTestService + | ++ 0 % + (0/5) + | +
+ src/app/lazy-roles-async-isolate/lazy-roles-async-test/lazy-roles-async-test.component.ts + | ++ component + | ++ LazyRolesAsyncTestComponent + | ++ 0 % + (0/3) + | +
+
+ projects/ngx-permissions/src/lib/testing/permissions-allow.directive.stub.ts
+
+
+ OnInit
+
selector | +[ngxPermissionsOnly],[ngxPermissionsExcept] |
+
+ ngxPermissionsElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExcept
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnly
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsThen
+ |
+
+
+ Type: |
+
+ + | +
+ permissionsAuthorized
+ |
+
+ $event type: EventEmitter
+
+ |
+
+ + | +
+ permissionsUnauthorized
+ |
+
+ $event type: EventEmitter
+
+ |
+
+ + | +
+ constructor(viewContainer: any, templateRef: any)
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private getAuthorizedTemplate + | +
+
+ getAuthorizedTemplate()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Directive, EventEmitter, Input, OnInit, Output, TemplateRef, ViewContainerRef } from '@angular/core';
+
+@Directive({
+ selector: '[ngxPermissionsOnly],[ngxPermissionsExcept]'
+})
+export class NgxPermissionsAllowStubDirective implements OnInit {
+
+ @Input() ngxPermissionsOnly: string | string[];
+ @Input() ngxPermissionsOnlyThen: TemplateRef<any>;
+ @Input() ngxPermissionsOnlyElse: TemplateRef<any>;
+
+ @Input() ngxPermissionsExcept: string | string[];
+ @Input() ngxPermissionsExceptElse: TemplateRef<any>;
+ @Input() ngxPermissionsExceptThen: TemplateRef<any>;
+
+ @Input() ngxPermissionsThen: TemplateRef<any>;
+ @Input() ngxPermissionsElse: TemplateRef<any>;
+
+ @Output() permissionsAuthorized = new EventEmitter();
+ @Output() permissionsUnauthorized = new EventEmitter();
+
+
+ constructor(private viewContainer: ViewContainerRef,
+ private templateRef: TemplateRef<any>) {}
+
+
+ ngOnInit(): void {
+ this.viewContainer.clear();
+ if (this.getAuthorizedTemplate()) {
+ this.viewContainer.createEmbeddedView(this.getAuthorizedTemplate());
+ }
+ this.permissionsUnauthorized.emit();
+ }
+
+
+ private getAuthorizedTemplate() {
+ return this.ngxPermissionsOnlyThen ||
+ this.ngxPermissionsExceptThen ||
+ this.ngxPermissionsThen ||
+ this.templateRef;
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/directive/permissions.directive.ts
+
+
selector | +[ngxPermissionsOnly],[ngxPermissionsExcept] |
+
+ ngxPermissionsAuthorisedStrategy
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExcept
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptAuthorisedStrategy
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptUnauthorisedStrategy
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnly
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyAuthorisedStrategy
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyUnauthorisedStrategy
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsUnauthorisedStrategy
+ |
+
+
+ Type: |
+
+ + | +
+ permissionsAuthorized
+ |
+
+ $event type: EventEmitter
+
+ |
+
+ + | +
+ permissionsUnauthorized
+ |
+
+ $event type: EventEmitter
+
+ |
+
+ + | +
+ constructor(permissionsService: any, configurationService: any, rolesService: any, viewContainer: any, templateRef: any)
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ ngOnDestroy + | +
+ ngOnDestroy()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private validateExceptOnlyPermissions + | +
+
+ validateExceptOnlyPermissions()
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private validateExceptAndOnlyPermissions + | +
+
+ validateExceptAndOnlyPermissions()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private validateOnlyPermissions + | +
+
+ validateOnlyPermissions()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private handleUnauthorisedPermission + | +
+
+ handleUnauthorisedPermission(template: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private handleAuthorisedPermission + | +
+
+ handleAuthorisedPermission(template: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private showTemplateBlockInView + | +
+
+ showTemplateBlockInView(template: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private getAuthorisedTemplates + | +
+
+ getAuthorisedTemplates()
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private noElseBlockDefined + | +
+
+ noElseBlockDefined()
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
+ Private noThenBlockDefined + | +
+
+ noThenBlockDefined()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private onlyAuthorisedStrategyDefined + | +
+
+ onlyAuthorisedStrategyDefined()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private unauthorisedStrategyDefined + | +
+
+ unauthorisedStrategyDefined()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private applyStrategy + | +
+
+ applyStrategy(str: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private currentAuthorizedState + | +
+ currentAuthorizedState: |
+
+ + | +
+ Private firstMergeUnusedRun + | +
+ firstMergeUnusedRun: |
+
+ Default value : 1
+ |
+
+ + | +
+ Private initPermissionSubscription + | +
+ initPermissionSubscription: |
+
+ + | +
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output, TemplateRef, ViewContainerRef } from '@angular/core';
+import { Subscription, merge } from 'rxjs';
+import { skip } from 'rxjs/operators';
+import { NgxPermissionsPredefinedStrategies } from '../enums/predefined-strategies.enum';
+import { NgxPermissionsConfigurationService, StrategyFunction } from '../service/configuration.service';
+import { NgxPermissionsService } from '../service/permissions.service';
+import { NgxRolesService } from '../service/roles.service';
+import { isBoolean, isFunction, isString, notEmptyValue } from '../utils/utils';
+
+@Directive({
+ selector: '[ngxPermissionsOnly],[ngxPermissionsExcept]'
+})
+export class NgxPermissionsDirective implements OnInit, OnDestroy {
+
+ @Input() ngxPermissionsOnly: string | string[];
+ @Input() ngxPermissionsOnlyThen: TemplateRef<any>;
+ @Input() ngxPermissionsOnlyElse: TemplateRef<any>;
+
+ @Input() ngxPermissionsExcept: string | string[];
+ @Input() ngxPermissionsExceptElse: TemplateRef<any>;
+ @Input() ngxPermissionsExceptThen: TemplateRef<any>;
+
+ @Input() ngxPermissionsThen: TemplateRef<any>;
+ @Input() ngxPermissionsElse: TemplateRef<any>;
+
+ @Input() ngxPermissionsOnlyAuthorisedStrategy: string | StrategyFunction;
+ @Input() ngxPermissionsOnlyUnauthorisedStrategy: string | StrategyFunction;
+
+ @Input() ngxPermissionsExceptUnauthorisedStrategy: string | StrategyFunction;
+ @Input() ngxPermissionsExceptAuthorisedStrategy: string | StrategyFunction;
+
+ @Input() ngxPermissionsUnauthorisedStrategy: string | StrategyFunction;
+ @Input() ngxPermissionsAuthorisedStrategy: string | StrategyFunction;
+
+ @Output() permissionsAuthorized = new EventEmitter();
+ @Output() permissionsUnauthorized = new EventEmitter();
+
+ private initPermissionSubscription: Subscription;
+ // skip first run cause merge will fire twice
+ private firstMergeUnusedRun = 1;
+ private currentAuthorizedState: boolean;
+
+ constructor(
+ private permissionsService: NgxPermissionsService,
+ private configurationService: NgxPermissionsConfigurationService,
+ private rolesService: NgxRolesService,
+ private viewContainer: ViewContainerRef,
+ private templateRef: TemplateRef<any>
+ ) {
+ }
+
+ ngOnInit(): void {
+ this.viewContainer.clear();
+ this.initPermissionSubscription = this.validateExceptOnlyPermissions();
+ }
+
+ ngOnDestroy(): void {
+ if (this.initPermissionSubscription) {
+ this.initPermissionSubscription.unsubscribe();
+ }
+ }
+
+ private validateExceptOnlyPermissions(): Subscription {
+ return merge(this.permissionsService.permissions$, this.rolesService.roles$)
+ .pipe(skip(this.firstMergeUnusedRun))
+ .subscribe(() => {
+ if (notEmptyValue(this.ngxPermissionsExcept)) {
+ return this.validateExceptAndOnlyPermissions();
+ }
+
+ if (notEmptyValue(this.ngxPermissionsOnly)) {
+ return this.validateOnlyPermissions();
+ }
+
+ this.handleAuthorisedPermission(this.getAuthorisedTemplates());
+ });
+ }
+
+ private validateExceptAndOnlyPermissions(): void {
+ Promise.all([ this.permissionsService.hasPermission(this.ngxPermissionsExcept), this.rolesService.hasOnlyRoles(this.ngxPermissionsExcept) ])
+ .then(([ hasPermission, hasRole ]) => {
+ if (hasPermission || hasRole) {
+ this.handleUnauthorisedPermission(this.ngxPermissionsExceptElse || this.ngxPermissionsElse);
+ } else {
+ if (!!this.ngxPermissionsOnly) {
+ throw false;
+ } else {
+ this.handleAuthorisedPermission(this.ngxPermissionsExceptThen || this.ngxPermissionsThen || this.templateRef);
+ }
+ }
+ }).catch(() => {
+ if (!!this.ngxPermissionsOnly) {
+ this.validateOnlyPermissions();
+ } else {
+ this.handleAuthorisedPermission(this.ngxPermissionsExceptThen || this.ngxPermissionsThen || this.templateRef);
+ }
+ });
+ }
+
+ private validateOnlyPermissions(): void {
+ Promise.all([ this.permissionsService.hasPermission(this.ngxPermissionsOnly), this.rolesService.hasOnlyRoles(this.ngxPermissionsOnly) ])
+ .then(([ permissionPr, roles ]) => {
+ if (permissionPr || roles) {
+ this.handleAuthorisedPermission(this.ngxPermissionsOnlyThen || this.ngxPermissionsThen || this.templateRef);
+ } else {
+ this.handleUnauthorisedPermission(this.ngxPermissionsOnlyElse || this.ngxPermissionsElse);
+ }
+ }).catch(() => {
+ this.handleUnauthorisedPermission(this.ngxPermissionsOnlyElse || this.ngxPermissionsElse);
+ });
+ }
+
+ private handleUnauthorisedPermission(template: TemplateRef<any>): void {
+
+ if (!isBoolean(this.currentAuthorizedState) || this.currentAuthorizedState) {
+ this.currentAuthorizedState = false;
+ this.permissionsUnauthorized.emit();
+
+ if (this.unauthorisedStrategyDefined()) {
+ if (isString(this.unauthorisedStrategyDefined())) {
+ this.applyStrategy(this.unauthorisedStrategyDefined());
+ } else if (isFunction(this.unauthorisedStrategyDefined())) {
+ this.showTemplateBlockInView(this.templateRef);
+ (this.unauthorisedStrategyDefined() as Function)(this.templateRef);
+ }
+ return;
+ }
+
+ if (this.configurationService.onUnAuthorisedDefaultStrategy && this.noElseBlockDefined()) {
+ this.applyStrategy(this.configurationService.onUnAuthorisedDefaultStrategy);
+ } else {
+ this.showTemplateBlockInView(template);
+ }
+
+ }
+ }
+
+ private handleAuthorisedPermission(template: TemplateRef<any>): void {
+ if (!isBoolean(this.currentAuthorizedState) || !this.currentAuthorizedState) {
+ this.currentAuthorizedState = true;
+ this.permissionsAuthorized.emit();
+
+ if (this.onlyAuthorisedStrategyDefined()) {
+ if (isString(this.onlyAuthorisedStrategyDefined())) {
+ this.applyStrategy(this.onlyAuthorisedStrategyDefined());
+ } else if (isFunction(this.onlyAuthorisedStrategyDefined())) {
+ this.showTemplateBlockInView(this.templateRef);
+ (this.onlyAuthorisedStrategyDefined() as Function)(this.templateRef);
+ }
+ return;
+ }
+
+ if (this.configurationService.onAuthorisedDefaultStrategy && this.noThenBlockDefined()) {
+ this.applyStrategy(this.configurationService.onAuthorisedDefaultStrategy);
+ } else {
+ this.showTemplateBlockInView(template);
+ }
+ }
+ }
+
+ private showTemplateBlockInView(template: TemplateRef<any>): void {
+ this.viewContainer.clear();
+ if (!template) {
+ return;
+ }
+
+ this.viewContainer.createEmbeddedView(template);
+ }
+
+ private getAuthorisedTemplates(): TemplateRef<any> {
+ return this.ngxPermissionsOnlyThen
+ || this.ngxPermissionsExceptThen
+ || this.ngxPermissionsThen
+ || this.templateRef;
+ }
+
+ private noElseBlockDefined(): boolean {
+ return !this.ngxPermissionsExceptElse || !this.ngxPermissionsElse;
+ }
+
+ private noThenBlockDefined() {
+ return !this.ngxPermissionsExceptThen || !this.ngxPermissionsThen;
+ }
+
+ private onlyAuthorisedStrategyDefined() {
+ return this.ngxPermissionsOnlyAuthorisedStrategy ||
+ this.ngxPermissionsExceptAuthorisedStrategy ||
+ this.ngxPermissionsAuthorisedStrategy;
+ }
+
+ private unauthorisedStrategyDefined() {
+ return this.ngxPermissionsOnlyUnauthorisedStrategy ||
+ this.ngxPermissionsExceptUnauthorisedStrategy ||
+ this.ngxPermissionsUnauthorisedStrategy;
+ }
+
+ private applyStrategy(str: any) {
+ if (str === NgxPermissionsPredefinedStrategies.SHOW) {
+ this.showTemplateBlockInView(this.templateRef);
+ return;
+ }
+
+ if (str === NgxPermissionsPredefinedStrategies.REMOVE) {
+ this.viewContainer.clear();
+ return;
+ }
+ const strategy = this.configurationService.getStrategy(str);
+ this.showTemplateBlockInView(this.templateRef);
+ strategy(this.templateRef);
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/testing/permissions-restrict.directive.stub.ts
+
+
+ OnInit
+
selector | +[ngxPermissionsOnly],[ngxPermissionsExcept] |
+
+ ngxPermissionsElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExcept
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsExceptThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnly
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyElse
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsOnlyThen
+ |
+
+
+ Type: |
+
+ + | +
+ ngxPermissionsThen
+ |
+
+
+ Type: |
+
+ + | +
+ permissionsAuthorized
+ |
+
+ $event type: EventEmitter
+
+ |
+
+ + | +
+ permissionsUnauthorized
+ |
+
+ $event type: EventEmitter
+
+ |
+
+ + | +
+ constructor(viewContainer: any)
+ |
+
+ + | +
+ ngOnInit + | +
+ ngOnInit()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private getUnAuthorizedTemplate + | +
+
+ getUnAuthorizedTemplate()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Directive, EventEmitter, Input, OnInit, Output, TemplateRef, ViewContainerRef } from '@angular/core';
+
+@Directive({
+ selector: '[ngxPermissionsOnly],[ngxPermissionsExcept]'
+})
+export class NgxPermissionsRestrictStubDirective implements OnInit {
+
+ @Input() ngxPermissionsOnly: string | string[];
+ @Input() ngxPermissionsOnlyThen: TemplateRef<any>;
+ @Input() ngxPermissionsOnlyElse: TemplateRef<any>;
+
+ @Input() ngxPermissionsExcept: string | string[];
+ @Input() ngxPermissionsExceptElse: TemplateRef<any>;
+ @Input() ngxPermissionsExceptThen: TemplateRef<any>;
+
+ @Input() ngxPermissionsThen: TemplateRef<any>;
+ @Input() ngxPermissionsElse: TemplateRef<any>;
+
+ @Output() permissionsAuthorized = new EventEmitter();
+ @Output() permissionsUnauthorized = new EventEmitter();
+
+
+ constructor(private viewContainer: ViewContainerRef) {}
+
+
+ ngOnInit(): void {
+ this.viewContainer.clear();
+ if (this.getUnAuthorizedTemplate()) {
+ this.viewContainer.createEmbeddedView(this.getUnAuthorizedTemplate());
+ }
+ this.permissionsUnauthorized.emit();
+ }
+
+
+ private getUnAuthorizedTemplate() {
+ return this.ngxPermissionsOnlyElse ||
+ this.ngxPermissionsExceptElse ||
+ this.ngxPermissionsElse;
+ }
+
+}
+
+ Permission and roles based access control for your angular(angular 2,4,5,6+) applications(AOT, lazy modules compatible)
+##
+ +To see better structured documentation go to wiki-page.
In one month
the detailed functionality description will be available only on wiki page.
You can test library in Plunker
+Some functionality is missing visit wiki-page
+To install this library, run:
+$ npm install ngx-permissions --save
You can import library in any Angular application by running:
+$ npm install ngx-permissions --save
and then from your Angular AppModule
:
import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+
+import { AppComponent } from './app.component';
+
+// Import your library
+import { NgxPermissionsModule } from 'ngx-permissions';
+
+@NgModule({
+ declarations: [
+ AppComponent
+ ],
+ imports: [
+ BrowserModule,
+
+ // Specify your library as an import
+ NgxPermissionsModule.forRoot()
+ ],
+ providers: [],
+ bootstrap: [AppComponent]
+})
+export class AppModule { }
SharedModule
+If you use a SharedModule that you import in multiple other feature modules, you can export the NgxPermissionsModule to make sure you don't have to import it in every module.
+@NgModule({
+ exports: [
+ CommonModule,
+ NgxPermissionsModule
+ ]
+})
+export class SharedModule { }
++Note: Never call a forRoot static method in the SharedModule. You might end up with different instances of the service in your injector tree. But you can use forChild if necessary.
+
When you lazy load a module, you should use the forChild
static method to import the NgxPermissionsModule
.
Since lazy loaded modules use a different injector from the rest of your application, you can configure them separately.
+You can also isolate the service by using permissionsIsolate: true
or rolesIsolate: true
. In which case the service is a completely isolated instance.
+Otherwise, by default, it will share its data with other instances of the service.
@NgModule({
+ imports: [
+ NgxPermissionsModule.forChild()
+ ]
+})
+export class LazyLoadedModule { }
@NgModule({
+ imports: [
+ NgxPermissionsModule.forChild({
+ permissionsIsolate: true,
+ rolesIsolate: true})
+ ]
+})
+export class LazyIsolatedLoadedModule { }
Once your library is imported, you can use its components, directives and pipes in your Angular application:
+Import service to the main application and load permissions
+import { Component, OnInit } from '@angular/core';
+import { NgxPermissionsService } from 'ngx-permissions';
+import { HttpClient } from '@angular/common/http';
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit {
+
+ title = 'app';
+
+ constructor(private permissionsService: NgxPermissionsService,
+ private http: HttpClient) {}
+
+ ngOnInit(): void {
+ const perm = ["ADMIN", "EDITOR"];
+
+ this.permissionsService.loadPermissions(perm);
+
+ this.http.get('url').subscribe((permissions) => {
+ //const perm = ["ADMIN", "EDITOR"]; example of permissions
+ this.permissionsService.loadPermissions(permissions);
+ })
+ }
+}
Usage in templates
+<div *ngxPermissionsOnly="['ADMIN', 'GUEST']">
+ <div>You can see this text congrats</div>
+</div>
+
+<ng-template ngxPermissionsOnly="ADMIN">
+ <div>You can see this text congrats</div>
+ </ng-template>
+
+ <ng-template [ngxPermissionsExcept]="['JOHNY']">
+ <div> All will see it except JOHNY</div>
+ </ng-template>
Let's start with little explanation what permission is. Permission is the most atomic ability that a user can have +in your application. So you can think about permission as a smallest action that user can do inside your site.
+But can user
or anonymous
be a permission? Technically yes, but from business point of view you should treat them
+as Roles that are more complex objects that can store more complex logic.
++:bulb: Note
+
It's a good convention to start permission with a verb and combine them with resource or object, so permissions likereadDocuments
orlistSongs
+are meaningful and easy to understand for other programmes. Notice that they are named lowerCamelCase for easy differentiation form roles.
++:skull: Warning
+
This library is intended for simplify the client side development workflow in a role based web application. DO NOT RELY ONLY ON THIS CHECKS FOR YOU APPLICATION SECURITY! Client side checks can be easily bypassed, so always implement the checks on the backend!
So, how do you tell Permission what does 'readDocuments' or 'listSongs' mean and how to know if the current user belongs +to those definitions?
+Well, Permission allows you to set different 'permissions' definitions along with the logic that determines if the current
+session belongs to them. To do that library exposes special container NgxPermissionsService
that allows you to manipulate them freely.
To add permissions individually NgxPermissionsService
exposes method addPermission
that generic usage is shown below or add as array:
[...]
+ ngOnInit() {
+ this.permissionsService.addPermission('changeSomething')
+ this.permissionsService.addPermission(['changeSomething', 'anotherAlso'])
+ this.permissionsService.addPermission('changeSomething', () => {
+ return true;
+ })
+
+ this.permissionsService.addPermission('anotherPermissions', (permissionName, permissionsObject) => {
+ return !!permissionsObject[permissionName];
+ });
+ this.permissionsService.addPermission(['anotherPermissions', 'AnotherOne'], (permissionName, permissionsObject) => {
+ return !!permissionsObject[permissionName];
+ });
+
+ //Will add validation function to every permission
+ this.permissionsService.addPermission(['anotherPermissions', 'AnotherOne'], (permissionName, permissionsObject) => {
+ return !!permissionsObject[permissionName];
+ });
+
+ this.permissionsService.addPermission('permissions', (permissionName, permissionsObject) => {
+ return this.checkSession().toPromise();
+ });
+ }
+
APP_INITIALIZER is defined in angular/core. You include it in your app.module.ts like this.
+APP_INITIALIZER is an OpaqueToken that references the ApplicationInitStatus service. ApplicationInitStatus is a multi provider. It supports multiple dependencies and you can use it in your providers list multiple times. It is used like this.
+import { APP_INITIALIZER } from '@angular/core';
+
+@NgModule({
+ providers: [
+ DictionaryService,
+ {
+ provide: APP_INITIALIZER,
+ useFactory: (ds: DictionaryService, ps: NgxPermissionsService ) => function() {return ds.load().then((data) => {return ps.loadPermissions(data)})},
+ deps: [LoadService, NgxPermissionsService],
+ multi: true
+ }]
+})
+export class AppModule { }
Validation function are injected with any angular services. There are 2 local injectables available that can be used to implement more complex validation logic.
+Injectable Local | +Description | +
---|---|
permissionName |
+String representing name of checked permission | +
permissionsObject |
+Object of store permissions storing permissions properties | +
It also have to return one of values to properly represent results:
+Validation result | +Returned value | +|
---|---|---|
Valid | +[true \ |
+Promise.resolve() but it should not resolve false ] |
+
Invalid | +[false \ |
+Promise.reject() or Promise.resolve(false) ] |
+
To define multiple permissions method loadPermissions
can be used. The only
+difference from definePermission
is that it accepts Array
of permission names instead of single one.
Often meet example of usage is set of permissions (e.g. received from server after user login) that you will iterate over to +check if permission is valid.
+const permissions = ['listMeeting', 'seeMeeting', 'editMeeting', 'deleteMeeting']
+NgxPermissionsService.loadPermissions(permissions)
+NgxPermissionsService.loadPermissions(permissions, (permissionName, permissionStore) => {
+ return !!permissionStore[permissionName];
+})
NOTE: This method will remove older permissions and pass only new;
+You can easily remove all permissions form the NgxPermissionsService
(e.g. after user logged out or switched profile) by calling:
NgxPermissionsService.flushPermissions();
Alternatively you can use removePermission
to delete defined permissions manually:
NgxPermissionsService.removePermission('user');
And to get all user permissions use method getPermissions
or use Observable permissions$
:
var permissions = NgxPermissionsService.getPermissions();
+
+NgxPermissionsService.permissions$.subscribe((permissions) => {
+ console.log(permissions)
+})
Make sure you are familiar with:
+ +By definition a role is a named set of abilities (permissions) by which a specific group of users is identified.
+So for example USER
or ANONYMOUS
would be roles and not permissions. We can represent our USER
role as a group of permissions that the role should be able to perform. For example: listArticles
, editArticles
and other custom server/browser validated privileges.
++:bulb: Note
+
It's a good convention to name roles with UPPER_CASE, so roles likeACCOUNTANT
orADMIN
are easier to distinguish from permissions.
Similarly to permissions we are gonna use here RolesService
that exposes addRole
allowing to define custom roles used by users in your application.
[...]
+
+NgxRolesService
+ .addRole('ROLE_NAME', ['permissionNameA', 'permissionNameB', 'permissionNameC', ...])
+
+NgxRolesService.addRole('Guest', () => {
+ return this.sessionService.checkSession().toPromise();
+ });
+
+NgxRolesService.addRole('Guest', () => {
+ return true;
+ });
Validation function are injected with any angular services. There are 2 local injectables available that can be used to implement more complex validation logic.
+Parameter | +Description | +
---|---|
roleName |
+String representing name of checked role | +
transitionProperties |
+Array or validation function | +
It also have to return one of values to properly represent results:
+Validation result | +Returned value | +|
---|---|---|
Valid | +[true \ |
+Promise.resolve() but it should not resolve false ] |
+
Invalid | +[false \ |
+Promise.reject() or Promise.resolve(false) ] |
+
++Note: Right now to make request to the backend it only supports promises +Note: If at least one of request fulfils it will show the component
+
Usage of addRole
is very similar to addPermissions
:
NgxRolesService
+ NgxPermission
+ // Library will internally validate if 'listEvents' and 'editEvents' permissions are valid when checking if role is valid
+ .addRole('ADMIN', ['listEvents', 'editEvents']);
+
+NgxRolesService.addRole('Guest', () => {
+ return this.sessionService.checkSession().toPromise();
+ });
+
Service NgxRolesService
allows you define multiple roles with addRoles
method. This method accepts Object
containing keys as a role names and corresponding validators as values.
NgxRolesService
+ // Or use your own function/service to validate role
+ .addRoles({
+ 'USER': ['canReadInvoices'],
+ 'ADMIN': ['canReadInvoices','canEditInvoices','canUploadImages'],
+ 'GUEST': () => {
+ return this.sessionService.checkSessions().toPromise();
+ }
+ });
++:bulb: Note
+
To remove all roles use flushRoles
method:
NgxRolesService.flushRoles();
Alternatively you can use removeRole
to delete defined role manually:
NgxRolesService.removeRole('USER');
To get specific role use method getRole
:
let role = NgxRolesService.getRole('roleName');
And to get all roles form NgxRolesService
use method getRoles
or use Observable roles$
:
let roles = NgxRolesService.getRoles();
+
+NgxRolesService.roles$.subscribe((data) => {
+ console.log(data);
+})
Permission module exposes directive ngxPermissionsOnly
and ngxPermissionsExcept
that can show/hide elements of your application based on set of permissions.
++:fire: Important
+
Else, then syntax is supported.
Note if you usethen
block don't put anything in main block it will be not visible, onlythen
block will be used.
Permission directive accepts several attributes:
+Attribute | +Value | +Description | +
---|---|---|
ngxPermissionsOnly |
+[String | String[]] |
+Single or multiple permissions allowed to access content | +
ngxPermissionsExcept |
+[String | String[]] |
+Single or multiple permissions denied to access content | +
(permissionsAuthorized) |
+EventEmitter | +EventEmitter emitted when authorized | +
(permissionsUnauthorized) |
+EventEmitter | +EventEmitter emitted when unAuthorized | +
Directives accepts either single permission that has to be met in order to display it's content,
+You can use both ngxPermissionsOnly
and ngxPermissionsExcept
at the same time:
<ng-template [ngxPermissionsOnly]="['ADMIN']" (permissionsAuthorized)="yourCustomAuthorizedFunction()" (permissionsUnauthorized)="yourCustomAuthorizedFunction()">
+ <div>You can see this text congrats</div>
+ </ng-template>
+ <ng-template [ngxPermissionsOnly]="'ADMIN'" [ngxPermissionsExcept]="'Manager'">
+ <div>You can see this text congrats</div>
+ </ng-template>
+ <ng-template ngxPermissionsOnly="ADMIN">
+ <div>You can see this text congrats</div>
+ </ng-template>
+
+ <ng-template [ngxPermissionsExcept]="['JOHNY']">
+ <div> All will see it except JOHNY</div>
+ </ng-template>
Or set of permissions separated by 'coma':
+<ng-template [ngxPermissionsOnly]="['ADMIN', 'GUEST']">
+ <div>You can see this text congrats</div>
+</ng-template>
+
+ <ng-template [ngxPermissionsExcept]="['ADMIN', 'JOHNY']">
+ <div>All will see it except admin and Johny</div>
+ </ng-template>
+ <ng-template [ngxPermissionsExcept]="['ADMIN', 'JOHNY']" [ngxPermissionsOnly]="['MANAGER']">
+ <div>All will see it except admin and Johny</div>
+ </ng-template>
+
+ <ng-template [ngxPermissionsExcept]="['MANAGER']"
+ [ngxPermissionExceptThen]="thenBlock"
+ [ngxPermissionExceptElse]="elseBlock">
+ </ng-template>
+ <ng-template #elseBlock>
+ <div>elseBlock</div>
+ </ng-template>
+ <ng-template #thenBlock>
+ <div>thenBlock</div>
+ </ng-template>
+
+ <ng-template
+ [ngxPermissionsOnly]="['MANAGER']"
+ [ngxPermissionsOnlyThen]="thenBlock"
+ [ngxPermissionsOnlyElse]="elseBlock">
+ </ng-template>
+ <ng-template #elseBlock>
+ <div>elseBlock</div>
+ </ng-template>
+ <ng-template #thenBlock>
+ <div>thenBlock</div>
+ </ng-template>
+
+
+
Or just simply by *
+<div *ngxPermissionsOnly="['ADMIN', 'GUEST']">
+ <div>You can see this text congrats</div>
+</div>
+
+ <div *ngxPermissionsOnly="['THEN_BLOCK']; else elseBlock; then thenBlock">main</div>
+ <ng-template #elseBlock>
+ <div>elseBlock</div>
+ </ng-template>
+ <ng-template #thenBlock>
+ <div>thenBlock</div>
+ </ng-template>
+
+ <div *ngxPermissionsExcept="['THEN_BLOCK']; else elseBlock; then thenBlock"></div>
+ <ng-template #elseBlock>
+ <div>elseBlock</div>
+ </ng-template>
+ <ng-template #thenBlock>
+ <div>thenBlock</div>
+ </ng-template>
+
++Note: You cant use
*
style with other style directives like `ngIf. You should wrap them. And YES i don't like it either. + ``
html ++++ You can see this text congrats ++
> :fire: **Important**
+ > Using with except and only `together` should use `ngxPermissionsElse` or `ngxPermissionsThen`
+ ```html
+ <ng-template [ngxPermissionsExcept]="'FAIL_BLOCK'"
+ [ngxPermissionsOnly]="'ONLY_BLOCK'"
+ [ngxPermissionsElse]="elseBlock"
+ [ngxPermissionsThen]="thenBlock">
+
+ </ng-template>
+ <ng-template #elseBlock>
+ <div>elseBlock</div>
+ </ng-template>
+ <ng-template #thenBlock>
+ <div>thenBlock</div>
+ </ng-template>
Now you are ready to start working with controlling access to the states of your application. In order to restrict any state ngx-permission rely on angular-route's data
property, reserving key permissions
allowing to define authorization configuration.
Permissions object accepts following properties:
+Property | +Accepted value | +||
---|---|---|---|
only |
+[String \ |
+Array \ |
+Function ] |
+
except |
+[String \ |
+Array \ |
+Function ] |
+
redirectTo |
+[String ] |
+
Property only
:
String
contains single permission or roleArray
contains set of permissions and/or rolesProperty except
:
String
contains single permission or roleArray
contains set of permissions and/or roles++:fire: Important
+
If you combine bothonly
andexcept
properties you have to make sure they are not excluding each other, because denied roles/permissions would not allow access the state for users even if allowed ones would pass them.
In simplest cases you allow users having single role permission to access the state. To achieve that you can pass as String
desired role/permission to only/except property:
+You can use except
and only
at the same time;
import { RouterModule, Routes } from '@angular/router';
+import { NgModule } from '@angular/core';
+import { HomeComponent } from './home/home.component';
+import { NgxPermissionsGuard } from 'ngx-permissions';
+
+const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: 'ADMIN'
+ }
+ }
+ },
+];
+@NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class AppRoutingModule {}
+
In given case when user is trying to access home
state NgxPermissionsGuard
service is called checking if isAuthorized
permission is valid:
Often several permissions/roles are sufficient to allow/deny user to access the state. Then array value comes in handy:
+import { RouterModule, Routes } from '@angular/router';
+import { NgModule } from '@angular/core';
+import { HomeComponent } from './home/home.component';
+import { NgxPermissionsGuard } from 'ngx-permissions';
+
+const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['ADMIN', 'MODERATOR'],
+ except: ['GUEST']
+ }
+ }
+ },
+];
+@NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class AppRoutingModule {}
When NgxPermissionsGuard
service will be called it would expect user to have either ADMIN
or MODERATOR
permissions to pass him to home
route.
You can find states that would require to verify access dynamically - often depending on parameters.
+Let's imagine situation where user want to modify the invoice. We need to check every time if he is allowed to do that on state level. We are gonna use ActivatedRouteSnapshot
and RouterStateSnapshot
object to check weather he is able to do that.
++To make AOT compatible you should export function. +Below is presented code AOT Compatible
+
AOT compatible
+export function testPermissions(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
+ if (route.params['id'] === 42) {
+ return ['MANAGER', "UTILS"]
+ } else {
+ return 'ADMIN'
+ }
+}
+const appRoutes: Routes = [
+ { path: 'dynamic/:id',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: testPermissions
+ }
+ }
+ }
+];
++:skull: Warning
+
Below is presented code not AOT compatible
const appRoutes: Routes = [
+ { path: 'dynamic/:id',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
+ if (route.params['id'] === 42) {
+ return ['MANAGER', "UTILS"]
+ } else {
+ return 'ADMIN'
+ }
+ }
+ }
+ }
+ }
+];
So whenever we try access state with param id = 42
set to true additional check for permission manager and utils
will be made. Otherwise only ADMIN
will be required.
++:fire: Important
+
Notice that function require to always return array or string of roles/permissions in order to work properly.
Property redirectTo:
+String
defines single redirection ruleObjects
defines single/multiple redirection rulesFunction
defines dynamic redirection rule(s)In case you want to redirect to some specific state when user is not authorized pass to redirectTo
path of that route.
import { RouterModule, Routes } from '@angular/router';
+import { NgModule } from '@angular/core';
+import { HomeComponent } from './home/home.component';
+import { NgxPermissionsGuard } from 'ngx-permissions';
+
+const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['ADMIN', 'MODERATOR'],
+ redirectTo: '/another-route'
+ }
+ }
+ },
+];
+@NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class AppRoutingModule {}
In order to pass additional properties like params use pass redirectTo
as object.
+navigationCommands
and navigationExtras
are reserved words it corresponds to parameters passed to router.navigate function
+navigate(commands: any[], extras: NavigationExtras): Promise<boolean>
+const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['ADMIN', 'MODERATOR'],
+ redirectTo: {
+ navigationCommands: ['123'],
+ navigationExtras: {
+ skipLocationChange: true
+ }
+ }
+ }
+ },
+];
+@NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+`
In some situation you want to redirect user based on denied permission/role to create redirection strategies. In order to do that you have to create redirection Object
that contain keys representing rejected permissions or roles and values implementing redirection rules.
Redirection rules are represented by following values:
+Value type | +Return | +Usage | +|
---|---|---|---|
String |
+[String ] |
+Simple state transitions | +|
Object |
+[Object ] |
+Redirection with custom parameters or options | +|
Function |
+[String \ |
+Object ] |
+Dynamic properties-based redirection | +
++:bulb: Note
+
Use default property that will handle fallback redirect for not defined permissions.
The simplest example of multiple redirection rules are redirection based on pairs role/permission and state. When user is not granted to access the state will be redirected to agendaList
if missing canReadAgenda
permission or to dashboard
when missing canEditAgenda
. Property default
is reserved for cases when you want handle specific cases leaving default redirection.
const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['canReadAgenda','canEditAgenda'],
+ redirectTo: {
+ canReadAgenda: 'agendaList',
+ canEditAgenda: 'dashboard',
+ default: 'login'
+ }
+ }
+ }
+ },
+ ];
+ @NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+ })
If you need more control over redirection parameters Object
as a value can be used to customise target url navigationCommands
and transition navigationExtras
.
++:bulb: Note
+navigationCommands
andnavigationExtras
are reserved words it corresponds to parameters passed to router.navigate function +navigate(commands: any[], extras: NavigationExtras): Promise<boolean>
+ const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['canEditAgenda'],
+ redirectTo:
+ canEditAgenda: {
+ navigationCommands: 'dashboard',
+ navigationExtras: {
+ skipLocationChange: true
+ }
+
+ },
+ default: 'login'
+ }
+ }
+ }
+ },
+ ];
+ @NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+ })
To present usage redirectTo
as Object
with values as Function
in a state definition agenda
presented below redirection rules are interpreted as:
canReadAgenda
invoked function returns string representing the state name to which unauthorized user will be redirectedcanEditAgenda
invoked function returns object with custom options and params that will be passed along to transited dashboard
url
+ const appRoutes: Routes = [
+ { path: 'home',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['canReadAgenda','canEditAgenda'],
+ redirectTo: {
+ canReadAgenda: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
+ return 'dashboard';
+ },
+ canEditAgenda: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
+ return {
+ navigationCommands: ['/dashboard'],
+ navigationExtras: {
+ skipLocationChange: true
+ }
+ }
+ },
+ default: 'login'
+ }
+ }
+ }
+ },
+ ];
+ @NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+ })
++:fire: Important
+
Above code is not AOT compatible to make it AOT compatible extract it to function +navigationCommands
andnavigationExtras
reserved words. Matching parameter to router.navigate function
export function canReadAgenda(rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routeStateSnapshot: RouterStateSnapshot) => {
+ return 'dashboard';
+},
+
+redirectTo: {
+ canReadAgenda: canReadAgenda
+
+}
Similarly to examples showing defining dynamic access to state redirection can also be defined based on any parameters of ActivatedRouteSnapshot
and RouterStateSnapshot
;
++:bulb: Note
+
Remember to always return from function state name or object.
const appRoutes: Routes = [
+ { path: 'home/:isEditable',
+ component: HomeComponent,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['canReadAgenda','canEditAgenda'],
+ redirectTo: (rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routerStateSnapshot: RouterStateSnapshot) => {
+ if(activateRouteSnapshot.params['id'] === 42){
+ return 'login';
+ } else {
+ return 'dashboard'
+ }
+ }
+ }
+ },
+ ];
+ @NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+ })
++:fire: Important
+
Above code is not AOT compatible to make it AOT compatible extract it to function
export function redirectToFunc(rejectedPermissionName: string, activateRouteSnapshot: ActivatedRouteSnapshot, routerStateSnapshot: RouterStateSnapshot) => {
+ if(activateRouteSnapshot.params['id'] === 42){
+ return 'login';
+ } else {
+ return 'dashboard'
+ }
+ }
+
+redirectTo: redirectToFunc
NgxPermissionsGuard implements CanActivate interface for examples you can see above
+NgxPermissionsGuard implements CanLoad Interface. Functionality is the same as with canActivate
+const appRoutes: Routes = [
+
+ {
+ path: 'lazy',
+ data: {
+ permissions: {
+ except: 'ADDDMIN',
+ }
+ },
+ canLoad: [NgxPermissionsGuard],
+ loadChildren: 'app/lazy-module/lazy-module.module#LazyModule'
+ },
+
+
+];
+@NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ],
+ providers: [
+ // CanDeactivateGuard
+ ]
+})
+export class AppRoutingModule {}
+
+
+
++:fire: Warning
++
+- The only difference if you use as a function the parameter is only 1 and its type of Route
+
+{
+ path: 'lazy',
+ data: {
+ permissions: {
+ only: (route: Route) => {
+ //logic here
+ return ['MANAGER', "UTILS"]
+ }
+ }
+ },
+ canLoad: [NgxPermissionsGuard],
+ loadChildren: 'app/lazy-module/lazy-module.module#LazyModule'
+ },
NgxPermissionsGuard implements CanLoad Interface. Functionality is the same as with canActivate
+++:fire: Warning
++
+- Need to remember that rules and data you should specify on Child Components not on parent component
+
const appRoutes: Routes = [
+ { path: '',
+ component: IsolateComponent,
+ canActivateChild: [NgxPermissionsGuard],
+ children: [
+ {
+ path: 'except-should',
+ component: AnotherComponent,
+ data: {
+ permissions: {
+ except: 'ADMIN'
+ }
+ }
+ },
+ {
+ path: 'only-should',
+ component: ComeComponent,
+ data: {
+ permissions: {
+ only: 'GUEST'
+ }
+ }
+ },
+ ]
+ },
+];
This method only works with angular 4.3.2
or higher see https://github.com/angular/angular/issues/15670
There are a lot of times you have 2 guard one for authorisation when it makes request for permissions and second is permissions guard +and you want them to work in chain. To make them work in chain You should use them next
+
+let routes = [
+ { path: '',
+ canActivate: [AuthGuard],
+ children: [
+ {path: 'component',
+ component: ComponentName,
+ canActivate: [NgxPermissionsGuard],
+ data: {
+ permissions: {
+ only: ['ADMIN', 'MODERATOR'],
+ redirectTo: 'another-route'
+ }
+ }}
+ ]
+ }
+]
++Note: Make sure the permission request in chained in auth guard +
+`
js + canActivate() { + return authLogin().then((obj) => { + // or load here if you dont need second request + // this.permissions.service.loadPermissions(obj.permissions)
return this.authPermissions.getPermissions('url');
+ }).then((permissions) => {
+ this.permissions.service.loadPermissions(permissions)
+ )
+}
`
| --- |
+This project was generated with Angular CLI version 6.0.0.
+Run ng serve
for a dev server. Navigate to http://localhost:4200/
. The app will automatically reload if you change any of the source files.
Run ng build
to build the project. The build artifacts will be stored in the dist/
directory. Use the --prod
flag for a production build.
Run ng test
to execute the unit tests via Karma.
Run ng e2e
to execute the end-to-end tests via Protractor.
Thank You for using the library and support. HAVE A GREAT DAY!
angular 2 permissions, angular 4 permissions, angular permissions, angular 5 permissions ng2 permissions ng permissions +ng-permissions ng2-permissions angular2 permissions angular4 permissions angular 5 permissions
+MIT © Oleksandr Khymenko
+ + + + + + + + + + + + ++
+ src/app/lazy-roles-async-isolate/async-test.service.ts
+
+ constructor()
+ |
+
+ + | +
+ Public promiseResolveTrue + | +
+
+ promiseResolveTrue()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public promiseResolveFalse + | +
+
+ promiseResolveFalse()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public promiseReject + | +
+
+ promiseReject()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Injectable } from '@angular/core';
+
+@Injectable()
+export class AsyncTestService {
+
+ constructor() { }
+
+
+ public promiseResolveTrue() {
+ return Promise.resolve(true);
+ }
+
+ public promiseResolveFalse() {
+ return Promise.resolve(false);
+ }
+
+ public promiseReject() {
+ return <any>Promise.reject(() => {
+
+ });
+ }
+}
+
+ +
+ projects/ngx-permissions/src/lib/service/configuration.service.ts
+
+ constructor(isolate: boolean, configurationStore: any)
+ |
+
+ + | +
+ Public setDefaultOnAuthorizedStrategy + | +
+
+ setDefaultOnAuthorizedStrategy(name: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public setDefaultOnUnauthorizedStrategy + | +
+
+ setDefaultOnUnauthorizedStrategy(name: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public addPermissionStrategy + | +
+
+ addPermissionStrategy(key: string, func: StrategyFunction)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public getStrategy + | +
+
+ getStrategy(key: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public getAllStrategies + | +
+
+ getAllStrategies()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private predefinedStrategy + | +
+
+ predefinedStrategy(strategy: string)
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
+ Public onAuthorisedDefaultStrategy + | +
+ onAuthorisedDefaultStrategy: |
+
+ + | +
+ Public onUnAuthorisedDefaultStrategy + | +
+ onUnAuthorisedDefaultStrategy: |
+
+ + | +
+ Public strategies$ + | +
+ strategies$: |
+
+ + | +
+ Private strategiesSource + | +
+ strategiesSource: |
+
+ + | +
import { Inject, Injectable, InjectionToken, TemplateRef } from '@angular/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { NgxPermissionsPredefinedStrategies } from '../enums/predefined-strategies.enum';
+import { NgxPermissionsConfigurationStore } from '../store/configuration.store';
+
+export type StrategyFunction = (templateRef?: TemplateRef<any>) => void;
+
+export type Strategy = {
+ [ key: string ]: StrategyFunction
+};
+
+export const USE_CONFIGURATION_STORE = new InjectionToken('USE_CONFIGURATION_STORE');
+
+@Injectable()
+export class NgxPermissionsConfigurationService {
+
+ private strategiesSource: BehaviorSubject<Strategy>;
+ public strategies$: Observable<Strategy>;
+ public onAuthorisedDefaultStrategy: string | undefined;
+ public onUnAuthorisedDefaultStrategy: string | undefined;
+
+ constructor(
+ @Inject(USE_CONFIGURATION_STORE) private isolate: boolean = false,
+ private configurationStore: NgxPermissionsConfigurationStore
+ ) {
+ this.strategiesSource = this.isolate ? new BehaviorSubject<Strategy>({}) : this.configurationStore.strategiesSource;
+ this.strategies$ = this.strategiesSource.asObservable();
+
+ this.onAuthorisedDefaultStrategy = this.isolate ? undefined : this.configurationStore.onAuthorisedDefaultStrategy;
+ this.onUnAuthorisedDefaultStrategy = this.isolate ? undefined : this.configurationStore.onUnAuthorisedDefaultStrategy;
+
+ }
+
+ public setDefaultOnAuthorizedStrategy(name: string | 'remove' | 'show') {
+ if (this.strategiesSource.value[ name ] || this.predefinedStrategy(name)) {
+ this.onAuthorisedDefaultStrategy = name;
+ } else {
+ throw new Error(`No ${name} strategy is found please define one`);
+ }
+ }
+
+ public setDefaultOnUnauthorizedStrategy(name: string | 'remove' | 'show') {
+ if (this.strategiesSource.value[ name ] || this.predefinedStrategy(name)) {
+ this.onUnAuthorisedDefaultStrategy = name;
+ } else {
+ throw new Error(`No ' ${name} ' strategy is found please define one`);
+ }
+ }
+
+ public addPermissionStrategy(key: string, func: StrategyFunction): void {
+ this.strategiesSource.value[ key ] = func;
+ }
+
+ public getStrategy(key: string) {
+ return this.strategiesSource.value[ key ];
+ }
+
+ public getAllStrategies() {
+ return this.strategiesSource.value;
+ }
+
+ private predefinedStrategy(strategy: string): boolean {
+ return strategy === NgxPermissionsPredefinedStrategies.SHOW || strategy === NgxPermissionsPredefinedStrategies.REMOVE;
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/store/configuration.store.ts
+
+ constructor()
+ |
+
+ + | +
+ Public onAuthorisedDefaultStrategy + | +
+ onAuthorisedDefaultStrategy: |
+
+ + | +
+ Public onUnAuthorisedDefaultStrategy + | +
+ onUnAuthorisedDefaultStrategy: |
+
+ + | +
+ Public strategies$ + | +
+ strategies$: |
+
+ + | +
+ Public strategiesSource + | +
+ strategiesSource: |
+
+ + | +
import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { Strategy } from '../service/configuration.service';
+
+@Injectable()
+export class NgxPermissionsConfigurationStore {
+
+ public strategiesSource: BehaviorSubject<Strategy> = new BehaviorSubject<Strategy>({});
+ public strategies$: Observable<Strategy> = this.strategiesSource.asObservable();
+
+ public onAuthorisedDefaultStrategy: string | undefined;
+ public onUnAuthorisedDefaultStrategy: string | undefined;
+
+ constructor() {
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/router/permissions-guard.service.ts
+
+ constructor(permissionsService: any, rolesService: any, router: any)
+ |
+
+ + | +
+ canActivate + | +
+ canActivate(route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ canActivateChild + | +
+ canActivateChild(childRoute: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ canLoad + | +
+ canLoad(route: any)
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private hasPermissions + | +
+
+ hasPermissions(route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private transformPermission + | +
+
+ transformPermission(purePermissions: any, route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private isParameterAvailable + | +
+
+ isParameterAvailable(permission: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private passingExceptPermissionsValidation + | +
+
+ passingExceptPermissionsValidation(permissions: any, route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private redirectToAnotherRoute + | +
+
+ redirectToAnotherRoute(redirectTo: any, route: any, state: any, failedPermissionName: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private isRedirectionWithParameters + | +
+
+ isRedirectionWithParameters(object: any)
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
+ Private hasNavigationExtrasAsFunction + | +
+
+ hasNavigationExtrasAsFunction(redirectTo: any)
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
+ Private hasNavigationCommandsAsFunction + | +
+
+ hasNavigationCommandsAsFunction(redirectTo: any)
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
+ Private onlyRedirectCheck + | +
+
+ onlyRedirectCheck(permissions: any, route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private handleRedirectOfFailedPermission + | +
+
+ handleRedirectOfFailedPermission(permissions: any, failedPermission: string, route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private isFailedPermissionPropertyOfRedirectTo + | +
+
+ isFailedPermissionPropertyOfRedirectTo(permissions: any, failedPermission: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private checkOnlyPermissions + | +
+
+ checkOnlyPermissions(purePermissions: any, route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Private passingOnlyPermissionsValidation + | +
+
+ passingOnlyPermissionsValidation(permissions: any, route: any, state: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
import { Injectable } from '@angular/core';
+import {
+ ActivatedRouteSnapshot,
+ CanActivate,
+ CanActivateChild,
+ CanLoad,
+ NavigationExtras,
+ Route,
+ Router,
+ RouterStateSnapshot,
+} from '@angular/router';
+import { forkJoin, from, Observable, of } from 'rxjs';
+import { first, mergeMap, tap } from 'rxjs/operators';
+
+import { NgxPermissionsRouterData } from '../model/permissions-router-data.model';
+import { NgxPermissionsService } from '../service/permissions.service';
+import { NgxRolesService } from '../service/roles.service';
+import { isFunction, isPlainObject, transformStringToArray } from '../utils/utils';
+
+
+
+
+interface NgxRedirectToNavigationParameters {
+ navigationCommands: any[] | Function;
+ navigationExtras?: NavigationExtras | Function;
+}
+
+@Injectable()
+export class NgxPermissionsGuard implements CanActivate, CanLoad, CanActivateChild {
+
+ constructor(private permissionsService: NgxPermissionsService, private rolesService: NgxRolesService, private router: Router) {
+ }
+
+ canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> | boolean {
+ return this.hasPermissions(route, state);
+ }
+
+ canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
+ return this.hasPermissions(childRoute, state);
+ }
+
+ canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> {
+ return this.hasPermissions(route);
+ }
+
+ private hasPermissions(route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
+ const purePermissions = !!route && route.data ? route.data['permissions'] as NgxPermissionsRouterData : {};
+ let permissions: NgxPermissionsRouterData = this.transformPermission(purePermissions, route, state);
+
+ if (this.isParameterAvailable(permissions.except)) {
+ return this.passingExceptPermissionsValidation(permissions, route, state);
+ }
+
+ if (this.isParameterAvailable(permissions.only)) {
+ return this.passingOnlyPermissionsValidation(permissions, route, state);
+ }
+
+ return true;
+ }
+
+ private transformPermission(purePermissions: NgxPermissionsRouterData, route: any, state: any): any {
+ let permissions = {
+ ...purePermissions
+ };
+
+ if (isFunction(permissions.except)) {
+ permissions.except = (permissions.except as Function)(route, state);
+ }
+
+ if (isFunction(permissions.only)) {
+ permissions.only = (permissions.only as Function)(route, state);
+ }
+
+ permissions.except = transformStringToArray(permissions.except);
+ permissions.only = transformStringToArray(permissions.only);
+
+ return permissions;
+ }
+
+ private isParameterAvailable(permission: any) {
+ return !!(permission) && permission.length > 0;
+ }
+
+ private passingExceptPermissionsValidation(permissions: NgxPermissionsRouterData, route: any, state: any) {
+ if (!!permissions.redirectTo && (isFunction(permissions.redirectTo) ||
+ (isPlainObject(permissions.redirectTo) && !this.isRedirectionWithParameters(permissions.redirectTo)))) {
+ let failedPermission = '';
+
+ return from(permissions.except as any[]).pipe(
+ mergeMap((data) => {
+ return forkJoin([
+ this.permissionsService.hasPermission(<string | string[]>data),
+ this.rolesService.hasOnlyRoles(<string | string[]>data)
+ ]).pipe(tap((hasPermissions: boolean[]) => {
+ const dontHavePermissions = hasPermissions.every((_data) => _data === false);
+
+ if (!dontHavePermissions) {
+ failedPermission = data;
+ }
+ }));
+ }),
+ first((data: any) => data.some((_data: boolean) => _data === true), false),
+ mergeMap((isAllFalse) => {
+ if (!!failedPermission) {
+ this.handleRedirectOfFailedPermission(permissions, failedPermission, route, state);
+
+ return of(false);
+ }
+
+ if (!isAllFalse && permissions.only) {
+ return this.onlyRedirectCheck(permissions, route, state);
+ }
+
+ return of(!isAllFalse);
+ })
+ ).toPromise();
+ }
+
+ return Promise.all([
+ this.permissionsService.hasPermission(<string | string[]>permissions.except),
+ this.rolesService.hasOnlyRoles(<string | string[]>permissions.except)
+ ]).then(([permissionsPr, roles]) => {
+ if (permissionsPr || roles) {
+ if (permissions.redirectTo) {
+ this.redirectToAnotherRoute(permissions.redirectTo, route, state);
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ if (permissions.only) {
+ return this.checkOnlyPermissions(permissions, route, state);
+ }
+ return true;
+ }
+ });
+ }
+
+ private redirectToAnotherRoute(
+ redirectTo: string | any[] | NgxRedirectToNavigationParameters | Function,
+ route: ActivatedRouteSnapshot | Route,
+ state?: RouterStateSnapshot,
+ failedPermissionName?: string
+ ) {
+ if (isFunction(redirectTo)) {
+ redirectTo = (redirectTo as Function)(failedPermissionName, route, state);
+ }
+
+ if (this.isRedirectionWithParameters(redirectTo)) {
+ if (this.hasNavigationExtrasAsFunction(redirectTo)) {
+ (<NgxRedirectToNavigationParameters>redirectTo).navigationExtras =
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationExtras as Function)(
+ route,
+ state
+ );
+ }
+
+ if (this.hasNavigationCommandsAsFunction(redirectTo)) {
+ (<NgxRedirectToNavigationParameters>redirectTo).navigationCommands =
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationCommands as Function)(
+ route,
+ state
+ );
+ }
+
+ this.router.navigate(
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationCommands as any[]),
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationExtras as NavigationExtras)
+ );
+
+ return;
+ }
+
+ if (Array.isArray(redirectTo)) {
+ this.router.navigate(redirectTo);
+ } else {
+ this.router.navigate([redirectTo]);
+ }
+ }
+
+ private isRedirectionWithParameters(object: any | NgxRedirectToNavigationParameters): boolean {
+ return isPlainObject(object) && (!!object.navigationCommands || !!object.navigationExtras);
+ }
+
+ private hasNavigationExtrasAsFunction(redirectTo: any): boolean {
+ return !!(<NgxRedirectToNavigationParameters>redirectTo).navigationExtras &&
+ isFunction((<NgxRedirectToNavigationParameters>redirectTo).navigationExtras);
+ }
+
+ private hasNavigationCommandsAsFunction(redirectTo: any): boolean {
+ return !!(<NgxRedirectToNavigationParameters>redirectTo).navigationCommands &&
+ isFunction((<NgxRedirectToNavigationParameters>redirectTo).navigationCommands);
+ }
+
+ private onlyRedirectCheck(permissions: any, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot): Promise<boolean> {
+ let failedPermission = '';
+
+ return from(permissions.only).pipe(
+ mergeMap((data: any) => {
+ return forkJoin([
+ this.permissionsService.hasPermission(<string | string[]>data),
+ this.rolesService.hasOnlyRoles(<string | string[]>data)
+ ]).pipe(
+ tap((hasPermission: boolean[]) => {
+ const failed = hasPermission.every((_data) => _data === false);
+
+ if (failed) {
+ failedPermission = data;
+ }
+ })
+ );
+ }),
+ first(
+ (data: any) => {
+ if (isFunction(permissions.redirectTo)) {
+ return data.some((_data: boolean) => _data === true);
+ }
+
+ return data.every((_data: boolean) => _data === false);
+ },
+ false
+ ),
+ mergeMap((pass: boolean): Observable<boolean> => {
+ if (isFunction(permissions.redirectTo)) {
+ if (pass) {
+ return of(true);
+ } else {
+ this.handleRedirectOfFailedPermission(permissions, failedPermission, route, state);
+ return of(false);
+ }
+ } else {
+ if (!!failedPermission) {
+ this.handleRedirectOfFailedPermission(permissions, failedPermission, route, state);
+ }
+ return of(!pass);
+ }
+ })
+ ).toPromise();
+ }
+
+ private handleRedirectOfFailedPermission(
+ permissions: any,
+ failedPermission: string,
+ route: ActivatedRouteSnapshot | Route,
+ state?: RouterStateSnapshot
+ ) {
+ if (this.isFailedPermissionPropertyOfRedirectTo(permissions, failedPermission)) {
+ this.redirectToAnotherRoute((<any>permissions.redirectTo)[failedPermission], route, state, failedPermission);
+ } else {
+ if (isFunction(permissions.redirectTo)) {
+ this.redirectToAnotherRoute((<any>permissions.redirectTo), route, state, failedPermission);
+ } else {
+ this.redirectToAnotherRoute((<any>permissions.redirectTo)['default'], route, state, failedPermission);
+ }
+ }
+ }
+
+ private isFailedPermissionPropertyOfRedirectTo(permissions: any, failedPermission: string) {
+ return !!permissions.redirectTo && permissions.redirectTo[<any>failedPermission];
+ }
+
+ private checkOnlyPermissions(purePermissions: any, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
+ let permissions: NgxPermissionsRouterData = {
+ ...purePermissions
+ };
+
+ return Promise.all([
+ this.permissionsService.hasPermission(<string | string[]>permissions.only),
+ this.rolesService.hasOnlyRoles(<string | string[]>permissions.only)
+ ]).then(([permissionsPr, roles]) => {
+ if (permissionsPr || roles) {
+ return true;
+ } else {
+ if (permissions.redirectTo) {
+ this.redirectToAnotherRoute(permissions.redirectTo, route, state);
+ return false;
+ } else {
+ return false;
+ }
+ }
+ });
+ }
+
+ private passingOnlyPermissionsValidation(
+ permissions: NgxPermissionsRouterData, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
+ if ((isFunction(permissions.redirectTo) ||
+ isPlainObject(permissions.redirectTo) && !this.isRedirectionWithParameters(permissions.redirectTo))) {
+ return this.onlyRedirectCheck(permissions, route, state);
+ }
+ return this.checkOnlyPermissions(permissions, route, state);
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/service/permissions.service.ts
+
+ constructor(isolate: boolean, permissionsStore: any)
+ |
+
+ + | +
+ Public flushPermissions + | +
+
+ flushPermissions()
+ |
+
+ + | +
+ Remove all permissions from permissions source +
+ Returns :
+ void
+
+ |
+
+ Public hasPermission + | +
+
+ hasPermission(permission: string | {})
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Public loadPermissions + | +
+
+ loadPermissions(permissions: {}, validationFunction: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public addPermission + | +
+
+ addPermission(permission: string | {}, validationFunction: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public removePermission + | +
+
+ removePermission(permissionName: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public getPermission + | +
+
+ getPermission(name: string)
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Public getPermissions + | +
+
+ getPermissions()
+ |
+
+ + | +
+
+
+ Returns :
+ NgxPermissionsObject
+
+ |
+
+ Private reducePermission + | +
+
+ reducePermission(source: NgxPermissionsObject, name: string, validationFunction: any)
+ |
+
+ + | +
+
+
+ Returns :
+ NgxPermissionsObject
+
+ |
+
+ Private hasArrayPermission + | +
+
+ hasArrayPermission(permissions: {})
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private hasPermissionValidationFunction + | +
+
+ hasPermissionValidationFunction(key: string)
+ |
+
+ + | +
+
+
+ Returns :
+ boolean
+
+ |
+
+ Public permissions$ + | +
+ permissions$: |
+
+ + | +
+ Private permissionsSource + | +
+ permissionsSource: |
+
+ + | +
import { Inject, Injectable, InjectionToken } from '@angular/core';
+
+import { BehaviorSubject, from, Observable, ObservableInput, of } from 'rxjs';
+import { catchError, first, map, mergeAll, switchMap, tap } from 'rxjs/operators';
+
+import { NgxPermission } from '../model/permission.model';
+import { NgxPermissionsStore } from '../store/permissions.store';
+
+import { isBoolean, isFunction, transformStringToArray } from '../utils/utils';
+
+export type NgxPermissionsObject = { [ name: string ]: NgxPermission };
+
+export const USE_PERMISSIONS_STORE = new InjectionToken('USE_PERMISSIONS_STORE');
+
+@Injectable()
+export class NgxPermissionsService {
+
+ private permissionsSource: BehaviorSubject<NgxPermissionsObject>;
+ public permissions$: Observable<NgxPermissionsObject>;
+
+ constructor(
+ @Inject(USE_PERMISSIONS_STORE) private isolate: boolean = false,
+ private permissionsStore: NgxPermissionsStore
+ ) {
+ this.permissionsSource = isolate ? new BehaviorSubject<NgxPermissionsObject>({}) : permissionsStore.permissionsSource;
+ this.permissions$ = this.permissionsSource.asObservable();
+ }
+
+ /**
+ * Remove all permissions from permissions source
+ */
+ public flushPermissions(): void {
+ this.permissionsSource.next({});
+ }
+
+ public hasPermission(permission: string | string[]): Promise<boolean> {
+ if (!permission || (Array.isArray(permission) && permission.length === 0)) {
+ return Promise.resolve(true);
+ }
+
+ permission = transformStringToArray(permission);
+ return this.hasArrayPermission(permission);
+ }
+
+ public loadPermissions(permissions: string[], validationFunction?: Function): void {
+ const newPermissions = permissions.reduce((source, p) =>
+ this.reducePermission(source, p, validationFunction)
+ , {});
+
+ this.permissionsSource.next(newPermissions);
+ }
+
+ public addPermission(permission: string | string[], validationFunction?: Function): void {
+ if (Array.isArray(permission)) {
+ const permissions = permission.reduce((source, p) =>
+ this.reducePermission(source, p, validationFunction)
+ , this.permissionsSource.value);
+
+ this.permissionsSource.next(permissions);
+ } else {
+ const permissions = this.reducePermission(this.permissionsSource.value, permission, validationFunction);
+
+ this.permissionsSource.next(permissions);
+ }
+ }
+
+ public removePermission(permissionName: string): void {
+ const permissions = {
+ ...this.permissionsSource.value
+ };
+ delete permissions[ permissionName ];
+ this.permissionsSource.next(permissions);
+ }
+
+ public getPermission(name: string): NgxPermission {
+ return this.permissionsSource.value[ name ];
+ }
+
+ public getPermissions(): NgxPermissionsObject {
+ return this.permissionsSource.value;
+ }
+
+ private reducePermission(
+ source: NgxPermissionsObject,
+ name: string,
+ validationFunction?: Function
+ ): NgxPermissionsObject {
+ if (!!validationFunction && isFunction(validationFunction)) {
+ return {
+ ...source,
+ [ name ]: { name, validationFunction }
+ };
+ } else {
+ return {
+ ...source,
+ [ name ]: { name }
+ };
+ }
+ }
+
+ private hasArrayPermission(permissions: string[]): Promise<boolean> {
+ const promises: Observable<boolean>[] = permissions.map((key) => {
+ if (this.hasPermissionValidationFunction(key)) {
+ const immutableValue = { ...this.permissionsSource.value };
+ const validationFunction: Function = <Function>this.permissionsSource.value[ key ].validationFunction;
+
+ return of(null).pipe(
+ map(() => validationFunction(key, immutableValue)),
+ switchMap((promise: Promise<boolean> | boolean): ObservableInput<boolean> => isBoolean(promise) ?
+ of(promise as boolean) : promise as Promise<boolean>),
+ catchError(() => of(false))
+ );
+ }
+
+ // check for name of the permission if there is no validation function
+ return of(!!this.permissionsSource.value[ key ]);
+ });
+
+ return from(promises).pipe(
+ mergeAll(),
+ first((data) => data !== false, false),
+ map((data) => data === false ? false : true)
+ ).toPromise().then((data: any) => data);
+ }
+
+ private hasPermissionValidationFunction(key: string): boolean {
+ return !!this.permissionsSource.value[ key ] &&
+ !!this.permissionsSource.value[ key ].validationFunction &&
+ isFunction(this.permissionsSource.value[ key ].validationFunction);
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/store/permissions.store.ts
+
+ constructor()
+ |
+
+ + | +
+ Public permissions$ + | +
+ permissions$: |
+
+ + | +
+ Public permissionsSource + | +
+ permissionsSource: |
+
+ + | +
import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+
+@Injectable()
+export class NgxPermissionsStore {
+
+ public permissionsSource = new BehaviorSubject<{}>({});
+ public permissions$: Observable<{}> = this.permissionsSource.asObservable();
+
+ constructor() {
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/service/roles.service.ts
+
+ constructor(isolate: boolean, rolesStore: any, permissionsService: any)
+ |
+
+ + | +
+ Public addRole + | +
+
+ addRole(name: string, validationFunction: any)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public addRoles + | +
+
+ addRoles(rolesObj: { [name: string]: any; })
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public flushRoles + | +
+
+ flushRoles()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public removeRole + | +
+
+ removeRole(roleName: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public getRoles + | +
+
+ getRoles()
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public getRole + | +
+
+ getRole(name: string)
+ |
+
+ + | +
+
+
+ Returns :
+ void
+
+ |
+
+ Public hasOnlyRoles + | +
+
+ hasOnlyRoles(names: string | {})
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private hasRoleKey + | +
+
+ hasRoleKey(roleName: {})
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Private hasRolePermission + | +
+
+ hasRolePermission(roles: NgxRolesObject, roleNames: {})
+ |
+
+ + | +
+
+
+ Returns :
+ any
+
+ |
+
+ Public roles$ + | +
+ roles$: |
+
+ + | +
+ Private rolesSource + | +
+ rolesSource: |
+
+ + | +
import { Inject, Injectable, InjectionToken } from '@angular/core';
+import { BehaviorSubject, Observable, ObservableInput, from, of } from 'rxjs';
+import { catchError, every, first, map, mergeAll, mergeMap, switchMap } from 'rxjs/operators';
+import { NgxRole } from '../model/role.model';
+import { NgxRolesStore } from '../store/roles.store';
+import { isBoolean, isFunction, isPromise, transformStringToArray } from '../utils/utils';
+import { NgxPermissionsService } from './permissions.service';
+
+export const USE_ROLES_STORE = new InjectionToken('USE_ROLES_STORE');
+
+export type NgxRolesObject = { [name: string]: NgxRole };
+
+@Injectable()
+export class NgxRolesService {
+
+ private rolesSource: BehaviorSubject<NgxRolesObject>;
+
+ public roles$: Observable<NgxRolesObject>;
+
+ constructor(
+ @Inject(USE_ROLES_STORE) private isolate: boolean = false,
+ private rolesStore: NgxRolesStore,
+ private permissionsService: NgxPermissionsService
+ ) {
+ this.rolesSource = this.isolate ? new BehaviorSubject<NgxRolesObject>({}) : this.rolesStore.rolesSource;
+ this.roles$ = this.rolesSource.asObservable();
+ }
+
+ public addRole(name: string, validationFunction: Function | string[]) {
+ const roles = {
+ ...this.rolesSource.value,
+ [name]: { name, validationFunction }
+ };
+ this.rolesSource.next(roles);
+ }
+
+ public addRoles(rolesObj: { [name: string]: Function | string[] }) {
+ Object.keys(rolesObj).forEach((key, index) => {
+ this.addRole(key, rolesObj[key]);
+ });
+ }
+
+ public flushRoles() {
+ this.rolesSource.next({});
+ }
+
+ public removeRole(roleName: string) {
+ let roles = {
+ ...this.rolesSource.value
+ };
+ delete roles[roleName];
+ this.rolesSource.next(roles);
+ }
+
+ public getRoles() {
+ return this.rolesSource.value;
+ }
+
+ public getRole(name: string) {
+ return this.rolesSource.value[name];
+ }
+
+ public hasOnlyRoles(names: string | string[]): Promise<boolean> {
+ if (!names || (Array.isArray(names) && names.length === 0)) {
+ return Promise.resolve(true);
+ }
+
+ names = transformStringToArray(names);
+
+ return Promise.all([this.hasRoleKey(names), this.hasRolePermission(this.rolesSource.value, names)])
+ .then(([hasRoles, hasPermissions]: [boolean, boolean]) => {
+ return hasRoles || hasPermissions;
+ });
+ }
+
+ private hasRoleKey(roleName: string[]): Promise<boolean> {
+ const promises: Observable<boolean>[] = roleName.map((key) => {
+ if (
+ !!this.rolesSource.value[key] &&
+ !!this.rolesSource.value[key].validationFunction &&
+ isFunction(this.rolesSource.value[key].validationFunction) &&
+ !isPromise(this.rolesSource.value[key].validationFunction)
+ ) {
+ const validationFunction: Function = <Function>this.rolesSource.value[key].validationFunction;
+
+ return of(null).pipe(
+ map(() => validationFunction()),
+ switchMap((promise: Promise<boolean> | boolean): ObservableInput<boolean> => isBoolean(promise) ?
+ of(promise as boolean) : promise as Promise<boolean>),
+ catchError(() => of(false))
+ );
+ }
+
+ return of(false);
+ });
+
+ return from(promises).pipe(
+ mergeAll(),
+ first((data: any) => data !== false, false),
+ map((data) => data === false ? false : true)
+ ).toPromise().then((data: any) => data);
+ }
+
+ private hasRolePermission(roles: NgxRolesObject, roleNames: string[]): Promise<boolean> {
+ return from(roleNames).pipe(
+ mergeMap((key) => {
+ if (roles[key] && Array.isArray(roles[key].validationFunction)) {
+ return from(<string[]>roles[key].validationFunction).pipe(
+ mergeMap((permission) => this.permissionsService.hasPermission(permission)),
+ every((hasPermissions) => hasPermissions === true)
+ );
+ }
+
+ return of(false);
+ }),
+ first((hasPermission) => hasPermission === true, false)
+ ).toPromise();
+ }
+
+}
+
+ +
+ projects/ngx-permissions/src/lib/index.ts
+
+ configurationIsolate + | +
+ configurationIsolate: |
+
+ Type : boolean
+
+ |
+
+ Defined in projects/ngx-permissions/src/lib/index.ts:37
+ |
+
+ permissionsIsolate + | +
+ permissionsIsolate: |
+
+ Type : boolean
+
+ |
+
+ Defined in projects/ngx-permissions/src/lib/index.ts:36
+ |
+
+ rolesIsolate + | +
+ rolesIsolate: |
+
+ Type : boolean
+
+ |
+
+ Defined in projects/ngx-permissions/src/lib/index.ts:35
+ |
+
import { ModuleWithProviders, NgModule } from '@angular/core';
+import { NgxPermissionsDirective } from './directive/permissions.directive';
+import { NgxPermissionsGuard } from './router/permissions-guard.service';
+import { NgxPermissionsConfigurationService, USE_CONFIGURATION_STORE } from './service/configuration.service';
+import { NgxPermissionsService, USE_PERMISSIONS_STORE } from './service/permissions.service';
+import { NgxRolesService, USE_ROLES_STORE } from './service/roles.service';
+import { NgxPermissionsConfigurationStore } from './store/configuration.store';
+import { NgxPermissionsStore } from './store/permissions.store';
+import { NgxRolesStore } from './store/roles.store';
+import { NgxPermissionsAllowStubDirective } from './testing/permissions-allow.directive.stub';
+import { NgxPermissionsRestrictStubDirective } from './testing/permissions-restrict.directive.stub';
+
+export * from './store/roles.store';
+export * from './store/permissions.store';
+export * from './store/configuration.store';
+
+export * from './directive/permissions.directive';
+
+export * from './service/permissions.service';
+export * from './service/roles.service';
+export * from './service/configuration.service';
+
+export * from './router/permissions-guard.service';
+
+export * from './model/permissions-router-data.model';
+export * from './model/role.model';
+
+export * from './testing/permissions-allow.directive.stub';
+export * from './testing/permissions-restrict.directive.stub';
+
+export * from './enums/predefined-strategies.enum';
+
+export interface NgxPermissionsModuleConfig {
+ // isolate the service instance, only works for lazy loaded modules or components with the "providers" property
+ rolesIsolate?: boolean;
+ permissionsIsolate?: boolean;
+ configurationIsolate?: boolean;
+}
+
+
+@NgModule({
+ imports: [],
+ declarations: [
+ NgxPermissionsDirective
+ ],
+ exports: [
+ NgxPermissionsDirective
+ ]
+})
+export class NgxPermissionsModule {
+ static forRoot(config: NgxPermissionsModuleConfig = {}): ModuleWithProviders {
+ return {
+ ngModule: NgxPermissionsModule,
+ providers: [
+ NgxPermissionsStore,
+ NgxRolesStore,
+ NgxPermissionsConfigurationStore,
+ NgxPermissionsService,
+ NgxPermissionsGuard,
+ NgxRolesService,
+ NgxPermissionsConfigurationService,
+ { provide: USE_PERMISSIONS_STORE, useValue: config.permissionsIsolate },
+ { provide: USE_ROLES_STORE, useValue: config.rolesIsolate },
+ { provide: USE_CONFIGURATION_STORE, useValue: config.configurationIsolate },
+ ]
+ };
+ }
+
+ static forChild(config: NgxPermissionsModuleConfig = {}): ModuleWithProviders {
+ return {
+ ngModule: NgxPermissionsModule,
+ providers: [
+ { provide: USE_PERMISSIONS_STORE, useValue: config.permissionsIsolate },
+ { provide: USE_ROLES_STORE, useValue: config.rolesIsolate },
+ { provide: USE_CONFIGURATION_STORE, useValue: config.configurationIsolate },
+ NgxPermissionsConfigurationService,
+ NgxPermissionsService,
+ NgxRolesService,
+ NgxPermissionsGuard
+ ]
+ };
+ }
+}
+
+@NgModule({
+ imports: [],
+ declarations: [
+ NgxPermissionsAllowStubDirective
+ ],
+ exports: [
+ NgxPermissionsAllowStubDirective
+ ]
+})
+export class NgxPermissionsAllowStubModule {
+}
+
+
+@NgModule({
+ imports: [],
+ declarations: [
+ NgxPermissionsRestrictStubDirective
+ ],
+ exports: [
+ NgxPermissionsRestrictStubDirective
+ ]
+})
+export class NgxPermissionsRestrictStubModule {
+}
+
+
+
+ +
+ projects/ngx-permissions/src/lib/model/permissions-router-data.model.ts
+
+ except + | +
+ except: |
+
+ Type : any
+
+ |
+
+ + | +
+ only + | +
+ only: |
+
+ Type : any
+
+ |
+
+ + | +
+ redirectTo + | +
+ redirectTo: |
+
+ Type : string
+
+ |
+
+ + | +
export interface NgxPermissionsRouterData {
+ only?: string | string[] | Function;
+ except?: string | string[] | Function;
+ redirectTo?: string;
+}
+
+ +
+ projects/ngx-permissions/src/lib/router/permissions-guard.service.ts
+
+ navigationCommands + | +
+ navigationCommands: |
+
+ Type : any
+
+ |
+
+ + | +
+ navigationExtras + | +
+ navigationExtras: |
+
+ Type : any
+
+ |
+
+ + | +
import { Injectable } from '@angular/core';
+import {
+ ActivatedRouteSnapshot,
+ CanActivate,
+ CanActivateChild,
+ CanLoad,
+ NavigationExtras,
+ Route,
+ Router,
+ RouterStateSnapshot,
+} from '@angular/router';
+import { forkJoin, from, Observable, of } from 'rxjs';
+import { first, mergeMap, tap } from 'rxjs/operators';
+
+import { NgxPermissionsRouterData } from '../model/permissions-router-data.model';
+import { NgxPermissionsService } from '../service/permissions.service';
+import { NgxRolesService } from '../service/roles.service';
+import { isFunction, isPlainObject, transformStringToArray } from '../utils/utils';
+
+
+
+
+interface NgxRedirectToNavigationParameters {
+ navigationCommands: any[] | Function;
+ navigationExtras?: NavigationExtras | Function;
+}
+
+@Injectable()
+export class NgxPermissionsGuard implements CanActivate, CanLoad, CanActivateChild {
+
+ constructor(private permissionsService: NgxPermissionsService, private rolesService: NgxRolesService, private router: Router) {
+ }
+
+ canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> | boolean {
+ return this.hasPermissions(route, state);
+ }
+
+ canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
+ return this.hasPermissions(childRoute, state);
+ }
+
+ canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> {
+ return this.hasPermissions(route);
+ }
+
+ private hasPermissions(route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
+ const purePermissions = !!route && route.data ? route.data['permissions'] as NgxPermissionsRouterData : {};
+ let permissions: NgxPermissionsRouterData = this.transformPermission(purePermissions, route, state);
+
+ if (this.isParameterAvailable(permissions.except)) {
+ return this.passingExceptPermissionsValidation(permissions, route, state);
+ }
+
+ if (this.isParameterAvailable(permissions.only)) {
+ return this.passingOnlyPermissionsValidation(permissions, route, state);
+ }
+
+ return true;
+ }
+
+ private transformPermission(purePermissions: NgxPermissionsRouterData, route: any, state: any): any {
+ let permissions = {
+ ...purePermissions
+ };
+
+ if (isFunction(permissions.except)) {
+ permissions.except = (permissions.except as Function)(route, state);
+ }
+
+ if (isFunction(permissions.only)) {
+ permissions.only = (permissions.only as Function)(route, state);
+ }
+
+ permissions.except = transformStringToArray(permissions.except);
+ permissions.only = transformStringToArray(permissions.only);
+
+ return permissions;
+ }
+
+ private isParameterAvailable(permission: any) {
+ return !!(permission) && permission.length > 0;
+ }
+
+ private passingExceptPermissionsValidation(permissions: NgxPermissionsRouterData, route: any, state: any) {
+ if (!!permissions.redirectTo && (isFunction(permissions.redirectTo) ||
+ (isPlainObject(permissions.redirectTo) && !this.isRedirectionWithParameters(permissions.redirectTo)))) {
+ let failedPermission = '';
+
+ return from(permissions.except as any[]).pipe(
+ mergeMap((data) => {
+ return forkJoin([
+ this.permissionsService.hasPermission(<string | string[]>data),
+ this.rolesService.hasOnlyRoles(<string | string[]>data)
+ ]).pipe(tap((hasPermissions: boolean[]) => {
+ const dontHavePermissions = hasPermissions.every((_data) => _data === false);
+
+ if (!dontHavePermissions) {
+ failedPermission = data;
+ }
+ }));
+ }),
+ first((data: any) => data.some((_data: boolean) => _data === true), false),
+ mergeMap((isAllFalse) => {
+ if (!!failedPermission) {
+ this.handleRedirectOfFailedPermission(permissions, failedPermission, route, state);
+
+ return of(false);
+ }
+
+ if (!isAllFalse && permissions.only) {
+ return this.onlyRedirectCheck(permissions, route, state);
+ }
+
+ return of(!isAllFalse);
+ })
+ ).toPromise();
+ }
+
+ return Promise.all([
+ this.permissionsService.hasPermission(<string | string[]>permissions.except),
+ this.rolesService.hasOnlyRoles(<string | string[]>permissions.except)
+ ]).then(([permissionsPr, roles]) => {
+ if (permissionsPr || roles) {
+ if (permissions.redirectTo) {
+ this.redirectToAnotherRoute(permissions.redirectTo, route, state);
+ return false;
+ } else {
+ return false;
+ }
+ } else {
+ if (permissions.only) {
+ return this.checkOnlyPermissions(permissions, route, state);
+ }
+ return true;
+ }
+ });
+ }
+
+ private redirectToAnotherRoute(
+ redirectTo: string | any[] | NgxRedirectToNavigationParameters | Function,
+ route: ActivatedRouteSnapshot | Route,
+ state?: RouterStateSnapshot,
+ failedPermissionName?: string
+ ) {
+ if (isFunction(redirectTo)) {
+ redirectTo = (redirectTo as Function)(failedPermissionName, route, state);
+ }
+
+ if (this.isRedirectionWithParameters(redirectTo)) {
+ if (this.hasNavigationExtrasAsFunction(redirectTo)) {
+ (<NgxRedirectToNavigationParameters>redirectTo).navigationExtras =
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationExtras as Function)(
+ route,
+ state
+ );
+ }
+
+ if (this.hasNavigationCommandsAsFunction(redirectTo)) {
+ (<NgxRedirectToNavigationParameters>redirectTo).navigationCommands =
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationCommands as Function)(
+ route,
+ state
+ );
+ }
+
+ this.router.navigate(
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationCommands as any[]),
+ ((<NgxRedirectToNavigationParameters>redirectTo).navigationExtras as NavigationExtras)
+ );
+
+ return;
+ }
+
+ if (Array.isArray(redirectTo)) {
+ this.router.navigate(redirectTo);
+ } else {
+ this.router.navigate([redirectTo]);
+ }
+ }
+
+ private isRedirectionWithParameters(object: any | NgxRedirectToNavigationParameters): boolean {
+ return isPlainObject(object) && (!!object.navigationCommands || !!object.navigationExtras);
+ }
+
+ private hasNavigationExtrasAsFunction(redirectTo: any): boolean {
+ return !!(<NgxRedirectToNavigationParameters>redirectTo).navigationExtras &&
+ isFunction((<NgxRedirectToNavigationParameters>redirectTo).navigationExtras);
+ }
+
+ private hasNavigationCommandsAsFunction(redirectTo: any): boolean {
+ return !!(<NgxRedirectToNavigationParameters>redirectTo).navigationCommands &&
+ isFunction((<NgxRedirectToNavigationParameters>redirectTo).navigationCommands);
+ }
+
+ private onlyRedirectCheck(permissions: any, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot): Promise<boolean> {
+ let failedPermission = '';
+
+ return from(permissions.only).pipe(
+ mergeMap((data: any) => {
+ return forkJoin([
+ this.permissionsService.hasPermission(<string | string[]>data),
+ this.rolesService.hasOnlyRoles(<string | string[]>data)
+ ]).pipe(
+ tap((hasPermission: boolean[]) => {
+ const failed = hasPermission.every((_data) => _data === false);
+
+ if (failed) {
+ failedPermission = data;
+ }
+ })
+ );
+ }),
+ first(
+ (data: any) => {
+ if (isFunction(permissions.redirectTo)) {
+ return data.some((_data: boolean) => _data === true);
+ }
+
+ return data.every((_data: boolean) => _data === false);
+ },
+ false
+ ),
+ mergeMap((pass: boolean): Observable<boolean> => {
+ if (isFunction(permissions.redirectTo)) {
+ if (pass) {
+ return of(true);
+ } else {
+ this.handleRedirectOfFailedPermission(permissions, failedPermission, route, state);
+ return of(false);
+ }
+ } else {
+ if (!!failedPermission) {
+ this.handleRedirectOfFailedPermission(permissions, failedPermission, route, state);
+ }
+ return of(!pass);
+ }
+ })
+ ).toPromise();
+ }
+
+ private handleRedirectOfFailedPermission(
+ permissions: any,
+ failedPermission: string,
+ route: ActivatedRouteSnapshot | Route,
+ state?: RouterStateSnapshot
+ ) {
+ if (this.isFailedPermissionPropertyOfRedirectTo(permissions, failedPermission)) {
+ this.redirectToAnotherRoute((<any>permissions.redirectTo)[failedPermission], route, state, failedPermission);
+ } else {
+ if (isFunction(permissions.redirectTo)) {
+ this.redirectToAnotherRoute((<any>permissions.redirectTo), route, state, failedPermission);
+ } else {
+ this.redirectToAnotherRoute((<any>permissions.redirectTo)['default'], route, state, failedPermission);
+ }
+ }
+ }
+
+ private isFailedPermissionPropertyOfRedirectTo(permissions: any, failedPermission: string) {
+ return !!permissions.redirectTo && permissions.redirectTo[<any>failedPermission];
+ }
+
+ private checkOnlyPermissions(purePermissions: any, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
+ let permissions: NgxPermissionsRouterData = {
+ ...purePermissions
+ };
+
+ return Promise.all([
+ this.permissionsService.hasPermission(<string | string[]>permissions.only),
+ this.rolesService.hasOnlyRoles(<string | string[]>permissions.only)
+ ]).then(([permissionsPr, roles]) => {
+ if (permissionsPr || roles) {
+ return true;
+ } else {
+ if (permissions.redirectTo) {
+ this.redirectToAnotherRoute(permissions.redirectTo, route, state);
+ return false;
+ } else {
+ return false;
+ }
+ }
+ });
+ }
+
+ private passingOnlyPermissionsValidation(
+ permissions: NgxPermissionsRouterData, route: ActivatedRouteSnapshot | Route, state?: RouterStateSnapshot) {
+ if ((isFunction(permissions.redirectTo) ||
+ isPlainObject(permissions.redirectTo) && !this.isRedirectionWithParameters(permissions.redirectTo))) {
+ return this.onlyRedirectCheck(permissions, route, state);
+ }
+ return this.checkOnlyPermissions(permissions, route, state);
+ }
+
+}
+
+ =i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(Jo.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},Jo.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:d,empty:v,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),Jo.behavior={},Jo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Jo.event=null,Jo.requote=function(n){return n.replace(ha,"\\$&")};var ha=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ga={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},pa=function(n,t){return t.querySelector(n)},da=function(n,t){return t.querySelectorAll(n)},va=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(va=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(pa=function(n,t){return Sizzle(n,t)[0]||null},da=Sizzle,va=Sizzle.matchesSelector),Jo.selection=function(){return Jo.select(Qo.documentElement)};var ma=Jo.selection.prototype=[];ma.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o=0&&(e=n.slice(0,t),n=n.slice(t+1)),ya.hasOwnProperty(e)?{space:ya[e],local:n}:n}},ma.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Jo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},ma.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++u =0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=rc.get(e)||ec,r=uc.get(r)||y,Mu(r(e.apply(null,Go.call(arguments,1))))},Jo.interpolateHcl=Lu,Jo.interpolateHsl=Tu,Jo.interpolateLab=Ru,Jo.interpolateRound=Du,Jo.transform=function(n){var t=Qo.createElementNS(Jo.ns.prefix.svg,"g");return(Jo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:ic)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var ic={a:1,b:0,c:0,d:1,e:0,f:0};Jo.interpolateTransform=Hu,Jo.layout={},Jo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e
yr||V(i)){return r*Infinity}return r*i}};b(Math,mr);h(Math,"log1p",mr.log1p,Math.log1p(-1e-17)!==-1e-17);h(Math,"asinh",mr.asinh,Math.asinh(-1e7)!==-Math.asinh(1e7));h(Math,"tanh",mr.tanh,Math.tanh(-2e-17)!==-2e-17);h(Math,"acosh",mr.acosh,Math.acosh(Number.MAX_VALUE)===Infinity);h(Math,"cbrt",mr.cbrt,Math.abs(1-Math.cbrt(1e-300)/1e-100)/Number.EPSILON>8);h(Math,"sinh",mr.sinh,Math.sinh(-2e-17)!==-2e-17);var wr=Math.expm1(10);h(Math,"expm1",mr.expm1,wr>22025.465794806718||wr<22025.465794806718);var jr=Math.round;var Sr=Math.round(.5-Number.EPSILON/4)===0&&Math.round(-.5+Number.EPSILON/3.99)===1;var Tr=lr+1;var Ir=2*lr-1;var Er=[Tr,Ir].every(function(e){return Math.round(e)===e});h(Math,"round",function round(e){var t=_(e);var r=t===-1?-0:t+1;return e-t<.5?t:r},!Sr||!Er);O.preserveToString(Math.round,jr);var Pr=Math.imul;if(Math.imul(4294967295,5)!==-5){Math.imul=mr.imul;O.preserveToString(Math.imul,Pr)}if(Math.imul.length!==2){Z(Math,"imul",function imul(e,t){return re.Call(Pr,Math,arguments);
+})}var Cr=function(){var e=S.setTimeout;if(typeof e!=="function"&&typeof e!=="object"){return}re.IsPromise=function(e){if(!re.TypeIsObject(e)){return false}if(typeof e._promise==="undefined"){return false}return true};var r=function(e){if(!re.IsConstructor(e)){throw new TypeError("Bad promise constructor")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError("Bad Promise implementation!")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(re.IsCallable(t.resolve)&&re.IsCallable(t.reject))){throw new TypeError("Bad promise constructor")}};var n;if(typeof window!=="undefined"&&re.IsCallable(window.postMessage)){n=function(){var e=[];var t="zero-timeout-message";var r=function(r){M(e,r);window.postMessage(t,"*")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=N(e);n()}};window.addEventListener("message",n,true);return r}}var o=function(){var e=S.Promise;var t=e&&e.resolve&&e.resolve();return t&&function(e){return t.then(e)}};var i=re.IsCallable(S.setImmediate)?S.setImmediate:typeof process==="object"&&process.nextTick?process.nextTick:o()||(re.IsCallable(n)?n():function(t){e(t,0)});var a=function(e){return e};var u=function(e){throw e};var f=0;var s=1;var c=2;var l=0;var p=1;var v=2;var y={};var h=function(e,t,r){i(function(){g(e,t,r)})};var g=function(e,t,r){var n,o;if(t===y){return e(r)}try{n=e(r);o=t.resolve}catch(i){n=i;o=t.reject}o(n)};var d=function(e,t){var r=e._promise;var n=r.reactionLength;if(n>0){h(r.fulfillReactionHandler0,r.reactionCapability0,t);r.fulfillReactionHandler0=void 0;r.rejectReactions0=void 0;r.reactionCapability0=void 0;if(n>1){for(var o=1,i=0;o