diff --git a/src/lib/permissions/README.md b/src/lib/permissions/README.md
index 409e1da..40bd849 100644
--- a/src/lib/permissions/README.md
+++ b/src/lib/permissions/README.md
@@ -28,8 +28,8 @@ export class AppComponent implements OnInit {
You can see this text congrats
@@ -38,11 +38,24 @@ export class AppComponent implements OnInit {
You can see this text congrats
+----------------------------------------------
+
+
You cant see this text congrats
+
+
+
+ You cant see this text congrats
+
----------------------------------------------
@@ -57,7 +70,7 @@ export class AppComponent implements OnInit {
----------------------------------------------
-main
+main
elseBlock
diff --git a/src/lib/permissions/directives/allow/allow.directive.spec.ts b/src/lib/permissions/directives/allow/allow.directive.spec.ts
index 34bc3d7..ab9ba23 100644
--- a/src/lib/permissions/directives/allow/allow.directive.spec.ts
+++ b/src/lib/permissions/directives/allow/allow.directive.spec.ts
@@ -41,11 +41,13 @@ function getFixtureContent(): HTMLElement {
describe('Permission directive', () => {
@Component({
- template: `
- 123
- `,
+ template: `
+
+ 123
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -104,11 +106,13 @@ describe('Permission directive', () => {
describe('Permission directive with roles', () => {
@Component({
- template: `
- 123
- `,
+ template: `
+
+ 123
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
const awesomePermissions = 'AWESOME';
beforeEach(() => configureTestBed(TestComponent));
@@ -166,11 +170,13 @@ describe('Permission directive with roles', () => {
describe('Permission directive with roles array', () => {
@Component({
- template: `
- 123
- `,
+ template: `
+
+ 123
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
const awesomePermission = 'AWESOME';
beforeEach(() => configureTestBed(TestComponent));
@@ -221,11 +227,13 @@ describe('Permission directive with roles array', () => {
describe('Permission directive testing different selectors *allow', () => {
@Component({
- template: ` `,
+ template: `
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -249,15 +257,56 @@ describe('Permission directive testing different selectors *allow', () => {
expect(getFixtureContent()).toEqual(null);
}));
+
+ it('should hide the component when deny permission is added', fakeAsync(() => {
+ permissionsService.add(ADMIN);
+ tick();
+ const content = getFixtureContent();
+ expect(content).toBeTruthy();
+ expect(content.innerHTML).toEqual('123
');
+
+ permissionsService.add(GUEST);
+ tick();
+
+ expect(getFixtureContent()).toEqual(null);
+ }));
+
+ it('should hide the component when deny role is added', fakeAsync(() => {
+ permissionsService.add(ADMIN);
+ tick();
+ const content = getFixtureContent();
+ expect(content).toBeTruthy();
+ expect(content.innerHTML).toEqual('123
');
+
+ rolesService.add(GUEST);
+ tick();
+
+ expect(getFixtureContent()).toEqual(null);
+ }));
+
+ it('should show the component when deny permission is remove', fakeAsync(() => {
+ permissionsService.add([ADMIN, GUEST]);
+ tick();
+ expect(getFixtureContent()).toEqual(null);
+
+ permissionsService.remove(GUEST);
+ tick();
+
+ const content = getFixtureContent();
+ expect(content).toBeTruthy();
+ expect(content.innerHTML).toEqual('123
');
+ }));
});
describe('Permission directive angular testing different async functions in roles', () => {
@Component({
- template: ` `,
+ template: `
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -284,11 +333,13 @@ describe('Permission directive angular testing different async functions in role
describe('Permission directive angular testing different async functions in roles via array', () => {
@Component({
- template: ` `,
+ template: `
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -327,11 +378,13 @@ describe('Permission directive angular testing different async functions in role
describe('Permission directive with different async functions in permissions via array', () => {
@Component({
- template: ` `,
+ template: `
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -390,11 +443,13 @@ describe('Permission directive with different async functions in permissions via
describe('Permission directive testing different async functions in permissions via string', () => {
@Component({
- template: ` `,
+ template: `
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -472,7 +527,8 @@ describe('Permissions directive with else block', () => {
`,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -513,7 +569,8 @@ describe('Permissions directive with then block', () => {
`,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -535,7 +592,8 @@ describe('Permissions directive with empty argument', () => {
`,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -554,7 +612,8 @@ describe('Permissions directive with an empty array', () => {
`,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -567,11 +626,13 @@ describe('Permissions directive with an empty array', () => {
describe('Permission directive with true if condition', () => {
@Component({
- template: `
- 123
- `,
+ template: `
+
+ 123
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -591,11 +652,13 @@ describe('Permission directive with true if condition', () => {
describe('Permission directive with true if condition', () => {
@Component({
- template: `
- 123
- `,
+ template: `
+
+ 123
+ `,
})
- class TestComponent extends BaseTestComponent {}
+ class TestComponent extends BaseTestComponent {
+ }
beforeEach(() => configureTestBed(TestComponent));
@@ -613,9 +676,10 @@ describe('Permission directive with true if condition', () => {
describe('Permission directive with true promise if condition', () => {
@Component({
- template: `
- 123
- `,
+ template: `
+
+ 123
+ `,
})
class TestComponent extends BaseTestComponent {
condition = Promise.resolve(true);
@@ -639,9 +703,10 @@ describe('Permission directive with true promise if condition', () => {
describe('Permission directive with false promise if condition', () => {
@Component({
- template: ` `,
+ template: `
+ `,
})
class TestComponent extends BaseTestComponent {
condition = Promise.resolve(false);
@@ -718,9 +783,10 @@ describe('Permissions directive with then block and if condition', () => {
describe('Permission directive with false promise, if condition and change detection on push', () => {
@Component({
- template: ` `,
+ template: `
+ `,
changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestComponent extends BaseTestComponent {
@@ -740,7 +806,7 @@ describe('Permission directive with false promise, if condition and change detec
expect(getFixtureContent()).toEqual(null);
}));
- it('should show else block when permission is missing and condition is false', fakeAsync(() => {
+ it('should show component when permission is added and condition is true', fakeAsync(() => {
permissionsService.add(ADMIN);
(fixture.componentInstance as TestComponent).condition.next(true);
tick();
@@ -749,4 +815,19 @@ describe('Permission directive with false promise, if condition and change detec
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`123
`);
}));
+
+ it('should hide component when permission is present, condition is true and deny permission is present', fakeAsync(() => {
+ permissionsService.add(ADMIN);
+ (fixture.componentInstance as TestComponent).condition.next(true);
+ tick();
+
+ const content = getFixtureContent();
+ expect(content).toBeTruthy();
+ expect(content.innerHTML).toEqual(`123
`);
+
+ permissionsService.add(GUEST);
+ tick();
+
+ expect(getFixtureContent()).toEqual(null);
+ }));
});
diff --git a/src/lib/permissions/directives/allow/allow.directive.ts b/src/lib/permissions/directives/allow/allow.directive.ts
index 74b69bf..7b5a3d3 100644
--- a/src/lib/permissions/directives/allow/allow.directive.ts
+++ b/src/lib/permissions/directives/allow/allow.directive.ts
@@ -18,6 +18,7 @@ export class IqserAllowDirective extends IqserPermissionsDirective implements On
* narrow its type, which allows the strictNullChecks feature of TypeScript to work with `IqserPermissionsDirective`.
*/
static ngTemplateGuard_allow: 'binding';
+ #deny?: string | List;
constructor(templateRef: TemplateRef) {
super(templateRef);
@@ -40,8 +41,35 @@ export class IqserAllowDirective extends IqserPermissionsDirective implements On
this.setElseTemplateRef(template);
}
+ @Input()
+ set allowDeny(value: string | List) {
+ this.#deny = value;
+ this._updateView.next();
+ }
+
@Input()
set allowIf(value: boolean | Promise | Observable) {
this.setIf(value);
}
+
+ get #hasDenyPermission() {
+ if (!this.#deny) {
+ return false;
+ }
+
+ return this._permissionsService.hasSome(this.#deny) || this._rolesService.hasSome(this.#deny);
+ }
+
+ protected override _validate() {
+ const hasDenyPermission = this.#hasDenyPermission;
+ if (!this._permissions) {
+ return !hasDenyPermission;
+ }
+
+ if (hasDenyPermission) {
+ return false;
+ }
+
+ return this._permissionsService.has(this._permissions) || this._rolesService.has(this._permissions);
+ }
}
diff --git a/src/lib/permissions/directives/deny/deny.directive.ts b/src/lib/permissions/directives/deny/deny.directive.ts
index cfa85cc..7e55fa6 100644
--- a/src/lib/permissions/directives/deny/deny.directive.ts
+++ b/src/lib/permissions/directives/deny/deny.directive.ts
@@ -50,6 +50,6 @@ export class IqserDenyDirective extends IqserPermissionsDirective implements OnD
return true;
}
- return !(this._permissionsService.hasAtLeastOne(this._permissions) || this._rolesService.hasAtLeastOne(this._permissions));
+ return !(this._permissionsService.hasSome(this._permissions) || this._rolesService.hasSome(this._permissions));
}
}
diff --git a/src/lib/permissions/services/permissions.service.ts b/src/lib/permissions/services/permissions.service.ts
index fa7555c..f2f8529 100644
--- a/src/lib/permissions/services/permissions.service.ts
+++ b/src/lib/permissions/services/permissions.service.ts
@@ -24,25 +24,11 @@ export class IqserPermissionsService {
has(permissions: List): boolean;
has(permissions: string | List): boolean;
has(permissions: string | List): boolean {
- const isEmpty = !permissions || permissions.length === 0;
- if (isEmpty) {
- return true;
- }
-
- const all = this.#permissions$.value;
- const results = toArray(permissions).map(permission => all[permission]?.(permission, all) ?? false);
- return results.every(result => result);
+ return this.#evaluate(permissions).every(result => result);
}
- hasAtLeastOne(permissions: List | string): boolean {
- const isEmpty = !permissions || permissions.length === 0;
- if (isEmpty) {
- return true;
- }
-
- const all = this.#permissions$.value;
- const results = toArray(permissions).map(permission => all[permission]?.(permission, all) ?? false);
- return results.some(result => result);
+ hasSome(permissions: List | string): boolean {
+ return this.#evaluate(permissions).some(result => result);
}
load(permissions: IqserPermissions | List) {
@@ -69,8 +55,11 @@ export class IqserPermissionsService {
}
has$(permission: string): Observable;
+
has$(permissions: List): Observable;
+
has$(permissions: string | List): Observable;
+
has$(permissions: string | List) {
const isEmpty = !permissions || permissions.length === 0;
if (isEmpty) {
@@ -83,6 +72,16 @@ export class IqserPermissionsService {
);
}
+ #evaluate(permissions: List | string) {
+ const isEmpty = !permissions || permissions.length === 0;
+ if (isEmpty) {
+ return [true];
+ }
+
+ const all = this.#permissions$.value;
+ return toArray(permissions).map(permission => all[permission]?.(permission, all) ?? false);
+ }
+
#reduce(permissions: IqserPermissions | List, initialValue = {} as IqserPermissions) {
if (isArray(permissions)) {
return this.#permissions$.next(this.#reduceList(permissions, initialValue));
diff --git a/src/lib/permissions/services/roles.service.ts b/src/lib/permissions/services/roles.service.ts
index c45863f..ca5f3be 100644
--- a/src/lib/permissions/services/roles.service.ts
+++ b/src/lib/permissions/services/roles.service.ts
@@ -41,25 +41,22 @@ export class IqserRolesService {
}
has(roles: string | List): boolean {
- const isEmpty = !roles || roles.length === 0;
-
- if (isEmpty) {
- return true;
- }
-
- const validations = toArray(roles).map(role => this.#runValidation(role));
- return this.#checkPermissionsIfNeeded(validations).every(result => result);
+ const results = this.#evaluate(roles);
+ return this.#checkPermissionsIfNeeded(results).every(result => result);
}
- hasAtLeastOne(roles: string | List): boolean {
- const isEmpty = !roles || roles.length === 0;
+ hasSome(roles: string | List): boolean {
+ const results = this.#evaluate(roles);
+ return this.#checkPermissionsIfNeeded(results).some(result => result);
+ }
+ #evaluate(roles: string | List) {
+ const isEmpty = !roles || roles.length === 0;
if (isEmpty) {
- return true;
+ return [true];
}
- const validations = toArray(roles).map(role => this.#runValidation(role));
- return this.#checkPermissionsIfNeeded(validations).some(result => result);
+ return toArray(roles).map(role => this.#runValidation(role));
}
#checkPermissionsIfNeeded(results: List) {