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);
}
}