Skip to content

Commit

Permalink
feat: extend the authorization service and directive to check against…
Browse files Browse the repository at this point in the history
… multiple permissions
  • Loading branch information
SGrueber committed Oct 22, 2021
1 parent 4eb6f24 commit b4d9c38
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { AuthorizationToggleModule } from 'ish-core/authorization-toggle.module'
<div *ishIsAuthorizedTo="'DO_THIS'">content1</div>
<div *ishIsAuthorizedTo="'DO_THAT'">content2</div>
<div *ishIsAuthorizedTo="dynamicPermission">content3</div>
<div *ishIsAuthorizedTo="['DO_THIS', 'DO_NOTHING']">content4</div>
<div *ishIsAuthorizedTo="['DO_THAT', 'DO_NOTHING']">content5</div>
`,
// Default change detection for dynamic permission test
changeDetection: ChangeDetectionStrategy.Default,
Expand Down Expand Up @@ -40,10 +42,12 @@ describe('Authorization Toggle Directive', () => {

it('should render content if permission is granted', () => {
expect(element.textContent).toContain('content1');
expect(element.textContent).toContain('content4');
});

it('should not render content if not permitted', () => {
expect(element.textContent).not.toContain('content2');
expect(element.textContent).not.toContain('content5');
});

it('should react on changing permissions in store', () => {
Expand Down
15 changes: 14 additions & 1 deletion src/app/core/directives/authorization-toggle.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ import { distinctUntilChanged, takeUntil } from 'rxjs/operators';

import { AuthorizationToggleService } from 'ish-core/utils/authorization-toggle/authorization-toggle.service';

/**
* Structural directive.
* Used on an element, this element will only be rendered if the logged in user has the specified permission or one of the specified permission in case an array is given.
*
* @example
* <div *ishIsAuthorizedTo="APP_B2B_PURCHASE'">
* Only visible when the current user is allowed to purchase items.
* </div>
* or
* <div *ishIsAuthorizedTo="['APP_B2B_ORDER_APPROVAL', 'APP_B2B_MANAGE_COSTCENTER']">
* Only visible when the current user has at least one of the given permissions.
* </div>
*/
@Directive({
selector: '[ishIsAuthorizedTo]',
})
Expand All @@ -29,7 +42,7 @@ export class AuthorizationToggleDirective implements OnDestroy {
});
}

@Input() set ishIsAuthorizedTo(permission: string) {
@Input() set ishIsAuthorizedTo(permission: string | string[]) {
// end previous subscription and subscribe to new permission
if (this.subscription) {
// tslint:disable-next-line: ban
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,24 @@ describe('Authorization Toggle Service', () => {
});

describe('isAuthorizedTo', () => {
it('should return true if user has permission', () => {
it('should return true if user has a given permission', () => {
expect(authorizationToggleService.isAuthorizedTo('DO_THIS')).toBeObservable(cold('a', { a: true }));
});

it("should return false if user doesn't have permission", () => {
it('should return true if user has one of the given permissions', () => {
expect(authorizationToggleService.isAuthorizedTo(['DO_THAT', 'DO_THIS'])).toBeObservable(cold('a', { a: true }));
});

it("should return false if user doesn't have the given permission", () => {
expect(authorizationToggleService.isAuthorizedTo('DO_THAT')).toBeObservable(cold('a', { a: false }));
});

it("should return false if user doesn't have any of the given permissions", () => {
expect(authorizationToggleService.isAuthorizedTo(['DO_THAT', 'DO_NOTHING'])).toBeObservable(
cold('a', { a: false })
);
});

it('should return shortcut true for permission "always"', () => {
expect(authorizationToggleService.isAuthorizedTo('always')).toBeObservable(cold('(a|)', { a: true }));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { map } from 'rxjs/operators';
import { getUserPermissions } from 'ish-core/store/customer/authorization';
import { whenTruthy } from 'ish-core/utils/operators';

export function checkPermission(permissions: string[], permission: string): boolean {
export function checkPermission(userPermissions: string[], permission: string | string[]): boolean {
if (permission === 'always') {
return true;
} else if (permission === 'never') {
return false;
} else {
return permissions.includes(permission);
// tslint:disable-next-line: no-parameter-reassignment
permission = typeof permission === 'string' ? [permission] : typeof permission === 'undefined' ? [] : permission;
return permission.some(id => userPermissions.includes(id));
}
}

Expand All @@ -24,7 +26,7 @@ export class AuthorizationToggleService {
this.permissions$ = store.pipe(select(getUserPermissions));
}

isAuthorizedTo(permission: string): Observable<boolean> {
isAuthorizedTo(permission: string | string[]): Observable<boolean> {
// special case shortcut
if (permission === 'always' || permission === 'never') {
return of(checkPermission([], permission));
Expand Down

0 comments on commit b4d9c38

Please sign in to comment.