Merge pull request 'Fixed a bug concerning user updates' (#38) from bugfix/37-user_update into dev
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Reviewed-on: #38 closes #37
This commit is contained in:
		| @@ -1,10 +1,10 @@ | ||||
| import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; | ||||
| import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; | ||||
| import { getConnectionManager, Repository } from 'typeorm'; | ||||
| import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; | ||||
| import { UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; | ||||
| import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; | ||||
| import { CreateUser } from '../models/actions/CreateUser'; | ||||
| import { UpdateUser } from '../models/actions/UpdateUser'; | ||||
| import { User } from '../models/entities/User'; | ||||
| import { ResponseEmpty } from '../models/responses/ResponseEmpty'; | ||||
| import { ResponseUser } from '../models/responses/ResponseUser'; | ||||
| @@ -71,18 +71,21 @@ export class UserController { | ||||
| 	@ResponseSchema(UserNotFoundError, { statusCode: 404 }) | ||||
| 	@ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 }) | ||||
| 	@OpenAPI({ description: "Update a user object (id can't be changed)." }) | ||||
| 	async put(@Param('id') id: number, @EntityFromBody() user: User) { | ||||
| 		let oldUser = await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups'] }); | ||||
| 	async put(@Param('id') id: number, @Body({ validate: true }) updateUser: UpdateUser) { | ||||
| 		let oldUser = await this.userRepository.findOne({ id: id }); | ||||
| 		delete oldUser.permissions; | ||||
| 		delete oldUser.groups; | ||||
| 		delete oldUser.actions; | ||||
|  | ||||
| 		if (!oldUser) { | ||||
| 			throw new UserNotFoundError(); | ||||
| 		} | ||||
|  | ||||
| 		if (oldUser.id != user.id) { | ||||
| 		if (oldUser.id != updateUser.id) { | ||||
| 			throw new UserIdsNotMatchingError(); | ||||
| 		} | ||||
| 		await this.userRepository.save(await updateUser.toUser(oldUser)); | ||||
|  | ||||
| 		await this.userRepository.update(oldUser, user); | ||||
| 		return new ResponseUser(await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups'] })); | ||||
| 	} | ||||
|  | ||||
| @@ -91,7 +94,7 @@ export class UserController { | ||||
| 	@ResponseSchema(User) | ||||
| 	@ResponseSchema(ResponseEmpty, { statusCode: 204 }) | ||||
| 	@OnUndefined(204) | ||||
| 	@OpenAPI({ description: 'Delete a specified runner (if it exists).' }) | ||||
| 	@OpenAPI({ description: 'Delete a user runner (if it exists).' }) | ||||
| 	async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { | ||||
| 		let user = await this.userRepository.findOne({ id: id }); | ||||
| 		if (!user) { return null; } | ||||
|   | ||||
| @@ -67,7 +67,7 @@ export class CreateUser { | ||||
|      * Optional. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     group?: number[] | number | ||||
|     groups?: number[] | number | ||||
|  | ||||
|     //TODO: ProfilePics | ||||
|  | ||||
| @@ -95,13 +95,16 @@ export class CreateUser { | ||||
|         return newUser; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get's all groups for this user by their id's; | ||||
|      */ | ||||
|     public async getGroups() { | ||||
|         if (!this.group) { return null; } | ||||
|         if (!this.groups) { return null; } | ||||
|         let groups = new Array<UserGroup>(); | ||||
|         if (!Array.isArray(this.group)) { | ||||
|             this.group = [this.group] | ||||
|         if (!Array.isArray(this.groups)) { | ||||
|             this.groups = [this.groups] | ||||
|         } | ||||
|         for (let group of this.group) { | ||||
|         for (let group of this.groups) { | ||||
|             let found = await getConnectionManager().get().getRepository(UserGroup).findOne({ id: group }); | ||||
|             if (!found) { throw new UserGroupNotFoundError(); } | ||||
|             groups.push(found); | ||||
|   | ||||
							
								
								
									
										123
									
								
								src/models/actions/UpdateUser.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/models/actions/UpdateUser.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| import * as argon2 from "argon2"; | ||||
| import { IsBoolean, IsEmail, IsInt, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { config } from '../../config'; | ||||
| import { UsernameOrEmailNeededError } from '../../errors/AuthError'; | ||||
| import { RunnerGroupNotFoundError } from '../../errors/RunnerGroupErrors'; | ||||
| import { User } from '../entities/User'; | ||||
| import { UserGroup } from '../entities/UserGroup'; | ||||
|  | ||||
| export class UpdateUser { | ||||
|  | ||||
|     /** | ||||
|      * The updated users's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The updated user's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The updated user's middle name. | ||||
|      * Optinal. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The updated user's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The updated user's username. | ||||
|      * You have to provide at least one of: {email, username}. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsString() | ||||
|     username?: string; | ||||
|  | ||||
|     /** | ||||
|      * The updated user's email address. | ||||
|      * You have to provide at least one of: {email, username}. | ||||
|      */ | ||||
|     @IsEmail() | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * The updated user's phone number. | ||||
|      * Optional | ||||
|      */ | ||||
|     @IsPhoneNumber(config.phone_validation_countrycode) | ||||
|     @IsOptional() | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new updated's password. Only provide if you want it updated. | ||||
|      * This will of course not be saved in plaintext :) | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     password?: string; | ||||
|  | ||||
|     /** | ||||
|      * Should the user be enabled? | ||||
|      */ | ||||
|     @IsBoolean() | ||||
|     enabled: boolean = true; | ||||
|  | ||||
|     /** | ||||
|      * The new user's groups' id(s). | ||||
|      * You can provide either one groupId or an array of groupIDs. | ||||
|      * Optional. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     groups?: UserGroup[] | ||||
|  | ||||
|     /** | ||||
|      * Creates a User entity from this. | ||||
|      */ | ||||
|     public async toUser(user: User): Promise<User> { | ||||
|         user.email = this.email; | ||||
|         user.username = this.username; | ||||
|         if (user.email === undefined && user.username === undefined) { | ||||
|             throw new UsernameOrEmailNeededError(); | ||||
|         } | ||||
|         if (this.password) { | ||||
|             user.password = await argon2.hash(this.password + user.uuid); | ||||
|             user.refreshTokenCount = user.refreshTokenCount + 1; | ||||
|         } | ||||
|  | ||||
|         user.enabled = this.enabled; | ||||
|         user.firstname = this.firstname | ||||
|         user.middlename = this.middlename | ||||
|         user.lastname = this.lastname | ||||
|         user.phone = this.phone; | ||||
|         user.groups = await this.getGroups(); | ||||
|         //TODO: ProfilePics | ||||
|  | ||||
|         return user; | ||||
|     } | ||||
|  | ||||
|     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.id }); | ||||
|             if (!found) { throw new RunnerGroupNotFoundError(); } | ||||
|             groups.push(found); | ||||
|         } | ||||
|         return groups; | ||||
|     } | ||||
| } | ||||
| @@ -29,7 +29,7 @@ export default class SeedUsers implements Seeder { | ||||
|         initialUser.lastname = "demo"; | ||||
|         initialUser.username = "demo"; | ||||
|         initialUser.password = "demo"; | ||||
|         initialUser.group = group; | ||||
|         initialUser.groups = group; | ||||
|         return await connection.getRepository(User).save(await initialUser.toUser()); | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user