176 lines
4.4 KiB
TypeScript
176 lines
4.4 KiB
TypeScript
import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl, IsUUID } from "class-validator";
|
|
import { ChildEntity, Column, JoinTable, ManyToMany, OneToMany } from "typeorm";
|
|
import { config } from '../../config';
|
|
import { ResponsePrincipal } from '../responses/ResponsePrincipal';
|
|
import { ResponseUser } from '../responses/ResponseUser';
|
|
import { Permission } from './Permission';
|
|
import { Principal } from './Principal';
|
|
import { UserAction } from './UserAction';
|
|
import { UserGroup } from './UserGroup';
|
|
|
|
/**
|
|
* Defines the User entity.
|
|
* Users are the ones that can use the "admin" webui and do stuff in the backend.
|
|
*/
|
|
@ChildEntity()
|
|
export class User extends Principal {
|
|
/**
|
|
* The user's uuid.
|
|
* Mainly gets used as a per-user salt for the password hash.
|
|
*/
|
|
@Column({ unique: true })
|
|
@IsUUID(4)
|
|
uuid: string;
|
|
|
|
/**
|
|
* The user's e-mail address.
|
|
* Either username or email has to be set (otherwise the user couldn't log in).
|
|
*/
|
|
@Column({ nullable: false, unique: true })
|
|
@IsEmail()
|
|
@IsNotEmpty()
|
|
email: string;
|
|
|
|
/**
|
|
* The user's phone number.
|
|
*/
|
|
@Column({ nullable: true })
|
|
@IsOptional()
|
|
@IsPhoneNumber(config.phone_validation_countrycode)
|
|
phone?: string;
|
|
|
|
/**
|
|
* The user's username.
|
|
* Either username or email has to be set (otherwise the user couldn't log in).
|
|
*/
|
|
@Column({ nullable: true, unique: true })
|
|
@IsString()
|
|
username?: string;
|
|
|
|
/**
|
|
* The user's first name.
|
|
*/
|
|
@Column()
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
firstname: string;
|
|
|
|
/**
|
|
* The user's middle name.
|
|
*/
|
|
@Column({ nullable: true })
|
|
@IsString()
|
|
@IsOptional()
|
|
middlename?: string;
|
|
|
|
/**
|
|
* The user's last name.
|
|
*/
|
|
@Column()
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
lastname: string;
|
|
|
|
/**
|
|
* The user's password.
|
|
* This is a argon2 hash salted with the user's uuid.
|
|
*/
|
|
@Column()
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
password: string;
|
|
|
|
/**
|
|
* The groups this user is a part of.
|
|
* The user will inherit the groups permissions (without overwriting his own).
|
|
*/
|
|
@IsOptional()
|
|
@ManyToMany(() => UserGroup, { nullable: true })
|
|
@JoinTable()
|
|
groups: UserGroup[];
|
|
|
|
/**
|
|
* Is this user enabled?
|
|
*/
|
|
@Column()
|
|
@IsBoolean()
|
|
enabled: boolean = true;
|
|
|
|
/**
|
|
* The user's jwt refresh token count.
|
|
* Used to invalidate jwts.
|
|
*/
|
|
@IsInt()
|
|
@Column({ default: 1 })
|
|
refreshTokenCount?: number;
|
|
|
|
/**
|
|
* The user's profile picture.
|
|
* We haven't decided yet if this will be a bas64 encoded image or just a link to the profile picture.
|
|
*/
|
|
@Column({ nullable: false, unique: false })
|
|
@IsString()
|
|
@IsUrl()
|
|
profilePic: string;
|
|
|
|
/**
|
|
* The last time the user requested a password reset.
|
|
* Used to prevent spamming of the password reset route.
|
|
*/
|
|
@Column({ nullable: true, unique: false })
|
|
@IsString()
|
|
@IsOptional()
|
|
resetRequestedTimestamp?: number;
|
|
|
|
/**
|
|
* The actions performed by this user.
|
|
* For documentation purposes only, will be implemented later.
|
|
*/
|
|
@IsOptional()
|
|
@OneToMany(() => UserAction, action => action.user, { nullable: true })
|
|
actions: UserAction[]
|
|
|
|
/**
|
|
* Resolves all permissions granted to this user through groups.
|
|
*/
|
|
public get inheritedPermissions(): Permission[] {
|
|
let returnPermissions: Permission[] = new Array<Permission>();
|
|
|
|
if (!this.groups) { return returnPermissions; }
|
|
for (let group of this.groups) {
|
|
for (let permission of group.permissions) {
|
|
returnPermissions.push(permission);
|
|
}
|
|
}
|
|
return returnPermissions;
|
|
}
|
|
|
|
/**
|
|
* Resolves all permissions granted to this user through groups or directly to the string enum format.
|
|
* Also deduplicates the array.
|
|
*/
|
|
public get allPermissions(): string[] {
|
|
let returnPermissions: string[] = new Array<string>();
|
|
|
|
if (!this.permissions) { return returnPermissions; }
|
|
for (let permission of this.permissions) {
|
|
returnPermissions.push(permission.toString());
|
|
}
|
|
|
|
if (!this.groups) { return returnPermissions; }
|
|
for (let group of this.groups) {
|
|
for (let permission of group.permissions) {
|
|
returnPermissions.push(permission.toString());
|
|
}
|
|
}
|
|
return Array.from(new Set(returnPermissions));
|
|
}
|
|
|
|
/**
|
|
* Turns this entity into it's response class.
|
|
*/
|
|
public toResponse(): ResponsePrincipal {
|
|
return new ResponseUser(this);
|
|
}
|
|
}
|