139 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { hash } from "@node-rs/argon2";
 | |
| import { passwordStrength } from "check-password-strength";
 | |
| import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
 | |
| import { getConnectionManager } from 'typeorm';
 | |
| import * as uuid from 'uuid';
 | |
| import { config } from '../../../config';
 | |
| import { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, UserEmailNeededError, UsernameContainsIllegalCharacterError } from '../../../errors/UserErrors';
 | |
| import { UserGroupNotFoundError } from '../../../errors/UserGroupErrors';
 | |
| import { User } from '../../entities/User';
 | |
| import { UserGroup } from '../../entities/UserGroup';
 | |
| 
 | |
| /**
 | |
|  * This classed is used to create a new User entity from a json body (post request).
 | |
|  */
 | |
| export class CreateUser {
 | |
|     /**
 | |
|      * The new user's first name.
 | |
|      */
 | |
|     @IsString()
 | |
|     firstname: string;
 | |
| 
 | |
|     /**
 | |
|      * The new user's middle name.
 | |
|      */
 | |
|     @IsString()
 | |
|     @IsOptional()
 | |
|     middlename?: string;
 | |
| 
 | |
|     /**
 | |
|      * The new user's last name.
 | |
|      */
 | |
|     @IsString()
 | |
|     lastname: string;
 | |
| 
 | |
|     /**
 | |
|      * The new user's username.
 | |
|      * You have to provide a email addres, so this is optional.
 | |
|      */
 | |
|     @IsOptional()
 | |
|     @IsString()
 | |
|     username?: string;
 | |
| 
 | |
|     /**
 | |
|      * The new user's email address.
 | |
|      */
 | |
|     @IsEmail()
 | |
|     @IsString()
 | |
|     @IsNotEmpty()
 | |
|     email: string;
 | |
| 
 | |
|     /**
 | |
|      * The new user's phone number.
 | |
|      * This will be validated against the configured country phone numer syntax (default: international).
 | |
|      */
 | |
|     @IsPhoneNumber(config.phone_validation_countrycode)
 | |
|     @IsOptional()
 | |
|     phone?: string;
 | |
| 
 | |
|     /**
 | |
|      * The new user's password.
 | |
|      * This will of course not be saved in plaintext :)
 | |
|      */
 | |
|     @IsString()
 | |
|     password: string;
 | |
| 
 | |
|     /**
 | |
|      * Will the new user be enabled from the start?
 | |
|      * Default: true
 | |
|      */
 | |
|     @IsBoolean()
 | |
|     @IsOptional()
 | |
|     enabled?: boolean = true;
 | |
| 
 | |
|     /**
 | |
|      * The new user's groups' ids.
 | |
|      * You can provide either one groupId or an array of groupIDs.
 | |
|      */
 | |
|     @IsOptional()
 | |
|     groups?: number[] | number
 | |
| 
 | |
|     /**
 | |
|     * The user's profile pic (or rather a url pointing to it).
 | |
|     */
 | |
|     @IsString()
 | |
|     @IsUrl()
 | |
|     @IsOptional()
 | |
|     profilePic?: string;
 | |
| 
 | |
|     /**
 | |
|      * Converts this to a User entity.
 | |
|      */
 | |
|     public async toEntity(): Promise<User> {
 | |
|         let newUser: User = new User();
 | |
| 
 | |
|         if (!this.email) {
 | |
|             throw new UserEmailNeededError();
 | |
|         }
 | |
|         if (this.username?.includes("@")) { throw new UsernameContainsIllegalCharacterError(); }
 | |
| 
 | |
|         let password_strength = passwordStrength(this.password);
 | |
|         if (!password_strength.contains.includes("uppercase")) { throw new PasswordMustContainUppercaseLetterError(); }
 | |
|         if (!password_strength.contains.includes("lowercase")) { throw new PasswordMustContainLowercaseLetterError(); }
 | |
|         if (!password_strength.contains.includes("number")) { throw new PasswordMustContainNumberError(); }
 | |
|         if (!(password_strength.length > 9)) { throw new PasswordTooShortError(); }
 | |
| 
 | |
|         newUser.email = this.email
 | |
|         newUser.username = this.username
 | |
|         newUser.firstname = this.firstname
 | |
|         newUser.middlename = this.middlename
 | |
|         newUser.lastname = this.lastname
 | |
|         newUser.uuid = uuid.v4()
 | |
|         newUser.phone = this.phone
 | |
|         newUser.password = await hash(this.password + newUser.uuid);
 | |
|         newUser.groups = await this.getGroups();
 | |
|         newUser.enabled = this.enabled;
 | |
| 
 | |
|         if (!this.profilePic) { newUser.profilePic = `https://lauf-fuer-kaya.de/lfk-logo.png`; }
 | |
|         else { newUser.profilePic = this.profilePic; }
 | |
| 
 | |
|         return newUser;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get's all groups for this user by their id's;
 | |
|      */
 | |
|     public async getGroups() {
 | |
|         if (!this.groups) { return null; }
 | |
|         let groups = new Array<UserGroup>();
 | |
|         if (!Array.isArray(this.groups)) {
 | |
|             this.groups = [this.groups]
 | |
|         }
 | |
|         for (let group of this.groups) {
 | |
|             let found = await getConnectionManager().get().getRepository(UserGroup).findOne({ id: group });
 | |
|             if (!found) { throw new UserGroupNotFoundError(); }
 | |
|             groups.push(found);
 | |
|         }
 | |
|         return groups;
 | |
|     }
 | |
| } |