Merge pull request 'Alpha Release 0.1.1 - Hotfix release' (#106) from dev into main
Reviewed-on: #106 Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
This commit is contained in:
		
							
								
								
									
										20
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								.drone.yml
									
									
									
									
									
								
							| @@ -90,11 +90,20 @@ trigger: | ||||
| kind: pipeline | ||||
| type: docker | ||||
| name: build:latest | ||||
| clone: | ||||
|   disable: true | ||||
|  | ||||
| steps: | ||||
|   - name: clone | ||||
|     image: alpine/git | ||||
|     commands: | ||||
|       - git clone $DRONE_REMOTE_URL . | ||||
|       - git checkout dev | ||||
|       - git merge main | ||||
|       - git checkout main | ||||
|   - name: build latest | ||||
|     depends_on: ["clone"] | ||||
|     image: plugins/docker | ||||
|     depends_on: [clone] | ||||
|     settings: | ||||
|       username: | ||||
|         from_secret: DOCKER_REGISTRY_USER | ||||
| @@ -104,6 +113,15 @@ steps: | ||||
|       tags: | ||||
|         - latest | ||||
|       registry: registry.odit.services | ||||
|   - name: push merge to repo | ||||
|     depends_on: ["clone"] | ||||
|     image: appleboy/drone-git-push | ||||
|     settings: | ||||
|       branch: dev | ||||
|       commit: false | ||||
|       remote: git@git.odit.services:lfk/backend.git | ||||
|       ssh_key: | ||||
|         from_secret: GITLAB_SSHKEY | ||||
|  | ||||
| trigger: | ||||
|   branch: | ||||
|   | ||||
							
								
								
									
										25
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,8 +2,32 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||
|  | ||||
| #### [v0.1.1](https://git.odit.services/lfk/backend/compare/v0.1.0...v0.1.1) | ||||
|  | ||||
| - 🚀Bumped version to v0.1.1 [`9445c6f`](https://git.odit.services/lfk/backend/commit/9445c6f21e376329b9200664a44a94ba1f1dd463) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`1b9d296`](https://git.odit.services/lfk/backend/commit/1b9d2969ebdca4dca84898b1e8307be7b781b90b) | ||||
| - Implemented the /me controller that allows a user to get and update themselves [`8ef5f90`](https://git.odit.services/lfk/backend/commit/8ef5f90abda97a73d5c5a7767a144ac3fb5288c1) | ||||
| - Implemented a baisc user checker/getter [`f1db883`](https://git.odit.services/lfk/backend/commit/f1db8836092269966a7f54e69b1f20c171e81b21) | ||||
| - Implemented getting own permissions [`4f6e816`](https://git.odit.services/lfk/backend/commit/4f6e81677c81c852e735407295c634b43b317479) | ||||
| - Hotfix: Missing relation bug [`6e6979c`](https://git.odit.services/lfk/backend/commit/6e6979cfe3660056cff6b9eabc194852234ac0a6) | ||||
| - Hotfix: Missing relation bug [`b167ba0`](https://git.odit.services/lfk/backend/commit/b167ba07f79709a2c3b33c5546c52659c42863f3) | ||||
| - automaticly merge main into dev after building a latest image [`02efb9a`](https://git.odit.services/lfk/backend/commit/02efb9a8e55831ecce4109e17b2f07a56e491fd5) | ||||
| - User deletion now requires confirmation [`6b7ecd3`](https://git.odit.services/lfk/backend/commit/6b7ecd3044c45b2eed46ee5010bed4dab4f02df9) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`3766899`](https://git.odit.services/lfk/backend/commit/3766899c8393545a89986a98dafd542edc4a1d39) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`6febb99`](https://git.odit.services/lfk/backend/commit/6febb994990b4cab7ee54b0368f74dd95664bfdf) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`de36a24`](https://git.odit.services/lfk/backend/commit/de36a24191a8cdc4ff6b23637ea9f91109b59bbb) | ||||
| - Merge pull request 'User self-management feature/100-me_endpoints' (#103) from feature/100-me_endpoints into dev [`a6c7d54`](https://git.odit.services/lfk/backend/commit/a6c7d54fe72ffe23add926afa0be150a7a370099) | ||||
| - Created barebones file for the userchecker [`e586a11`](https://git.odit.services/lfk/backend/commit/e586a11e2ad42af9c9bb5d2a47f48e3306fe49b2) | ||||
| - Updated descriptions and responses [`fc7b8f4`](https://git.odit.services/lfk/backend/commit/fc7b8f4c16cef0e72b04f096d5a17d4144b5feb7) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`50b893f`](https://git.odit.services/lfk/backend/commit/50b893f5370902ccc40f8bb45ed160103400f529) | ||||
| - Moved the me endpoints to /users/me [`f9834b5`](https://git.odit.services/lfk/backend/commit/f9834b5f4d80b11ee5f7773b339dd421341c6e7f) | ||||
| - Moved optional param to being optional [`a334adf`](https://git.odit.services/lfk/backend/commit/a334adffc6d07c8ab340263123e00a96f21acecb) | ||||
|  | ||||
| #### [v0.1.0](https://git.odit.services/lfk/backend/compare/v0.0.12...v0.1.0) | ||||
|  | ||||
| > 15 January 2021 | ||||
|  | ||||
| - Merge pull request 'First feature version 0.1.0' (#102) from dev into main [`38b9a77`](https://git.odit.services/lfk/backend/commit/38b9a772cd2d1c1e6298ae449d07db7c555a00e9) | ||||
| - Removed useless parts from functions and updated comments [`c05834f`](https://git.odit.services/lfk/backend/commit/c05834f2a13eb838efbf61be803e4e320561718e) | ||||
| - Switched tests over to the new id-only schema [`d88fb18`](https://git.odit.services/lfk/backend/commit/d88fb183198e66cadf5290c1ef7b7e4ccedad4f0) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`0e119e4`](https://git.odit.services/lfk/backend/commit/0e119e48340cd0a602a08da727b480aa2fe5500c) | ||||
| @@ -24,6 +48,7 @@ All notable changes to this project will be documented in this file. Dates are d | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`dc6ad9c`](https://git.odit.services/lfk/backend/commit/dc6ad9cdd3d8f29ef9a15bf7ac61c7c55c57e9fb) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`d1a0bed`](https://git.odit.services/lfk/backend/commit/d1a0bed00e01a0e9d8ba1165e3c6ca3dd910bd00) | ||||
| - Clarified comments [`1b799a6`](https://git.odit.services/lfk/backend/commit/1b799a697305791c3f67ac4a738c7287d1ac553e) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`6184304`](https://git.odit.services/lfk/backend/commit/618430433d03012c2cad5be6021cf1ea8fdf9624) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`8218a45`](https://git.odit.services/lfk/backend/commit/8218a452bdf7550ec1eed2b0045e94ea4ae91d31) | ||||
| - 🚀Bumped version to v0.1.0 [`80c5f9b`](https://git.odit.services/lfk/backend/commit/80c5f9b84de355b4408dcffd632589a9a0e4ad2e) | ||||
| - 🧾New changelog file version [CI SKIP] [skip ci] [`79f46cb`](https://git.odit.services/lfk/backend/commit/79f46cb745e4cb4bdac7dbb6c6c2b8fdc9867592) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@odit/lfk-backend", | ||||
|   "version": "0.1.0", | ||||
|   "version": "0.1.1", | ||||
|   "main": "src/app.ts", | ||||
|   "repository": "https://git.odit.services/lfk/backend", | ||||
|   "author": { | ||||
|   | ||||
| @@ -5,10 +5,12 @@ import { config, e as errors } from './config'; | ||||
| import loaders from "./loaders/index"; | ||||
| import authchecker from "./middlewares/authchecker"; | ||||
| import { ErrorHandler } from './middlewares/ErrorHandler'; | ||||
| import UserChecker from './middlewares/UserChecker'; | ||||
|  | ||||
| const CONTROLLERS_FILE_EXTENSION = process.env.NODE_ENV === 'production' ? 'js' : 'ts'; | ||||
| const app = createExpressServer({ | ||||
|   authorizationChecker: authchecker, | ||||
|   currentUserChecker: UserChecker, | ||||
|   middlewares: [ErrorHandler], | ||||
|   development: config.development, | ||||
|   cors: true, | ||||
|   | ||||
							
								
								
									
										86
									
								
								src/controllers/MeController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/controllers/MeController.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| import { Body, CurrentUser, Delete, Get, JsonController, OnUndefined, Put, QueryParam } from 'routing-controllers'; | ||||
| import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; | ||||
| import { getConnectionManager, Repository } from 'typeorm'; | ||||
| import { UserDeletionNotConfirmedError, UserIdsNotMatchingError, UsernameContainsIllegalCharacterError, UserNotFoundError } from '../errors/UserErrors'; | ||||
| import { UpdateUser } from '../models/actions/update/UpdateUser'; | ||||
| import { User } from '../models/entities/User'; | ||||
| import { ResponseUser } from '../models/responses/ResponseUser'; | ||||
| import { ResponseUserPermissions } from '../models/responses/ResponseUserPermissions'; | ||||
| import { PermissionController } from './PermissionController'; | ||||
|  | ||||
|  | ||||
| @JsonController('/users/me') | ||||
| @OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) | ||||
| export class MeController { | ||||
| 	private userRepository: Repository<User>; | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the repository of this controller's model/entity. | ||||
| 	 */ | ||||
| 	constructor() { | ||||
| 		this.userRepository = getConnectionManager().get().getRepository(User); | ||||
| 	} | ||||
|  | ||||
| 	@Get('/') | ||||
| 	@ResponseSchema(ResponseUser) | ||||
| 	@ResponseSchema(UserNotFoundError, { statusCode: 404 }) | ||||
| 	@OnUndefined(UserNotFoundError) | ||||
| 	@OpenAPI({ description: 'Lists all information about yourself.' }) | ||||
| 	async get(@CurrentUser() currentUser: User) { | ||||
| 		let user = await this.userRepository.findOne({ id: currentUser.id }, { relations: ['permissions', 'groups', 'groups.permissions', 'permissions.principal', 'groups.permissions.principal'] }) | ||||
| 		if (!user) { throw new UserNotFoundError(); } | ||||
| 		return new ResponseUser(user); | ||||
| 	} | ||||
|  | ||||
| 	@Get('/') | ||||
| 	@ResponseSchema(ResponseUserPermissions) | ||||
| 	@ResponseSchema(UserNotFoundError, { statusCode: 404 }) | ||||
| 	@OnUndefined(UserNotFoundError) | ||||
| 	@OpenAPI({ description: 'Lists all permissions granted to the you sorted into directly granted and inherited as permission response objects.' }) | ||||
| 	async getPermissions(@CurrentUser() currentUser: User) { | ||||
| 		let user = await this.userRepository.findOne({ id: currentUser.id }, { relations: ['permissions', 'groups', 'groups.permissions', 'permissions.principal', 'groups.permissions.principal'] }) | ||||
| 		if (!user) { throw new UserNotFoundError(); } | ||||
| 		return new ResponseUserPermissions(user); | ||||
| 	} | ||||
|  | ||||
| 	@Put('/') | ||||
| 	@ResponseSchema(ResponseUser) | ||||
| 	@ResponseSchema(UserNotFoundError, { statusCode: 404 }) | ||||
| 	@ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 }) | ||||
| 	@ResponseSchema(UsernameContainsIllegalCharacterError, { statusCode: 406 }) | ||||
| 	@OpenAPI({ description: "Update the yourself. <br> You can't edit your own permissions or group memberships here - Please use the /api/users/:id enpoint instead. <br> Please remember that ids can't be changed." }) | ||||
| 	async put(@CurrentUser() currentUser: User, @Body({ validate: true }) updateUser: UpdateUser) { | ||||
| 		let oldUser = await this.userRepository.findOne({ id: currentUser.id }, { relations: ['groups'] }); | ||||
| 		updateUser.groups = oldUser.groups.map(g => g.id); | ||||
|  | ||||
| 		if (!oldUser) { | ||||
| 			throw new UserNotFoundError(); | ||||
| 		} | ||||
|  | ||||
| 		if (oldUser.id != updateUser.id) { | ||||
| 			throw new UserIdsNotMatchingError(); | ||||
| 		} | ||||
| 		await this.userRepository.save(await updateUser.update(oldUser)); | ||||
|  | ||||
| 		return new ResponseUser(await this.userRepository.findOne({ id: currentUser.id }, { relations: ['permissions', 'groups', 'groups.permissions'] })); | ||||
| 	} | ||||
|  | ||||
| 	@Delete('/') | ||||
| 	@ResponseSchema(ResponseUser) | ||||
| 	@ResponseSchema(UserNotFoundError, { statusCode: 404 }) | ||||
| 	@ResponseSchema(UserDeletionNotConfirmedError, { statusCode: 406 }) | ||||
| 	@OpenAPI({ description: 'Delete yourself. <br> You have to confirm your decision by providing the ?force=true query param. <br> If there are any permissions directly granted to you they will get deleted as well.' }) | ||||
| 	async remove(@CurrentUser() currentUser: User, @QueryParam("force") force: boolean) { | ||||
| 		if (!force) { throw new UserDeletionNotConfirmedError; } | ||||
| 		if (!currentUser) { return UserNotFoundError; } | ||||
| 		const responseUser = await this.userRepository.findOne({ id: currentUser.id }, { relations: ['permissions', 'groups', 'groups.permissions'] });; | ||||
|  | ||||
| 		const permissionControler = new PermissionController(); | ||||
| 		for (let permission of responseUser.permissions) { | ||||
| 			await permissionControler.remove(permission.id, true); | ||||
| 		} | ||||
|  | ||||
| 		await this.userRepository.delete(currentUser); | ||||
| 		return new ResponseUser(responseUser); | ||||
| 	} | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| 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 { UserIdsNotMatchingError, UsernameContainsIllegalCharacterError, UserNotFoundError } from '../errors/UserErrors'; | ||||
| import { UserDeletionNotConfirmedError, UserIdsNotMatchingError, UsernameContainsIllegalCharacterError, UserNotFoundError } from '../errors/UserErrors'; | ||||
| import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; | ||||
| import { CreateUser } from '../models/actions/create/CreateUser'; | ||||
| import { UpdateUser } from '../models/actions/update/UpdateUser'; | ||||
| @@ -105,9 +105,11 @@ export class UserController { | ||||
| 	@Authorized("USER:DELETE") | ||||
| 	@ResponseSchema(ResponseUser) | ||||
| 	@ResponseSchema(ResponseEmpty, { statusCode: 204 }) | ||||
| 	@ResponseSchema(UserDeletionNotConfirmedError, { statusCode: 406 }) | ||||
| 	@OnUndefined(204) | ||||
| 	@OpenAPI({ description: 'Delete the user whose id you provided. <br> If there are any permissions directly granted to the user they will get deleted as well. <br> If no user with this id exists it will just return 204(no content).' }) | ||||
| 	@OpenAPI({ description: 'Delete the user whose id you provided. <br> You have to confirm your decision by providing the ?force=true query param. <br> If there are any permissions directly granted to the user they will get deleted as well. <br> If no user with this id exists it will just return 204(no content).' }) | ||||
| 	async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { | ||||
| 		if (!force) { throw new UserDeletionNotConfirmedError; } | ||||
| 		let user = await this.userRepository.findOne({ id: id }); | ||||
| 		if (!user) { return null; } | ||||
| 		const responseUser = await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups', 'groups.permissions'] });; | ||||
|   | ||||
| @@ -1,24 +1,24 @@ | ||||
| import { IsString } from 'class-validator'; | ||||
| import { NotAcceptableError, NotFoundError } from 'routing-controllers'; | ||||
|  | ||||
| /** | ||||
|  * Error to throw, when to provided address doesn't belong to the accepted types. | ||||
|  */ | ||||
| export class AddressWrongTypeError extends NotAcceptableError { | ||||
| 	@IsString() | ||||
| 	name = "AddressWrongTypeError" | ||||
|  | ||||
| 	@IsString() | ||||
| 	message = "The address must be an existing address's id. \n You provided a object of another type." | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Error to throw, when a non-existent address get's loaded. | ||||
|  */ | ||||
| export class AddressNotFoundError extends NotFoundError { | ||||
| 	@IsString() | ||||
| 	name = "AddressNotFoundError" | ||||
|  | ||||
| 	@IsString() | ||||
| 	message = "The address you provided couldn't be located in the system. \n Please check your request." | ||||
| import { IsString } from 'class-validator'; | ||||
| import { NotAcceptableError, NotFoundError } from 'routing-controllers'; | ||||
|  | ||||
| /** | ||||
|  * Error to throw, when to provided address doesn't belong to the accepted types. | ||||
|  */ | ||||
| export class AddressWrongTypeError extends NotAcceptableError { | ||||
| 	@IsString() | ||||
| 	name = "AddressWrongTypeError" | ||||
|  | ||||
| 	@IsString() | ||||
| 	message = "The address must be an existing address's id. \n You provided a object of another type." | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Error to throw, when a non-existent address get's loaded. | ||||
|  */ | ||||
| export class AddressNotFoundError extends NotFoundError { | ||||
| 	@IsString() | ||||
| 	name = "AddressNotFoundError" | ||||
|  | ||||
| 	@IsString() | ||||
| 	message = "The address you provided couldn't be located in the system. \n Please check your request." | ||||
| } | ||||
| @@ -59,4 +59,16 @@ export class UserIdsNotMatchingError extends NotAcceptableError { | ||||
|  | ||||
| 	@IsString() | ||||
| 	message = "The ids don't match!! \n And if you wanted to change a user's id: This isn't allowed!" | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Error to throw when two users' ids don't match. | ||||
|  * Usually occurs when a user tries to change a user's id. | ||||
|  */ | ||||
| export class UserDeletionNotConfirmedError extends NotAcceptableError { | ||||
| 	@IsString() | ||||
| 	name = "UserDeletionNotConfirmedError" | ||||
|  | ||||
| 	@IsString() | ||||
| 	message = "You are trying to delete a user! \n If you're sure about doing this: provide the ?force=true query param." | ||||
| } | ||||
							
								
								
									
										58
									
								
								src/middlewares/UserChecker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/middlewares/UserChecker.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| import cookie from "cookie"; | ||||
| import * as jwt from "jsonwebtoken"; | ||||
| import { Action } from 'routing-controllers'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { config } from '../config'; | ||||
| import { IllegalJWTError, UserDisabledError, UserNonexistantOrRefreshtokenInvalidError } from '../errors/AuthError'; | ||||
| import { JwtCreator, JwtUser } from '../jwtcreator'; | ||||
| import { User } from '../models/entities/User'; | ||||
|  | ||||
| /** | ||||
|  * TODO: | ||||
|  */ | ||||
| const UserChecker = async (action: Action) => { | ||||
|     let jwtPayload = undefined | ||||
|     try { | ||||
|         let provided_token = "" + action.request.headers["authorization"].replace("Bearer ", ""); | ||||
|         jwtPayload = <any>jwt.verify(provided_token, config.jwt_secret); | ||||
|         jwtPayload = jwtPayload["userdetails"]; | ||||
|     } catch (error) { | ||||
|         jwtPayload = await refresh(action); | ||||
|     } | ||||
|  | ||||
|     const user = await getConnectionManager().get().getRepository(User).findOne({ id: jwtPayload["id"], refreshTokenCount: jwtPayload["refreshTokenCount"] }) | ||||
|     if (!user) { throw new UserNonexistantOrRefreshtokenInvalidError() } | ||||
|     if (user.enabled == false) { throw new UserDisabledError(); } | ||||
|     return user; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Handles soft-refreshing of access-tokens. | ||||
|  * @param action Routing-Controllers action object that provides request and response objects among other stuff. | ||||
|  */ | ||||
| const refresh = async (action: Action) => { | ||||
|     let refresh_token = undefined; | ||||
|     try { | ||||
|         refresh_token = cookie.parse(action.request.headers["cookie"])["lfk_backend__refresh_token"]; | ||||
|     } | ||||
|     catch { | ||||
|         throw new IllegalJWTError(); | ||||
|     } | ||||
|  | ||||
|     let jwtPayload = undefined; | ||||
|     try { | ||||
|         jwtPayload = <any>jwt.verify(refresh_token, config.jwt_secret); | ||||
|     } catch (error) { | ||||
|         throw new IllegalJWTError(); | ||||
|     } | ||||
|  | ||||
|     const user = await getConnectionManager().get().getRepository(User).findOne({ id: jwtPayload["id"], refreshTokenCount: jwtPayload["refreshTokenCount"] }, { relations: ['permissions', 'groups', 'groups.permissions'] }) | ||||
|     if (!user) { throw new UserNonexistantOrRefreshtokenInvalidError() } | ||||
|     if (user.enabled == false) { throw new UserDisabledError(); } | ||||
|  | ||||
|     let newAccess = JwtCreator.createAccess(user); | ||||
|     action.response.header("authorization", "Bearer " + newAccess); | ||||
|  | ||||
|     return await new JwtUser(user); | ||||
| } | ||||
| export default UserChecker; | ||||
| @@ -1,69 +1,69 @@ | ||||
| import { IsNotEmpty, IsOptional, IsPostalCode, IsString } from 'class-validator'; | ||||
| import { config } from '../../../config'; | ||||
| import { Address } from '../../entities/Address'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Address entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateAddress { | ||||
|     /** | ||||
|      * The newaddress's description. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     description?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's first line. | ||||
|      * Containing the street and house number. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     address1: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's second line. | ||||
|      * Containing optional information. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     address2?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's postal code. | ||||
|      * This will get checked against the postal code syntax for the configured country. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     @IsPostalCode(config.postalcode_validation_countrycode) | ||||
|     postalcode: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's city. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     city: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's country. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     country: string; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Address entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<Address> { | ||||
|         let newAddress: Address = new Address(); | ||||
|  | ||||
|         newAddress.address1 = this.address1; | ||||
|         newAddress.address2 = this.address2; | ||||
|         newAddress.postalcode = this.postalcode; | ||||
|         newAddress.city = this.city; | ||||
|         newAddress.country = this.country; | ||||
|  | ||||
|         return newAddress; | ||||
|     } | ||||
| import { IsNotEmpty, IsOptional, IsPostalCode, IsString } from 'class-validator'; | ||||
| import { config } from '../../../config'; | ||||
| import { Address } from '../../entities/Address'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Address entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateAddress { | ||||
|     /** | ||||
|      * The newaddress's description. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     description?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's first line. | ||||
|      * Containing the street and house number. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     address1: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's second line. | ||||
|      * Containing optional information. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     address2?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's postal code. | ||||
|      * This will get checked against the postal code syntax for the configured country. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     @IsPostalCode(config.postalcode_validation_countrycode) | ||||
|     postalcode: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's city. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     city: string; | ||||
|  | ||||
|     /** | ||||
|      * The new address's country. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     country: string; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Address entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<Address> { | ||||
|         let newAddress: Address = new Address(); | ||||
|  | ||||
|         newAddress.address1 = this.address1; | ||||
|         newAddress.address2 = this.address2; | ||||
|         newAddress.postalcode = this.postalcode; | ||||
|         newAddress.city = this.city; | ||||
|         newAddress.country = this.country; | ||||
|  | ||||
|         return newAddress; | ||||
|     } | ||||
| } | ||||
| @@ -1,38 +1,38 @@ | ||||
| import { IsBoolean, IsOptional } from 'class-validator'; | ||||
| import { DonorReceiptAddressNeededError } from '../../../errors/DonorErrors'; | ||||
| import { Donor } from '../../entities/Donor'; | ||||
| import { CreateParticipant } from './CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Donor entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateDonor extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * Does this donor need a receipt? | ||||
|      */ | ||||
|     @IsBoolean() | ||||
|     @IsOptional() | ||||
|     receiptNeeded?: boolean = false; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Donor entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<Donor> { | ||||
|         let newDonor: Donor = new Donor(); | ||||
|  | ||||
|         newDonor.firstname = this.firstname; | ||||
|         newDonor.middlename = this.middlename; | ||||
|         newDonor.lastname = this.lastname; | ||||
|         newDonor.phone = this.phone; | ||||
|         newDonor.email = this.email; | ||||
|         newDonor.address = await this.getAddress(); | ||||
|         newDonor.receiptNeeded = this.receiptNeeded; | ||||
|  | ||||
|         if (this.receiptNeeded == true && this.address == null) { | ||||
|             throw new DonorReceiptAddressNeededError() | ||||
|         } | ||||
|  | ||||
|         return newDonor; | ||||
|     } | ||||
| import { IsBoolean, IsOptional } from 'class-validator'; | ||||
| import { DonorReceiptAddressNeededError } from '../../../errors/DonorErrors'; | ||||
| import { Donor } from '../../entities/Donor'; | ||||
| import { CreateParticipant } from './CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Donor entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateDonor extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * Does this donor need a receipt? | ||||
|      */ | ||||
|     @IsBoolean() | ||||
|     @IsOptional() | ||||
|     receiptNeeded?: boolean = false; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Donor entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<Donor> { | ||||
|         let newDonor: Donor = new Donor(); | ||||
|  | ||||
|         newDonor.firstname = this.firstname; | ||||
|         newDonor.middlename = this.middlename; | ||||
|         newDonor.lastname = this.lastname; | ||||
|         newDonor.phone = this.phone; | ||||
|         newDonor.email = this.email; | ||||
|         newDonor.address = await this.getAddress(); | ||||
|         newDonor.receiptNeeded = this.receiptNeeded; | ||||
|  | ||||
|         if (this.receiptNeeded == true && this.address == null) { | ||||
|             throw new DonorReceiptAddressNeededError() | ||||
|         } | ||||
|  | ||||
|         return newDonor; | ||||
|     } | ||||
| } | ||||
| @@ -1,78 +1,78 @@ | ||||
| import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { config } from '../../../config'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
| import { GroupContact } from '../../entities/GroupContact'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Group entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateGroupContact { | ||||
|     /** | ||||
|      * The new contact's first name. | ||||
|      */ | ||||
|     @IsNotEmpty() | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new contact's middle name. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsString() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new contact's last name. | ||||
|      */ | ||||
|     @IsNotEmpty() | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new contact's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * The contact's phone number. | ||||
|      * This will be validated against the configured country phone numer syntax (default: international). | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsPhoneNumber(config.phone_validation_countrycode) | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The contact's email address. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsEmail() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * Gets the new contact's address by it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Address entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<GroupContact> { | ||||
|         let contact: GroupContact = new GroupContact(); | ||||
|         contact.firstname = this.firstname; | ||||
|         contact.middlename = this.middlename; | ||||
|         contact.lastname = this.lastname; | ||||
|         contact.email = this.email; | ||||
|         contact.phone = this.phone; | ||||
|         contact.address = await this.getAddress(); | ||||
|         return null; | ||||
|     } | ||||
| import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { config } from '../../../config'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
| import { GroupContact } from '../../entities/GroupContact'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Group entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateGroupContact { | ||||
|     /** | ||||
|      * The new contact's first name. | ||||
|      */ | ||||
|     @IsNotEmpty() | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new contact's middle name. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsString() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new contact's last name. | ||||
|      */ | ||||
|     @IsNotEmpty() | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new contact's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * The contact's phone number. | ||||
|      * This will be validated against the configured country phone numer syntax (default: international). | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsPhoneNumber(config.phone_validation_countrycode) | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The contact's email address. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsEmail() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * Gets the new contact's address by it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Address entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<GroupContact> { | ||||
|         let contact: GroupContact = new GroupContact(); | ||||
|         contact.firstname = this.firstname; | ||||
|         contact.middlename = this.middlename; | ||||
|         contact.lastname = this.lastname; | ||||
|         contact.email = this.email; | ||||
|         contact.phone = this.phone; | ||||
|         contact.address = await this.getAddress(); | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -1,65 +1,65 @@ | ||||
| import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { config } from '../../../config'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Participant entity from a json body (post request). | ||||
|  */ | ||||
| export abstract class CreateParticipant { | ||||
|     /** | ||||
|      * The new participant's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's middle name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's phone number. | ||||
|      * This will be validated against the configured country phone numer syntax (default: international). | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     @IsPhoneNumber(config.phone_validation_countrycode) | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's e-mail address. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     @IsEmail() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * Gets the new participant's address by it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
| import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { config } from '../../../config'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Participant entity from a json body (post request). | ||||
|  */ | ||||
| export abstract class CreateParticipant { | ||||
|     /** | ||||
|      * The new participant's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's middle name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsNotEmpty() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's phone number. | ||||
|      * This will be validated against the configured country phone numer syntax (default: international). | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     @IsPhoneNumber(config.phone_validation_countrycode) | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's e-mail address. | ||||
|      */ | ||||
|     @IsString() | ||||
|     @IsOptional() | ||||
|     @IsEmail() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * The new participant's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * Gets the new participant's address by it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
| } | ||||
| @@ -1,53 +1,53 @@ | ||||
| import { IsInt } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors'; | ||||
| import { RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors'; | ||||
| import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; | ||||
| import { Runner } from '../../entities/Runner'; | ||||
| import { RunnerGroup } from '../../entities/RunnerGroup'; | ||||
| import { CreateParticipant } from './CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Runner entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateRunner extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * The new runner's group's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     group: number; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Runner entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<Runner> { | ||||
|         let newRunner: Runner = new Runner(); | ||||
|  | ||||
|         newRunner.firstname = this.firstname; | ||||
|         newRunner.middlename = this.middlename; | ||||
|         newRunner.lastname = this.lastname; | ||||
|         newRunner.phone = this.phone; | ||||
|         newRunner.email = this.email; | ||||
|         newRunner.group = await this.getGroup(); | ||||
|         newRunner.address = await this.getAddress(); | ||||
|  | ||||
|         return newRunner; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the new runner's group by it's id. | ||||
|      */ | ||||
|     public async getGroup(): Promise<RunnerGroup> { | ||||
|         if (this.group === undefined || this.group === null) { | ||||
|             throw new RunnerTeamNeedsParentError(); | ||||
|         } | ||||
|         if (!isNaN(this.group)) { | ||||
|             let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: this.group }); | ||||
|             if (!group) { throw new RunnerGroupNotFoundError; } | ||||
|             return group; | ||||
|         } | ||||
|  | ||||
|         throw new RunnerOrganisationWrongTypeError; | ||||
|     } | ||||
| import { IsInt } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors'; | ||||
| import { RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors'; | ||||
| import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; | ||||
| import { Runner } from '../../entities/Runner'; | ||||
| import { RunnerGroup } from '../../entities/RunnerGroup'; | ||||
| import { CreateParticipant } from './CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new Runner entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateRunner extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * The new runner's group's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     group: number; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Runner entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<Runner> { | ||||
|         let newRunner: Runner = new Runner(); | ||||
|  | ||||
|         newRunner.firstname = this.firstname; | ||||
|         newRunner.middlename = this.middlename; | ||||
|         newRunner.lastname = this.lastname; | ||||
|         newRunner.phone = this.phone; | ||||
|         newRunner.email = this.email; | ||||
|         newRunner.group = await this.getGroup(); | ||||
|         newRunner.address = await this.getAddress(); | ||||
|  | ||||
|         return newRunner; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the new runner's group by it's id. | ||||
|      */ | ||||
|     public async getGroup(): Promise<RunnerGroup> { | ||||
|         if (this.group === undefined || this.group === null) { | ||||
|             throw new RunnerTeamNeedsParentError(); | ||||
|         } | ||||
|         if (!isNaN(this.group)) { | ||||
|             let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: this.group }); | ||||
|             if (!group) { throw new RunnerGroupNotFoundError; } | ||||
|             return group; | ||||
|         } | ||||
|  | ||||
|         throw new RunnerOrganisationWrongTypeError; | ||||
|     } | ||||
| } | ||||
| @@ -1,41 +1,41 @@ | ||||
| import { IsInt, IsOptional } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
| import { RunnerOrganisation } from '../../entities/RunnerOrganisation'; | ||||
| import { CreateRunnerGroup } from './CreateRunnerGroup'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new RunnerOrganisation entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateRunnerOrganisation extends CreateRunnerGroup { | ||||
|     /** | ||||
|      * The new organisation's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * Gets the org's address by it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new RunnerOrganisation entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<RunnerOrganisation> { | ||||
|         let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation(); | ||||
|  | ||||
|         newRunnerOrganisation.name = this.name; | ||||
|         newRunnerOrganisation.contact = await this.getContact(); | ||||
|         newRunnerOrganisation.address = await this.getAddress(); | ||||
|  | ||||
|         return newRunnerOrganisation; | ||||
|     } | ||||
| import { IsInt, IsOptional } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
| import { RunnerOrganisation } from '../../entities/RunnerOrganisation'; | ||||
| import { CreateRunnerGroup } from './CreateRunnerGroup'; | ||||
|  | ||||
| /** | ||||
|  * This classed is used to create a new RunnerOrganisation entity from a json body (post request). | ||||
|  */ | ||||
| export class CreateRunnerOrganisation extends CreateRunnerGroup { | ||||
|     /** | ||||
|      * The new organisation's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * Gets the org's address by it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new RunnerOrganisation entity from this. | ||||
|      */ | ||||
|     public async toEntity(): Promise<RunnerOrganisation> { | ||||
|         let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation(); | ||||
|  | ||||
|         newRunnerOrganisation.name = this.name; | ||||
|         newRunnerOrganisation.contact = await this.getContact(); | ||||
|         newRunnerOrganisation.address = await this.getAddress(); | ||||
|  | ||||
|         return newRunnerOrganisation; | ||||
|     } | ||||
| } | ||||
| @@ -1,44 +1,44 @@ | ||||
| import { IsBoolean, IsInt, IsOptional } from 'class-validator'; | ||||
| import { DonorReceiptAddressNeededError } from '../../../errors/DonorErrors'; | ||||
| import { Donor } from '../../entities/Donor'; | ||||
| import { CreateParticipant } from '../create/CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This class is used to update a Donor entity (via put request). | ||||
|  */ | ||||
| export class UpdateDonor extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * The updated donor's id. | ||||
|      * This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to). | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * Does the updated donor need a receipt? | ||||
|      */ | ||||
|     @IsBoolean() | ||||
|     @IsOptional() | ||||
|     receiptNeeded?: boolean; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Updates a provided Donor entity based on this. | ||||
|      */ | ||||
|     public async update(donor: Donor): Promise<Donor> { | ||||
|         donor.firstname = this.firstname; | ||||
|         donor.middlename = this.middlename; | ||||
|         donor.lastname = this.lastname; | ||||
|         donor.phone = this.phone; | ||||
|         donor.email = this.email; | ||||
|         donor.receiptNeeded = this.receiptNeeded; | ||||
|         donor.address = await this.getAddress(); | ||||
|  | ||||
|         if (this.receiptNeeded == true && this.address == null) { | ||||
|             throw new DonorReceiptAddressNeededError() | ||||
|         } | ||||
|  | ||||
|         return donor; | ||||
|     } | ||||
| import { IsBoolean, IsInt, IsOptional } from 'class-validator'; | ||||
| import { DonorReceiptAddressNeededError } from '../../../errors/DonorErrors'; | ||||
| import { Donor } from '../../entities/Donor'; | ||||
| import { CreateParticipant } from '../create/CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This class is used to update a Donor entity (via put request). | ||||
|  */ | ||||
| export class UpdateDonor extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * The updated donor's id. | ||||
|      * This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to). | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * Does the updated donor need a receipt? | ||||
|      */ | ||||
|     @IsBoolean() | ||||
|     @IsOptional() | ||||
|     receiptNeeded?: boolean; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Updates a provided Donor entity based on this. | ||||
|      */ | ||||
|     public async update(donor: Donor): Promise<Donor> { | ||||
|         donor.firstname = this.firstname; | ||||
|         donor.middlename = this.middlename; | ||||
|         donor.lastname = this.lastname; | ||||
|         donor.phone = this.phone; | ||||
|         donor.email = this.email; | ||||
|         donor.receiptNeeded = this.receiptNeeded; | ||||
|         donor.address = await this.getAddress(); | ||||
|  | ||||
|         if (this.receiptNeeded == true && this.address == null) { | ||||
|             throw new DonorReceiptAddressNeededError() | ||||
|         } | ||||
|  | ||||
|         return donor; | ||||
|     } | ||||
| } | ||||
| @@ -1,54 +1,54 @@ | ||||
| import { IsInt, IsPositive } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors'; | ||||
| import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; | ||||
| import { Runner } from '../../entities/Runner'; | ||||
| import { RunnerGroup } from '../../entities/RunnerGroup'; | ||||
| import { CreateParticipant } from '../create/CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This class is used to update a Runner entity (via put request). | ||||
|  */ | ||||
| export class UpdateRunner extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * The updated runner's id. | ||||
|      * This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to). | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The updated runner's group's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsPositive() | ||||
|     group: number; | ||||
|  | ||||
|     /** | ||||
|      * Updates a provided Runner entity based on this. | ||||
|      */ | ||||
|     public async update(runner: Runner): Promise<Runner> { | ||||
|         runner.firstname = this.firstname; | ||||
|         runner.middlename = this.middlename; | ||||
|         runner.lastname = this.lastname; | ||||
|         runner.phone = this.phone; | ||||
|         runner.email = this.email; | ||||
|         runner.group = await this.getGroup(); | ||||
|         runner.address = await this.getAddress(); | ||||
|  | ||||
|         return runner; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Loads the updated runner's group based on it's id. | ||||
|      */ | ||||
|     public async getGroup(): Promise<RunnerGroup> { | ||||
|         if (this.group === undefined || this.group === null) { | ||||
|             throw new RunnerTeamNeedsParentError(); | ||||
|         } | ||||
|         let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: this.group }); | ||||
|         if (!group) { throw new RunnerGroupNotFoundError; } | ||||
|         return group; | ||||
|     } | ||||
| import { IsInt, IsPositive } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors'; | ||||
| import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; | ||||
| import { Runner } from '../../entities/Runner'; | ||||
| import { RunnerGroup } from '../../entities/RunnerGroup'; | ||||
| import { CreateParticipant } from '../create/CreateParticipant'; | ||||
|  | ||||
| /** | ||||
|  * This class is used to update a Runner entity (via put request). | ||||
|  */ | ||||
| export class UpdateRunner extends CreateParticipant { | ||||
|  | ||||
|     /** | ||||
|      * The updated runner's id. | ||||
|      * This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to). | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The updated runner's group's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsPositive() | ||||
|     group: number; | ||||
|  | ||||
|     /** | ||||
|      * Updates a provided Runner entity based on this. | ||||
|      */ | ||||
|     public async update(runner: Runner): Promise<Runner> { | ||||
|         runner.firstname = this.firstname; | ||||
|         runner.middlename = this.middlename; | ||||
|         runner.lastname = this.lastname; | ||||
|         runner.phone = this.phone; | ||||
|         runner.email = this.email; | ||||
|         runner.group = await this.getGroup(); | ||||
|         runner.address = await this.getAddress(); | ||||
|  | ||||
|         return runner; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Loads the updated runner's group based on it's id. | ||||
|      */ | ||||
|     public async getGroup(): Promise<RunnerGroup> { | ||||
|         if (this.group === undefined || this.group === null) { | ||||
|             throw new RunnerTeamNeedsParentError(); | ||||
|         } | ||||
|         let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: this.group }); | ||||
|         if (!group) { throw new RunnerGroupNotFoundError; } | ||||
|         return group; | ||||
|     } | ||||
| } | ||||
| @@ -1,48 +1,48 @@ | ||||
| import { IsInt, IsOptional } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
| import { RunnerOrganisation } from '../../entities/RunnerOrganisation'; | ||||
| import { CreateRunnerGroup } from '../create/CreateRunnerGroup'; | ||||
|  | ||||
| /** | ||||
|  * This class is used to update a RunnerOrganisation entity (via put request). | ||||
|  */ | ||||
| export class UpdateRunnerOrganisation extends CreateRunnerGroup { | ||||
|  | ||||
|     /** | ||||
|      * The updated orgs's id. | ||||
|      * This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to). | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The updated organisation's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * Loads the organisation's address based on it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Updates a provided RunnerOrganisation entity based on this. | ||||
|      */ | ||||
|     public async update(organisation: RunnerOrganisation): Promise<RunnerOrganisation> { | ||||
|  | ||||
|         organisation.name = this.name; | ||||
|         organisation.contact = await this.getContact(); | ||||
|         organisation.address = await this.getAddress(); | ||||
|  | ||||
|         return organisation; | ||||
|     } | ||||
| import { IsInt, IsOptional } from 'class-validator'; | ||||
| import { getConnectionManager } from 'typeorm'; | ||||
| import { AddressNotFoundError } from '../../../errors/AddressErrors'; | ||||
| import { Address } from '../../entities/Address'; | ||||
| import { RunnerOrganisation } from '../../entities/RunnerOrganisation'; | ||||
| import { CreateRunnerGroup } from '../create/CreateRunnerGroup'; | ||||
|  | ||||
| /** | ||||
|  * This class is used to update a RunnerOrganisation entity (via put request). | ||||
|  */ | ||||
| export class UpdateRunnerOrganisation extends CreateRunnerGroup { | ||||
|  | ||||
|     /** | ||||
|      * The updated orgs's id. | ||||
|      * This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to). | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The updated organisation's address's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     @IsOptional() | ||||
|     address?: number; | ||||
|  | ||||
|     /** | ||||
|      * Loads the organisation's address based on it's id. | ||||
|      */ | ||||
|     public async getAddress(): Promise<Address> { | ||||
|         if (!this.address) { return null; } | ||||
|         let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); | ||||
|         if (!address) { throw new AddressNotFoundError; } | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Updates a provided RunnerOrganisation entity based on this. | ||||
|      */ | ||||
|     public async update(organisation: RunnerOrganisation): Promise<RunnerOrganisation> { | ||||
|  | ||||
|         organisation.name = this.name; | ||||
|         organisation.contact = await this.getContact(); | ||||
|         organisation.address = await this.getAddress(); | ||||
|  | ||||
|         return organisation; | ||||
|     } | ||||
| } | ||||
| @@ -76,6 +76,7 @@ export class UpdateUser { | ||||
|      * Should the user be enabled? | ||||
|      */ | ||||
|     @IsBoolean() | ||||
|     @IsOptional() | ||||
|     enabled: boolean = true; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -1,90 +1,90 @@ | ||||
| import { | ||||
|   IsInt, | ||||
|   IsNotEmpty, | ||||
|   IsOptional, | ||||
|   IsPostalCode, | ||||
|   IsString | ||||
| } from "class-validator"; | ||||
| import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; | ||||
| import { config } from '../../config'; | ||||
| import { IAddressUser } from './IAddressUser'; | ||||
|  | ||||
| /** | ||||
|  * Defines the Address entity. | ||||
|  * Implemented this way to prevent any formatting differences. | ||||
| */ | ||||
| @Entity() | ||||
| export class Address { | ||||
|   /** | ||||
|    * Autogenerated unique id (primary key). | ||||
|    */ | ||||
|   @PrimaryGeneratedColumn() | ||||
|   @IsInt() | ||||
|   id: number; | ||||
|  | ||||
|   /** | ||||
|    * The address's description. | ||||
|    * Optional and mostly for UX. | ||||
|    */ | ||||
|   @Column({ nullable: true }) | ||||
|   @IsString() | ||||
|   @IsOptional() | ||||
|   description?: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's first line. | ||||
|    * Containing the street and house number. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   address1: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's second line. | ||||
|    * Containing optional information. | ||||
|    */ | ||||
|   @Column({ nullable: true }) | ||||
|   @IsString() | ||||
|   @IsOptional() | ||||
|   address2?: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's postal code. | ||||
|    * This will get checked against the postal code syntax for the configured country. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   @IsPostalCode(config.postalcode_validation_countrycode) | ||||
|   postalcode: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's city. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   city: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's country. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   country: string; | ||||
|  | ||||
|   /** | ||||
|    * Used to link the address to participants. | ||||
|    */ | ||||
|   @OneToMany(() => IAddressUser, addressUser => addressUser.address, { nullable: true }) | ||||
|   addressUsers: IAddressUser[]; | ||||
|  | ||||
|   /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|   public toResponse() { | ||||
|     return new Error("NotImplemented"); | ||||
|   } | ||||
| } | ||||
| import { | ||||
|   IsInt, | ||||
|   IsNotEmpty, | ||||
|   IsOptional, | ||||
|   IsPostalCode, | ||||
|   IsString | ||||
| } from "class-validator"; | ||||
| import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; | ||||
| import { config } from '../../config'; | ||||
| import { IAddressUser } from './IAddressUser'; | ||||
|  | ||||
| /** | ||||
|  * Defines the Address entity. | ||||
|  * Implemented this way to prevent any formatting differences. | ||||
| */ | ||||
| @Entity() | ||||
| export class Address { | ||||
|   /** | ||||
|    * Autogenerated unique id (primary key). | ||||
|    */ | ||||
|   @PrimaryGeneratedColumn() | ||||
|   @IsInt() | ||||
|   id: number; | ||||
|  | ||||
|   /** | ||||
|    * The address's description. | ||||
|    * Optional and mostly for UX. | ||||
|    */ | ||||
|   @Column({ nullable: true }) | ||||
|   @IsString() | ||||
|   @IsOptional() | ||||
|   description?: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's first line. | ||||
|    * Containing the street and house number. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   address1: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's second line. | ||||
|    * Containing optional information. | ||||
|    */ | ||||
|   @Column({ nullable: true }) | ||||
|   @IsString() | ||||
|   @IsOptional() | ||||
|   address2?: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's postal code. | ||||
|    * This will get checked against the postal code syntax for the configured country. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   @IsPostalCode(config.postalcode_validation_countrycode) | ||||
|   postalcode: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's city. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   city: string; | ||||
|  | ||||
|   /** | ||||
|    * The address's country. | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsString() | ||||
|   @IsNotEmpty() | ||||
|   country: string; | ||||
|  | ||||
|   /** | ||||
|    * Used to link the address to participants. | ||||
|    */ | ||||
|   @OneToMany(() => IAddressUser, addressUser => addressUser.address, { nullable: true }) | ||||
|   addressUsers: IAddressUser[]; | ||||
|  | ||||
|   /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|   public toResponse() { | ||||
|     return new Error("NotImplemented"); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,20 @@ | ||||
| import { Entity, ManyToOne, PrimaryColumn } from 'typeorm'; | ||||
| import { Address } from './Address'; | ||||
|  | ||||
| /** | ||||
|  * The interface(tm) all entities using addresses have to implement. | ||||
|  * This is a abstract class, because apparently typeorm can't really work with interfaces :/ | ||||
|  */ | ||||
| @Entity() | ||||
| export abstract class IAddressUser { | ||||
|     @PrimaryColumn() | ||||
|     id: number; | ||||
|  | ||||
|     @ManyToOne(() => Address, address => address.addressUsers, { nullable: true }) | ||||
|     address?: Address | ||||
|  | ||||
|     /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|     public abstract toResponse(); | ||||
| } | ||||
| import { Entity, ManyToOne, PrimaryColumn } from 'typeorm'; | ||||
| import { Address } from './Address'; | ||||
|  | ||||
| /** | ||||
|  * The interface(tm) all entities using addresses have to implement. | ||||
|  * This is a abstract class, because apparently typeorm can't really work with interfaces :/ | ||||
|  */ | ||||
| @Entity() | ||||
| export abstract class IAddressUser { | ||||
|     @PrimaryColumn() | ||||
|     id: number; | ||||
|  | ||||
|     @ManyToOne(() => Address, address => address.addressUsers, { nullable: true }) | ||||
|     address?: Address | ||||
|  | ||||
|     /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|     public abstract toResponse(); | ||||
| } | ||||
|   | ||||
| @@ -1,65 +1,65 @@ | ||||
| import { IsInt, IsOptional } from "class-validator"; | ||||
| import { ChildEntity, ManyToOne, OneToMany } from "typeorm"; | ||||
| import { ResponseRunnerOrganisation } from '../responses/ResponseRunnerOrganisation'; | ||||
| import { Address } from './Address'; | ||||
| import { IAddressUser } from './IAddressUser'; | ||||
| import { Runner } from './Runner'; | ||||
| import { RunnerGroup } from "./RunnerGroup"; | ||||
| import { RunnerTeam } from "./RunnerTeam"; | ||||
|  | ||||
| /** | ||||
|  * Defines the RunnerOrganisation entity. | ||||
|  * This usually is a school, club or company. | ||||
| */ | ||||
| @ChildEntity() | ||||
| export class RunnerOrganisation extends RunnerGroup implements IAddressUser { | ||||
|  | ||||
|   /** | ||||
|    * The organisations's address. | ||||
|    */ | ||||
|   @IsOptional() | ||||
|   @ManyToOne(() => Address, address => address.addressUsers, { nullable: true }) | ||||
|   address?: Address; | ||||
|  | ||||
|   /** | ||||
|    * The organisation's teams. | ||||
|    * Used to link teams to a organisation. | ||||
|    */ | ||||
|   @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true }) | ||||
|   teams: RunnerTeam[]; | ||||
|  | ||||
|   /** | ||||
|    * Returns all runners associated with this organisation (directly or indirectly via teams). | ||||
|    */ | ||||
|   public get allRunners(): Runner[] { | ||||
|     let returnRunners: Runner[] = new Array<Runner>(); | ||||
|     returnRunners.push(...this.runners); | ||||
|     for (let team of this.teams) { | ||||
|       returnRunners.push(...team.runners) | ||||
|     } | ||||
|     return returnRunners; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the total distance ran by this group's runners based on all their valid scans. | ||||
|   */ | ||||
|   @IsInt() | ||||
|   public get distance(): number { | ||||
|     return this.allRunners.reduce((sum, current) => sum + current.distance, 0); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the total donations a runner has collected based on his linked donations and distance ran. | ||||
|   */ | ||||
|   @IsInt() | ||||
|   public get distanceDonationAmount(): number { | ||||
|     return this.allRunners.reduce((sum, current) => sum + current.distanceDonationAmount, 0); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|   public toResponse(): ResponseRunnerOrganisation { | ||||
|     return new ResponseRunnerOrganisation(this); | ||||
|   } | ||||
| import { IsInt, IsOptional } from "class-validator"; | ||||
| import { ChildEntity, ManyToOne, OneToMany } from "typeorm"; | ||||
| import { ResponseRunnerOrganisation } from '../responses/ResponseRunnerOrganisation'; | ||||
| import { Address } from './Address'; | ||||
| import { IAddressUser } from './IAddressUser'; | ||||
| import { Runner } from './Runner'; | ||||
| import { RunnerGroup } from "./RunnerGroup"; | ||||
| import { RunnerTeam } from "./RunnerTeam"; | ||||
|  | ||||
| /** | ||||
|  * Defines the RunnerOrganisation entity. | ||||
|  * This usually is a school, club or company. | ||||
| */ | ||||
| @ChildEntity() | ||||
| export class RunnerOrganisation extends RunnerGroup implements IAddressUser { | ||||
|  | ||||
|   /** | ||||
|    * The organisations's address. | ||||
|    */ | ||||
|   @IsOptional() | ||||
|   @ManyToOne(() => Address, address => address.addressUsers, { nullable: true }) | ||||
|   address?: Address; | ||||
|  | ||||
|   /** | ||||
|    * The organisation's teams. | ||||
|    * Used to link teams to a organisation. | ||||
|    */ | ||||
|   @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true }) | ||||
|   teams: RunnerTeam[]; | ||||
|  | ||||
|   /** | ||||
|    * Returns all runners associated with this organisation (directly or indirectly via teams). | ||||
|    */ | ||||
|   public get allRunners(): Runner[] { | ||||
|     let returnRunners: Runner[] = new Array<Runner>(); | ||||
|     returnRunners.push(...this.runners); | ||||
|     for (let team of this.teams) { | ||||
|       returnRunners.push(...team.runners) | ||||
|     } | ||||
|     return returnRunners; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the total distance ran by this group's runners based on all their valid scans. | ||||
|   */ | ||||
|   @IsInt() | ||||
|   public get distance(): number { | ||||
|     return this.allRunners.reduce((sum, current) => sum + current.distance, 0); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the total donations a runner has collected based on his linked donations and distance ran. | ||||
|   */ | ||||
|   @IsInt() | ||||
|   public get distanceDonationAmount(): number { | ||||
|     return this.allRunners.reduce((sum, current) => sum + current.distanceDonationAmount, 0); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|   public toResponse(): ResponseRunnerOrganisation { | ||||
|     return new ResponseRunnerOrganisation(this); | ||||
|   } | ||||
| } | ||||
| @@ -138,8 +138,10 @@ export class User extends Principal { | ||||
|  | ||||
|     if (!this.groups) { return returnPermissions; } | ||||
|     for (let group of this.groups) { | ||||
|       for (let permission of group.permissions) { | ||||
|         returnPermissions.push(permission); | ||||
|       if (group.permissions) { | ||||
|         for (let permission of group.permissions) { | ||||
|           returnPermissions.push(permission); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return returnPermissions; | ||||
| @@ -159,8 +161,10 @@ export class User extends Principal { | ||||
|  | ||||
|     if (!this.groups) { return returnPermissions; } | ||||
|     for (let group of this.groups) { | ||||
|       for (let permission of group.permissions) { | ||||
|         returnPermissions.push(permission.toString()); | ||||
|       if (group.permissions) { | ||||
|         for (let permission of group.permissions) { | ||||
|           returnPermissions.push(permission.toString()); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return Array.from(new Set(returnPermissions)); | ||||
|   | ||||
| @@ -1,40 +1,40 @@ | ||||
| import { | ||||
|   IsNotEmpty, | ||||
|   IsOptional, | ||||
|   IsString | ||||
| } from "class-validator"; | ||||
| import { ChildEntity, Column } from "typeorm"; | ||||
| import { ResponsePrincipal } from '../responses/ResponsePrincipal'; | ||||
| import { ResponseUserGroup } from '../responses/ResponseUserGroup'; | ||||
| import { Principal } from './Principal'; | ||||
|  | ||||
| /** | ||||
|  * Defines the UserGroup entity. | ||||
|  * This entity describes a group of users with a set of permissions. | ||||
| */ | ||||
| @ChildEntity() | ||||
| export class UserGroup extends Principal { | ||||
|  | ||||
|   /** | ||||
|    * The group's name | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsNotEmpty() | ||||
|   @IsString() | ||||
|   name: string; | ||||
|  | ||||
|   /** | ||||
|    * The group's description | ||||
|    */ | ||||
|   @Column({ nullable: true }) | ||||
|   @IsOptional() | ||||
|   @IsString() | ||||
|   description?: string; | ||||
|  | ||||
|   /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|   public toResponse(): ResponsePrincipal { | ||||
|     return new ResponseUserGroup(this); | ||||
|   } | ||||
| import { | ||||
|   IsNotEmpty, | ||||
|   IsOptional, | ||||
|   IsString | ||||
| } from "class-validator"; | ||||
| import { ChildEntity, Column } from "typeorm"; | ||||
| import { ResponsePrincipal } from '../responses/ResponsePrincipal'; | ||||
| import { ResponseUserGroup } from '../responses/ResponseUserGroup'; | ||||
| import { Principal } from './Principal'; | ||||
|  | ||||
| /** | ||||
|  * Defines the UserGroup entity. | ||||
|  * This entity describes a group of users with a set of permissions. | ||||
| */ | ||||
| @ChildEntity() | ||||
| export class UserGroup extends Principal { | ||||
|  | ||||
|   /** | ||||
|    * The group's name | ||||
|    */ | ||||
|   @Column() | ||||
|   @IsNotEmpty() | ||||
|   @IsString() | ||||
|   name: string; | ||||
|  | ||||
|   /** | ||||
|    * The group's description | ||||
|    */ | ||||
|   @Column({ nullable: true }) | ||||
|   @IsOptional() | ||||
|   @IsString() | ||||
|   description?: string; | ||||
|  | ||||
|   /** | ||||
|    * Turns this entity into it's response class. | ||||
|    */ | ||||
|   public toResponse(): ResponsePrincipal { | ||||
|     return new ResponseUserGroup(this); | ||||
|   } | ||||
| } | ||||
| @@ -1,56 +1,56 @@ | ||||
| import { IsInt, IsString } from "class-validator"; | ||||
| import { Participant } from '../entities/Participant'; | ||||
|  | ||||
| /** | ||||
|  * Defines the participant response. | ||||
| */ | ||||
| export abstract class ResponseParticipant { | ||||
|     /** | ||||
|      * The participant's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The participant's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's middle name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's phone number. | ||||
|      */ | ||||
|     @IsString() | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's e-mail address. | ||||
|      */ | ||||
|     @IsString() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ResponseParticipant object from a participant. | ||||
|      * @param participant The participant the response shall be build for. | ||||
|      */ | ||||
|     public constructor(participant: Participant) { | ||||
|         this.id = participant.id; | ||||
|         this.firstname = participant.firstname; | ||||
|         this.middlename = participant.middlename; | ||||
|         this.lastname = participant.lastname; | ||||
|         this.phone = participant.phone; | ||||
|         this.email = participant.email; | ||||
|     } | ||||
| } | ||||
| import { IsInt, IsString } from "class-validator"; | ||||
| import { Participant } from '../entities/Participant'; | ||||
|  | ||||
| /** | ||||
|  * Defines the participant response. | ||||
| */ | ||||
| export abstract class ResponseParticipant { | ||||
|     /** | ||||
|      * The participant's id. | ||||
|      */ | ||||
|     @IsInt() | ||||
|     id: number; | ||||
|  | ||||
|     /** | ||||
|      * The participant's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's middle name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's phone number. | ||||
|      */ | ||||
|     @IsString() | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The participant's e-mail address. | ||||
|      */ | ||||
|     @IsString() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ResponseParticipant object from a participant. | ||||
|      * @param participant The participant the response shall be build for. | ||||
|      */ | ||||
|     public constructor(participant: Participant) { | ||||
|         this.id = participant.id; | ||||
|         this.firstname = participant.firstname; | ||||
|         this.middlename = participant.middlename; | ||||
|         this.lastname = participant.lastname; | ||||
|         this.phone = participant.phone; | ||||
|         this.email = participant.email; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,97 +1,99 @@ | ||||
| import { | ||||
|     IsArray, | ||||
|     IsBoolean, | ||||
|  | ||||
|     IsOptional, | ||||
|     IsString | ||||
| } from "class-validator"; | ||||
| import { User } from '../entities/User'; | ||||
| import { UserGroup } from '../entities/UserGroup'; | ||||
| import { ResponsePrincipal } from './ResponsePrincipal'; | ||||
|  | ||||
| /** | ||||
|  * Defines the user response. | ||||
| */ | ||||
| export class ResponseUser extends ResponsePrincipal { | ||||
|     /** | ||||
|      * The user's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's middle name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's phone number. | ||||
|      */ | ||||
|     @IsString() | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's e-mail address. | ||||
|      */ | ||||
|     @IsString() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's username. | ||||
|      */ | ||||
|     @IsString() | ||||
|     username?: string; | ||||
|  | ||||
|     /** | ||||
|     * Is user enabled? | ||||
|     */ | ||||
|     @IsBoolean() | ||||
|     enabled: boolean = true; | ||||
|  | ||||
|     /** | ||||
|     * The user's profile pic (or rather a url pointing to it). | ||||
|     */ | ||||
|     @IsString() | ||||
|     profilePic: string; | ||||
|  | ||||
|     /** | ||||
|      * The groups that the user is a part of. | ||||
|      */ | ||||
|     @IsArray() | ||||
|     @IsOptional() | ||||
|     groups: UserGroup[]; | ||||
|  | ||||
|     /** | ||||
|      * The user's permissions. | ||||
|      * Directly granted or inherited converted to their string form and deduplicated. | ||||
|      */ | ||||
|     @IsArray() | ||||
|     @IsOptional() | ||||
|     permissions: string[]; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ResponseUser object from a user. | ||||
|      * @param user The user the response shall be build for. | ||||
|      */ | ||||
|     public constructor(user: User) { | ||||
|         super(user); | ||||
|         this.firstname = user.firstname; | ||||
|         this.middlename = user.middlename; | ||||
|         this.lastname = user.lastname; | ||||
|         this.phone = user.phone; | ||||
|         this.email = user.email; | ||||
|         this.username = user.username; | ||||
|         this.enabled = user.enabled; | ||||
|         this.profilePic = user.profilePic; | ||||
|         this.groups = user.groups; | ||||
|         this.permissions = user.allPermissions; | ||||
|         this.groups.forEach(function (g) { delete g.permissions }); | ||||
|     } | ||||
| } | ||||
| import { | ||||
|     IsArray, | ||||
|     IsBoolean, | ||||
|  | ||||
|     IsOptional, | ||||
|     IsString | ||||
| } from "class-validator"; | ||||
| import { User } from '../entities/User'; | ||||
| import { UserGroup } from '../entities/UserGroup'; | ||||
| import { ResponsePrincipal } from './ResponsePrincipal'; | ||||
|  | ||||
| /** | ||||
|  * Defines the user response. | ||||
| */ | ||||
| export class ResponseUser extends ResponsePrincipal { | ||||
|     /** | ||||
|      * The user's first name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     firstname: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's middle name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     middlename?: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's last name. | ||||
|      */ | ||||
|     @IsString() | ||||
|     lastname: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's phone number. | ||||
|      */ | ||||
|     @IsString() | ||||
|     phone?: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's e-mail address. | ||||
|      */ | ||||
|     @IsString() | ||||
|     email?: string; | ||||
|  | ||||
|     /** | ||||
|      * The user's username. | ||||
|      */ | ||||
|     @IsString() | ||||
|     username?: string; | ||||
|  | ||||
|     /** | ||||
|     * Is user enabled? | ||||
|     */ | ||||
|     @IsBoolean() | ||||
|     enabled: boolean = true; | ||||
|  | ||||
|     /** | ||||
|     * The user's profile pic (or rather a url pointing to it). | ||||
|     */ | ||||
|     @IsString() | ||||
|     profilePic: string; | ||||
|  | ||||
|     /** | ||||
|      * The groups that the user is a part of. | ||||
|      */ | ||||
|     @IsArray() | ||||
|     @IsOptional() | ||||
|     groups: UserGroup[]; | ||||
|  | ||||
|     /** | ||||
|      * The user's permissions. | ||||
|      * Directly granted or inherited converted to their string form and deduplicated. | ||||
|      */ | ||||
|     @IsArray() | ||||
|     @IsOptional() | ||||
|     permissions: string[]; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ResponseUser object from a user. | ||||
|      * @param user The user the response shall be build for. | ||||
|      */ | ||||
|     public constructor(user: User) { | ||||
|         super(user); | ||||
|         this.firstname = user.firstname; | ||||
|         this.middlename = user.middlename; | ||||
|         this.lastname = user.lastname; | ||||
|         this.phone = user.phone; | ||||
|         this.email = user.email; | ||||
|         this.username = user.username; | ||||
|         this.enabled = user.enabled; | ||||
|         this.profilePic = user.profilePic; | ||||
|         this.groups = user.groups; | ||||
|         this.permissions = user.allPermissions; | ||||
|         if (this.groups) { | ||||
|             this.groups.forEach(function (g) { delete g.permissions }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,41 +1,41 @@ | ||||
| import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator"; | ||||
| import { Permission } from '../entities/Permission'; | ||||
| import { UserGroup } from '../entities/UserGroup'; | ||||
| import { ResponsePrincipal } from './ResponsePrincipal'; | ||||
|  | ||||
| /** | ||||
|  * Defines the userGroup response. | ||||
| */ | ||||
| export class ResponseUserGroup extends ResponsePrincipal { | ||||
|     /** | ||||
|      * The userGroup's name. | ||||
|      */ | ||||
|     @IsNotEmpty() | ||||
|     @IsString() | ||||
|     name: string; | ||||
|  | ||||
|     /** | ||||
|      * The userGroup's description. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsString() | ||||
|     description?: string; | ||||
|  | ||||
|     /** | ||||
|      * The userGroup's permissions. | ||||
|      */ | ||||
|     @IsArray() | ||||
|     @IsOptional() | ||||
|     permissions: Permission[]; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ResponseUserGroup object from a userGroup. | ||||
|      * @param group The userGroup the response shall be build for. | ||||
|      */ | ||||
|     public constructor(group: UserGroup) { | ||||
|         super(group); | ||||
|         this.name = group.name; | ||||
|         this.description = group.description; | ||||
|         this.permissions = group.permissions; | ||||
|     } | ||||
| } | ||||
| import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator"; | ||||
| import { Permission } from '../entities/Permission'; | ||||
| import { UserGroup } from '../entities/UserGroup'; | ||||
| import { ResponsePrincipal } from './ResponsePrincipal'; | ||||
|  | ||||
| /** | ||||
|  * Defines the userGroup response. | ||||
| */ | ||||
| export class ResponseUserGroup extends ResponsePrincipal { | ||||
|     /** | ||||
|      * The userGroup's name. | ||||
|      */ | ||||
|     @IsNotEmpty() | ||||
|     @IsString() | ||||
|     name: string; | ||||
|  | ||||
|     /** | ||||
|      * The userGroup's description. | ||||
|      */ | ||||
|     @IsOptional() | ||||
|     @IsString() | ||||
|     description?: string; | ||||
|  | ||||
|     /** | ||||
|      * The userGroup's permissions. | ||||
|      */ | ||||
|     @IsArray() | ||||
|     @IsOptional() | ||||
|     permissions: Permission[]; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ResponseUserGroup object from a userGroup. | ||||
|      * @param group The userGroup the response shall be build for. | ||||
|      */ | ||||
|     public constructor(group: UserGroup) { | ||||
|         super(group); | ||||
|         this.name = group.name; | ||||
|         this.description = group.description; | ||||
|         this.permissions = group.permissions; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,94 +1,94 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| // --------------- | ||||
| describe('POST /api/donors with errors', () => { | ||||
|     it('creating a new donor without any parameters should return 400', async () => { | ||||
|         const res1 = await axios.post(base + '/api/donors', null, axios_config); | ||||
|         expect(res1.status).toEqual(400); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor without a last name should return 400', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle" | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(400); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with a invalid address should return 404', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle", | ||||
|             "lastname": "last", | ||||
|             "address": 99999999999999999999999999 | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(404); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with a invalid phone number should return 400', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle", | ||||
|             "lastname": "last", | ||||
|             "phone": "123" | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(400); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with a invalid mail address should return 400', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "string", | ||||
|             "middlename": "string", | ||||
|             "lastname": "string", | ||||
|             "phone": null, | ||||
|             "email": "123", | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(400); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor without an address but with receiptNeeded=true 406', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "string", | ||||
|             "middlename": "string", | ||||
|             "lastname": "string", | ||||
|             "receiptNeeded": true | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(406); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('POST /api/donors working', () => { | ||||
|     it('creating a new donor with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last" | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with all non-relationship optional params should return 200', async () => { | ||||
|         const res3 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle", | ||||
|             "lastname": "last", | ||||
|             "receiptNeeded": false | ||||
|         }, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| // --------------- | ||||
| describe('POST /api/donors with errors', () => { | ||||
|     it('creating a new donor without any parameters should return 400', async () => { | ||||
|         const res1 = await axios.post(base + '/api/donors', null, axios_config); | ||||
|         expect(res1.status).toEqual(400); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor without a last name should return 400', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle" | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(400); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with a invalid address should return 404', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle", | ||||
|             "lastname": "last", | ||||
|             "address": 99999999999999999999999999 | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(404); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with a invalid phone number should return 400', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle", | ||||
|             "lastname": "last", | ||||
|             "phone": "123" | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(400); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with a invalid mail address should return 400', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "string", | ||||
|             "middlename": "string", | ||||
|             "lastname": "string", | ||||
|             "phone": null, | ||||
|             "email": "123", | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(400); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor without an address but with receiptNeeded=true 406', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "string", | ||||
|             "middlename": "string", | ||||
|             "lastname": "string", | ||||
|             "receiptNeeded": true | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(406); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('POST /api/donors working', () => { | ||||
|     it('creating a new donor with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last" | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new donor with all non-relationship optional params should return 200', async () => { | ||||
|         const res3 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "middlename": "middle", | ||||
|             "lastname": "last", | ||||
|             "receiptNeeded": false | ||||
|         }, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| @@ -1,75 +1,75 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| describe('Update donor name after adding', () => { | ||||
|     let added_donor; | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last" | ||||
|         }, axios_config); | ||||
|         added_donor = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('valid update should return 200', async () => { | ||||
|         let donor_copy = added_donor | ||||
|         donor_copy.firstname = "second" | ||||
|         const res3 = await axios.put(base + '/api/donors/' + added_donor.id, donor_copy, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         let updated_donor = res3.data | ||||
|         expect(updated_donor).toEqual(donor_copy); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update donor id after adding(should fail)', () => { | ||||
|     let added_donor; | ||||
|     it('creating a new donor with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last" | ||||
|         }, axios_config); | ||||
|         added_donor = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid update should return 406', async () => { | ||||
|         added_donor.id++; | ||||
|         const res3 = await axios.put(base + '/api/donors/' + (added_donor.id - 1), added_donor, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update donor without address but receiptNeeded=true should fail', () => { | ||||
|     let added_donor; | ||||
|     it('creating a new donor with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|         }, axios_config); | ||||
|         added_donor = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid update should return 406', async () => { | ||||
|         added_donor.receiptNeeded = true; | ||||
|         const res3 = await axios.put(base + '/api/donors/' + added_donor.id, added_donor, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| describe('Update donor name after adding', () => { | ||||
|     let added_donor; | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last" | ||||
|         }, axios_config); | ||||
|         added_donor = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('valid update should return 200', async () => { | ||||
|         let donor_copy = added_donor | ||||
|         donor_copy.firstname = "second" | ||||
|         const res3 = await axios.put(base + '/api/donors/' + added_donor.id, donor_copy, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         let updated_donor = res3.data | ||||
|         expect(updated_donor).toEqual(donor_copy); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update donor id after adding(should fail)', () => { | ||||
|     let added_donor; | ||||
|     it('creating a new donor with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last" | ||||
|         }, axios_config); | ||||
|         added_donor = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid update should return 406', async () => { | ||||
|         added_donor.id++; | ||||
|         const res3 = await axios.put(base + '/api/donors/' + (added_donor.id - 1), added_donor, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update donor without address but receiptNeeded=true should fail', () => { | ||||
|     let added_donor; | ||||
|     it('creating a new donor with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/donors', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|         }, axios_config); | ||||
|         added_donor = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid update should return 406', async () => { | ||||
|         added_donor.receiptNeeded = true; | ||||
|         const res3 = await axios.put(base + '/api/donors/' + added_donor.id, added_donor, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| @@ -1,90 +1,90 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| describe('GET /api/organisations', () => { | ||||
|     it('basic get should return 200', async () => { | ||||
|         const res = await axios.get(base + '/api/organisations', axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('POST /api/organisations', () => { | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new org with without a name should return 400', async () => { | ||||
|         const res = await axios.post(base + '/api/organisations', { | ||||
|             "name": null | ||||
|         }, axios_config); | ||||
|         expect(res.status).toEqual(400); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + getting from all orgs', () => { | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('check if org was added', async () => { | ||||
|         const res = await axios.get(base + '/api/organisations', axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|         let added_org = res.data[res.data.length - 1] | ||||
|         delete added_org.id | ||||
|         expect(added_org).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }) | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + getting explicitly', () => { | ||||
|     let added_org_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         let added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('check if org was added', async () => { | ||||
|         const res2 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }) | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| describe('GET /api/organisations', () => { | ||||
|     it('basic get should return 200', async () => { | ||||
|         const res = await axios.get(base + '/api/organisations', axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('POST /api/organisations', () => { | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new org with without a name should return 400', async () => { | ||||
|         const res = await axios.post(base + '/api/organisations', { | ||||
|             "name": null | ||||
|         }, axios_config); | ||||
|         expect(res.status).toEqual(400); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + getting from all orgs', () => { | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('check if org was added', async () => { | ||||
|         const res = await axios.get(base + '/api/organisations', axios_config); | ||||
|         expect(res.status).toEqual(200); | ||||
|         expect(res.headers['content-type']).toContain("application/json") | ||||
|         let added_org = res.data[res.data.length - 1] | ||||
|         delete added_org.id | ||||
|         expect(added_org).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }) | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + getting explicitly', () => { | ||||
|     let added_org_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         let added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('check if org was added', async () => { | ||||
|         const res2 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }) | ||||
|     }); | ||||
| }); | ||||
| @@ -1,132 +1,132 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| // --------------- | ||||
| describe('adding + deletion (non-existant)', () => { | ||||
|     it('delete', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/0', axios_config); | ||||
|         expect(res2.status).toEqual(204); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + deletion (successfull)', () => { | ||||
|     let added_org_id | ||||
|     let added_org | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('delete', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }); | ||||
|     }); | ||||
|     it('check if org really was deleted', async () => { | ||||
|         const res3 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res3.status).toEqual(404); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + deletion with teams still existing (without force)', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('delete org - this should fail with a 406', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res2.status).toEqual(406); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + deletion with teams still existing (with force)', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('delete', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/' + added_org_id + '?force=true', axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id; | ||||
|         delete added_org2.teams; | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null | ||||
|         }); | ||||
|     }); | ||||
|     it('check if org really was deleted', async () => { | ||||
|         const res3 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res3.status).toEqual(404); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| // --------------- | ||||
| describe('adding + deletion (non-existant)', () => { | ||||
|     it('delete', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/0', axios_config); | ||||
|         expect(res2.status).toEqual(204); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + deletion (successfull)', () => { | ||||
|     let added_org_id | ||||
|     let added_org | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('delete', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }); | ||||
|     }); | ||||
|     it('check if org really was deleted', async () => { | ||||
|         const res3 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res3.status).toEqual(404); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + deletion with teams still existing (without force)', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('delete org - this should fail with a 406', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res2.status).toEqual(406); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + deletion with teams still existing (with force)', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('delete', async () => { | ||||
|         const res2 = await axios.delete(base + '/api/organisations/' + added_org_id + '?force=true', axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id; | ||||
|         delete added_org2.teams; | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "test123", | ||||
|             "contact": null, | ||||
|             "address": null | ||||
|         }); | ||||
|     }); | ||||
|     it('check if org really was deleted', async () => { | ||||
|         const res3 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); | ||||
|         expect(res3.status).toEqual(404); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| @@ -1,73 +1,73 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| // --------------- | ||||
| describe('adding + updating name', () => { | ||||
|     let added_org_id | ||||
|     let added_org | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update org', async () => { | ||||
|         const res2 = await axios.put(base + '/api/organisations/' + added_org_id, { | ||||
|             "id": added_org_id, | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }) | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + try updating id (should return 406)', () => { | ||||
|     let added_org_id | ||||
|     let added_org | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update org', async () => { | ||||
|         const res2 = await axios.put(base + '/api/organisations/' + added_org_id, { | ||||
|             "id": added_org_id + 1, | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(406); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| // --------------- | ||||
| describe('adding + updating name', () => { | ||||
|     let added_org_id | ||||
|     let added_org | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update org', async () => { | ||||
|         const res2 = await axios.put(base + '/api/organisations/' + added_org_id, { | ||||
|             "id": added_org_id, | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|         let added_org2 = res2.data | ||||
|         added_org_id = added_org2.id; | ||||
|         delete added_org2.id | ||||
|         expect(added_org2).toEqual({ | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|             "teams": [] | ||||
|         }) | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + try updating id (should return 406)', () => { | ||||
|     let added_org_id | ||||
|     let added_org | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update org', async () => { | ||||
|         const res2 = await axios.put(base + '/api/organisations/' + added_org_id, { | ||||
|             "id": added_org_id + 1, | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "address": null, | ||||
|         }, axios_config); | ||||
|         expect(res2.status).toEqual(406); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| @@ -1,131 +1,131 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + updating name', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update name', async () => { | ||||
|         const res3 = await axios.put(base + '/api/teams/' + added_team_id, { | ||||
|             "id": added_team_id, | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "parentGroup": added_org.id | ||||
|         }, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         let updated_team = res3.data; | ||||
|         added_team.name = "testlelele"; | ||||
|         expect(updated_team).toEqual(added_team) | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + try updating id (should return 406)', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update team', async () => { | ||||
|         added_team.id = added_team.id + 1; | ||||
|         added_team.parentGroup = added_team.parentGroup.id; | ||||
|         const res3 = await axios.put(base + '/api/teams/' + added_team_id, added_team, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('add+update parent org (valid)', () => { | ||||
|     let added_org; | ||||
|     let added_org2; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org.id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res3 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org2 = res3.data; | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update team', async () => { | ||||
|         added_team.parentGroup = added_org2.id; | ||||
|         const res4 = await axios.put(base + '/api/teams/' + added_team_id, added_team, axios_config); | ||||
|         let updated_team = res4.data; | ||||
|         expect(res4.status).toEqual(200); | ||||
|         expect(res4.headers['content-type']).toContain("application/json") | ||||
|         delete added_org2.address; | ||||
|         delete added_org2.contact; | ||||
|         delete added_org2.teams; | ||||
|         expect(updated_team.parentGroup).toEqual(added_org2) | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + updating name', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update name', async () => { | ||||
|         const res3 = await axios.put(base + '/api/teams/' + added_team_id, { | ||||
|             "id": added_team_id, | ||||
|             "name": "testlelele", | ||||
|             "contact": null, | ||||
|             "parentGroup": added_org.id | ||||
|         }, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         let updated_team = res3.data; | ||||
|         added_team.name = "testlelele"; | ||||
|         expect(updated_team).toEqual(added_team) | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('adding + try updating id (should return 406)', () => { | ||||
|     let added_org; | ||||
|     let added_org_id; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org_id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update team', async () => { | ||||
|         added_team.id = added_team.id + 1; | ||||
|         added_team.parentGroup = added_team.parentGroup.id; | ||||
|         const res3 = await axios.put(base + '/api/teams/' + added_team_id, added_team, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('add+update parent org (valid)', () => { | ||||
|     let added_org; | ||||
|     let added_org2; | ||||
|     let added_team; | ||||
|     let added_team_id | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new team with a valid org should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/teams', { | ||||
|             "name": "test123", | ||||
|             "parentGroup": added_org.id | ||||
|         }, axios_config); | ||||
|         added_team = res2.data; | ||||
|         added_team_id = added_team.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res3 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org2 = res3.data; | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('update team', async () => { | ||||
|         added_team.parentGroup = added_org2.id; | ||||
|         const res4 = await axios.put(base + '/api/teams/' + added_team_id, added_team, axios_config); | ||||
|         let updated_team = res4.data; | ||||
|         expect(res4.status).toEqual(200); | ||||
|         expect(res4.headers['content-type']).toContain("application/json") | ||||
|         delete added_org2.address; | ||||
|         delete added_org2.contact; | ||||
|         delete added_org2.teams; | ||||
|         expect(updated_team.parentGroup).toEqual(added_org2) | ||||
|     }); | ||||
| }); | ||||
| @@ -1,160 +1,160 @@ | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| describe('Update runner name after adding', () => { | ||||
|     let added_org; | ||||
|     let added_runner; | ||||
|     let updated_runner; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org.id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('valid update should return 200', async () => { | ||||
|         let runnercopy = added_runner | ||||
|         runnercopy.firstname = "second" | ||||
|         runnercopy.group = added_runner.group.id; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner.id, runnercopy, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         updated_runner = res3.data; | ||||
|         delete added_org.address; | ||||
|         delete added_org.contact; | ||||
|         delete added_org.teams; | ||||
|         runnercopy.group = added_org; | ||||
|         expect(updated_runner).toEqual(runnercopy); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update runner group after adding', () => { | ||||
|     let added_org_id; | ||||
|     let added_org_2; | ||||
|     let added_runner; | ||||
|     let updated_runner; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         let added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org_id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res3 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org_2 = res3.data | ||||
|         delete added_org_2.address; | ||||
|         delete added_org_2.contact; | ||||
|         delete added_org_2.teams; | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('valid group update should return 200', async () => { | ||||
|         added_runner.group = added_org_2.id; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         updated_runner = res3.data | ||||
|         expect(updated_runner.group).toEqual(added_org_2); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update runner id after adding(should fail)', () => { | ||||
|     let added_org_id; | ||||
|     let added_runner; | ||||
|     let added_runner_id; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         let added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org_id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         added_runner_id = added_runner.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid update should return 406', async () => { | ||||
|         added_runner.id++; | ||||
|         added_runner.group = added_runner.group.id; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner_id, added_runner, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update runner group with invalid group after adding', () => { | ||||
|     let added_org; | ||||
|     let added_runner; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org.id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid group update should return 404', async () => { | ||||
|         added_runner.group = 99999999999999999; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, axios_config); | ||||
|         expect(res3.status).toEqual(404); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| import axios from 'axios'; | ||||
| import { config } from '../../config'; | ||||
| const base = "http://localhost:" + config.internal_port | ||||
|  | ||||
| let access_token; | ||||
| let axios_config; | ||||
|  | ||||
| beforeAll(async () => { | ||||
|     const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); | ||||
|     access_token = res.data["access_token"]; | ||||
|     axios_config = { | ||||
|         headers: { "authorization": "Bearer " + access_token }, | ||||
|         validateStatus: undefined | ||||
|     }; | ||||
| }); | ||||
|  | ||||
| describe('Update runner name after adding', () => { | ||||
|     let added_org; | ||||
|     let added_runner; | ||||
|     let updated_runner; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org.id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('valid update should return 200', async () => { | ||||
|         let runnercopy = added_runner | ||||
|         runnercopy.firstname = "second" | ||||
|         runnercopy.group = added_runner.group.id; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner.id, runnercopy, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         updated_runner = res3.data; | ||||
|         delete added_org.address; | ||||
|         delete added_org.contact; | ||||
|         delete added_org.teams; | ||||
|         runnercopy.group = added_org; | ||||
|         expect(updated_runner).toEqual(runnercopy); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update runner group after adding', () => { | ||||
|     let added_org_id; | ||||
|     let added_org_2; | ||||
|     let added_runner; | ||||
|     let updated_runner; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         let added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org_id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res3 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org_2 = res3.data | ||||
|         delete added_org_2.address; | ||||
|         delete added_org_2.contact; | ||||
|         delete added_org_2.teams; | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('valid group update should return 200', async () => { | ||||
|         added_runner.group = added_org_2.id; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, axios_config); | ||||
|         expect(res3.status).toEqual(200); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|         updated_runner = res3.data | ||||
|         expect(updated_runner.group).toEqual(added_org_2); | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update runner id after adding(should fail)', () => { | ||||
|     let added_org_id; | ||||
|     let added_runner; | ||||
|     let added_runner_id; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         let added_org = res1.data | ||||
|         added_org_id = added_org.id; | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org_id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         added_runner_id = added_runner.id; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid update should return 406', async () => { | ||||
|         added_runner.id++; | ||||
|         added_runner.group = added_runner.group.id; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner_id, added_runner, axios_config); | ||||
|         expect(res3.status).toEqual(406); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
| // --------------- | ||||
| describe('Update runner group with invalid group after adding', () => { | ||||
|     let added_org; | ||||
|     let added_runner; | ||||
|     it('creating a new org with just a name should return 200', async () => { | ||||
|         const res1 = await axios.post(base + '/api/organisations', { | ||||
|             "name": "test123" | ||||
|         }, axios_config); | ||||
|         added_org = res1.data | ||||
|         expect(res1.status).toEqual(200); | ||||
|         expect(res1.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('creating a new runner with only needed params should return 200', async () => { | ||||
|         const res2 = await axios.post(base + '/api/runners', { | ||||
|             "firstname": "first", | ||||
|             "lastname": "last", | ||||
|             "group": added_org.id | ||||
|         }, axios_config); | ||||
|         added_runner = res2.data; | ||||
|         expect(res2.status).toEqual(200); | ||||
|         expect(res2.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
|     it('invalid group update should return 404', async () => { | ||||
|         added_runner.group = 99999999999999999; | ||||
|         const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, axios_config); | ||||
|         expect(res3.status).toEqual(404); | ||||
|         expect(res3.headers['content-type']).toContain("application/json") | ||||
|     }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user