Files
Picsur/frontend/src/app/models/forms/updateuser.control.ts

148 lines
3.7 KiB
TypeScript
Raw Normal View History

2022-03-23 17:17:39 +01:00
import { FormControl } from '@angular/forms';
import Fuse from 'fuse.js';
import { ERole } from 'picsur-shared/dist/entities/role.entity';
import { BehaviorSubject, Subscription } from 'rxjs';
2022-03-28 17:26:50 +02:00
import { FullUserModel } from '../forms-dto/fulluser.dto';
2022-03-23 17:17:39 +01:00
import {
CreatePasswordError,
CreateUsernameError,
PasswordValidators,
UsernameValidators
} from '../validators/user.validator';
2022-03-23 17:17:39 +01:00
export class UpdateUserControl {
2022-03-24 19:56:26 +01:00
// Special roles
private SoulBoundRolesList: string[] = [];
2022-03-23 17:17:39 +01:00
// Set once
private fullRoles: ERole[] = [];
private roles: string[] = [];
// Variables
private selectableRolesSubject = new BehaviorSubject<string[]>([]);
private rolesInputSubscription: null | Subscription;
public username = new FormControl('', UsernameValidators);
public password = new FormControl('', PasswordValidators);
public rolesControl = new FormControl('', []);
public selectableRoles = this.selectableRolesSubject.asObservable();
public selectedRoles: string[] = [];
public get usernameValue() {
return this.username.value;
}
public get usernameError() {
return CreateUsernameError(this.username.errors);
}
public get passwordError() {
return CreatePasswordError(this.password.errors);
}
constructor() {
this.rolesInputSubscription = this.rolesControl.valueChanges.subscribe(
(roles) => {
this.updateSelectableRoles();
}
);
}
public destroy() {
if (this.rolesInputSubscription) {
this.rolesInputSubscription.unsubscribe();
this.rolesInputSubscription = null;
}
}
public addRole(role: string) {
if (!this.selectableRolesSubject.value.includes(role)) return;
this.selectedRoles.push(role);
this.clearInput();
}
public removeRole(role: string) {
this.selectedRoles = this.selectedRoles.filter((r) => r !== role);
this.updateSelectableRoles();
}
public isRemovable(role: string) {
2022-03-24 19:56:26 +01:00
if (this.SoulBoundRolesList.includes(role)) return false;
2022-03-23 17:17:39 +01:00
return true;
}
public getEffectivePermissions(): string[] {
const permissions: string[] = [];
2022-03-23 19:29:40 +01:00
for (const role of this.selectedRoles) {
const fullRole = this.fullRoles.find((r) => r.name === role);
if (!fullRole) {
console.warn(`Role ${role} not found`);
continue;
}
permissions.push(
...fullRole.permissions.filter((p) => !permissions.includes(p))
);
}
return permissions;
}
2022-03-23 17:17:39 +01:00
// Data interaction
public putAllRoles(roles: ERole[]) {
this.fullRoles = roles;
this.roles = roles.map((role) => role.name);
this.updateSelectableRoles();
}
public putUsername(username: string) {
this.username.setValue(username);
}
public putRoles(roles: string[]) {
this.selectedRoles = roles;
this.updateSelectableRoles();
}
2022-03-24 19:56:26 +01:00
public putSoulBoundRoles(roles: string[]) {
this.SoulBoundRolesList = roles;
}
2022-03-23 17:17:39 +01:00
public getData(): FullUserModel {
return {
username: this.username.value,
password: this.password.value,
roles: this.selectedRoles,
};
}
// Logic
private updateSelectableRoles() {
const availableRoles = this.roles.filter(
// Not available if either already selected, or the role is not addable/removable
2022-03-24 19:56:26 +01:00
(r) =>
!(this.selectedRoles.includes(r) || this.SoulBoundRolesList.includes(r))
2022-03-23 17:17:39 +01:00
);
const searchValue = this.rolesControl.value;
if (searchValue && availableRoles.length > 0) {
const fuse = new Fuse(availableRoles);
const result = fuse
.search(this.rolesControl.value ?? '')
.map((r) => r.item);
this.selectableRolesSubject.next(result);
} else {
this.selectableRolesSubject.next(availableRoles);
}
}
private clearInput() {
this.rolesControl.setValue('');
}
}