common-ui/src/lib/permissions/services/permissions.service.ts
2023-03-19 13:58:34 +02:00

107 lines
3.5 KiB
TypeScript

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { isArray, isString, toArray } from '../utils';
import { IqserPermissions, PermissionValidationFn } from '../types';
import { List } from '../../utils';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class IqserPermissionsService {
readonly permissions$: Observable<IqserPermissions>;
readonly #permissions$ = new BehaviorSubject<IqserPermissions>({});
constructor() {
this.permissions$ = this.#permissions$.asObservable();
}
clear(): void {
this.#permissions$.next({});
}
has(permission: string): boolean;
has(permissions: List): boolean;
has(permissions: string | List): boolean;
has(permissions: string | List): boolean {
return this.#evaluate(permissions).every(result => result);
}
hasSome(permissions: List | string): boolean {
return this.#evaluate(permissions).some(result => result);
}
load(permissions: IqserPermissions | List) {
return this.#reduce(permissions);
}
add(permissions: string | List | IqserPermissions) {
const _permissions = isString(permissions) ? { [permissions]: () => true } : permissions;
return this.#reduce(_permissions, this.#permissions$.value);
}
remove(permission: string) {
const permissions = { ...this.#permissions$.value };
delete permissions[permission];
this.#permissions$.next(permissions);
}
get(): IqserPermissions;
get(permission: string): PermissionValidationFn | undefined;
get(permission?: string): IqserPermissions | PermissionValidationFn | undefined {
return permission ? this.#permissions$.value[permission] : this.#permissions$.value;
}
has$(permission: string): Observable<boolean>;
has$(permissions: List): Observable<boolean>;
has$(permissions: string | List): Observable<boolean>;
has$(permissions: string | List) {
const isEmpty = !permissions || permissions.length === 0;
if (isEmpty) {
return of(true);
}
return this.permissions$.pipe(
map(all => toArray(permissions).map(permission => all[permission]?.(permission, all) ?? false)),
map(results => results.every(result => result)),
);
}
#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));
}
return this.#permissions$.next(this.#reduceObject(permissions, initialValue));
}
#reduceObject(permissions: IqserPermissions, initialValue: IqserPermissions = {}) {
return Object.entries(permissions).reduce((acc, [permission, validationFn]) => {
return { ...acc, [permission]: validationFn };
}, initialValue);
}
#reduceList(permissions: List, initialValue: IqserPermissions = {}): IqserPermissions {
return permissions.reduce((acc, permission) => {
return { ...acc, [permission]: () => true };
}, initialValue);
}
}