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
|
2022-03-28 17:12:35 +02:00
|
|
|
} 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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 23:08:37 +01:00
|
|
|
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('');
|
|
|
|
|
}
|
|
|
|
|
}
|