Compare commits

...

54 Commits

Author SHA1 Message Date
5a3fc5b2bd Merge pull request 'Password security feature/99-password_checks' (#177) from feature/99-password_checks into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #177
2021-03-26 20:29:35 +00:00
070560e863 Fixed test params
All checks were successful
continuous-integration/drone/pr Build is passing
ref #99
2021-03-26 21:24:53 +01:00
536900091a Fixed empty object getting called
Some checks failed
continuous-integration/drone/pr Build is failing
ref #99
2021-03-26 21:19:58 +01:00
8154e715bb Now forceing user deletion in tests
Some checks failed
continuous-integration/drone/pr Build is failing
ref #99
2021-03-26 21:13:17 +01:00
4c6665062f Reenabled user tests
Some checks failed
continuous-integration/drone/pr Build is failing
ref #99
2021-03-26 21:08:50 +01:00
cb3ea9b1eb Fixed pw not getting hashed currectly;
All checks were successful
continuous-integration/drone/pr Build is passing
ref #99
2021-03-26 21:06:42 +01:00
7a64f23937 Moved to tmp files to better check for other problems
Some checks failed
continuous-integration/drone/pr Build is failing
ref #99
2021-03-26 20:57:42 +01:00
96ba25ec6c No longer using createuser in seeding process
Some checks failed
continuous-integration/drone/pr Build is failing
ref #99
2021-03-26 20:52:58 +01:00
e6a8ebcb5b Added user deletion tests
Some checks failed
continuous-integration/drone/pr Build was killed
ref #99
2021-03-26 20:44:28 +01:00
888cab5898 Added user creation invalid tests
ref #99
2021-03-26 20:41:36 +01:00
383a8095b8 Added user creation valid tests
ref #99
2021-03-26 20:41:25 +01:00
63f6526e4f Updated auth test to comply with the new pw requirements
ref #99
2021-03-26 20:28:08 +01:00
b24e24ff7d Added pw errors to user controller
ref #99
2021-03-26 20:24:08 +01:00
9ce35d8eb7 Added pw errors to me controller
ref #99
2021-03-26 20:23:29 +01:00
48a87e8936 Now checking password rules on user update
ref #99
2021-03-26 20:19:23 +01:00
b8c28ebb08 Formatting
ref #99
2021-03-26 20:18:39 +01:00
5daaa3a73c Now checking password rules on user creation
ref #99
2021-03-26 20:18:08 +01:00
24c38cce26 Added password errors
ref #99
2021-03-26 20:17:00 +01:00
bd00f4f8d5 Added password checker dependency
ref #99
2021-03-26 20:11:22 +01:00
03d76e6d0b 🧾New changelog file version [CI SKIP] [skip ci] 2021-03-26 16:35:23 +00:00
3f8e8ce3a6 Merge pull request 'Release 0.8.0' (#176) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #176
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-03-26 16:34:31 +00:00
c9bd6de476 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-03-26 16:19:28 +00:00
e702118d4d Merge pull request 'Selfservice deletion feature/174-selfservice_deletion' (#175) from feature/174-selfservice_deletion into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #175
2021-03-26 16:18:28 +00:00
97159dd9f8 Removed param from test
All checks were successful
continuous-integration/drone/pr Build is passing
ref #174
2021-03-26 16:56:45 +01:00
942d9dbc76 Merge branch 'dev' into feature/174-selfservice_deletion
Some checks failed
continuous-integration/drone/pr Build was killed
2021-03-26 16:54:34 +01:00
88844e1a44 🧾New changelog file version [CI SKIP] [skip ci] 2021-03-26 15:53:45 +00:00
e76a9cef95 Merge pull request 'Release 0.7.1' (#173) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #173
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-03-26 15:52:41 +00:00
20aeed8778 Added tests for the new endpoint
Some checks failed
continuous-integration/drone/pr Build is failing
ref #174
2021-03-26 16:50:12 +01:00
ccb7ae29a3 Fixed response bug
ref #174
2021-03-26 16:45:30 +01:00
dcb12b0ac2 Added selfservice deletion endpoint
ref #174
2021-03-26 16:42:14 +01:00
dd1258333e Updated old hint
ref #174
2021-03-26 16:42:01 +01:00
3ef3a94b20 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-03-26 14:24:07 +00:00
135852eb9a 🚀Bumped version to v0.7.1
All checks were successful
continuous-integration/drone/push Build is passing
2021-03-26 15:23:05 +01:00
963253cbc8 🧾New changelog file version [CI SKIP] [skip ci] 2021-03-26 14:22:55 +00:00
539a6509b1 Merge pull request 'RESPONSERUNNERCARD fix bugfix/171-responserunnercards' (#172) from bugfix/171-responserunnercards into dev
Some checks failed
continuous-integration/drone/push Build is failing
Thx @philipp :)

Reviewed-on: #172
2021-03-26 14:22:15 +00:00
f3d73d5346 Tests now keep the group
All checks were successful
continuous-integration/drone/pr Build is passing
ref #171
2021-03-26 15:17:05 +01:00
f159252651 Revert "Set timeout even higher b/c sqlite just kills itself during these tests"
Some checks failed
continuous-integration/drone/pr Build is failing
This reverts commit 6ab60998d4.
2021-03-26 15:14:17 +01:00
6ab60998d4 Set timeout even higher b/c sqlite just kills itself during these tests
Some checks failed
continuous-integration/drone/pr Build is failing
ref #171
2021-03-26 15:13:31 +01:00
30d220bc36 Adjusted jest timeout to mitigate sqlite from invalidateing all tests⏱
Some checks failed
continuous-integration/drone/pr Build is failing
ref #171
2021-03-26 15:06:20 +01:00
24aff3bac4 Now resolveing runnercards
ref #171
2021-03-26 14:56:21 +01:00
ce63043887 🧾New changelog file version [CI SKIP] [skip ci] 2021-03-23 17:50:46 +00:00
e40017a6b8 Merge pull request 'Release 0.7.0' (#170) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #170
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-03-23 17:49:45 +00:00
e843a464e7 🧾New changelog file version [CI SKIP] [skip ci]
Some checks failed
continuous-integration/drone/pr Build is failing
2021-03-23 17:44:04 +00:00
d0ae50d557 🚀Bumped version to v0.7.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-03-23 18:42:16 +01:00
7a49e7c5c9 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-03-23 17:42:14 +00:00
1dd64204cc Merge pull request 'Bulk card creation feature/168-runnercards_bulk' (#169) from feature/168-runnercards_bulk into dev
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
Reviewed-on: #169
2021-03-23 17:41:31 +00:00
438ff0fc3f Added bulk card creation tests
All checks were successful
continuous-integration/drone/pr Build is passing
ref #168
2021-03-23 18:19:49 +01:00
c1bbda51f0 Added new "bulk" endpoint
ref #168
2021-03-23 18:16:55 +01:00
4705a39aab 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-03-19 16:41:43 +00:00
4d721f62d9 Merge pull request 'Release 0.6.4' (#167) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #167
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-03-19 16:40:45 +00:00
b0328ffdaf 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-03-19 16:34:14 +00:00
031cede542 🚀Bumped version to v0.6.4
All checks were successful
continuous-integration/drone/push Build is passing
2021-03-19 17:33:17 +01:00
3c69f8c4a8 Adjsuted endpoint 2021-03-19 17:32:46 +01:00
cc6568c381 🧾New changelog file version [CI SKIP] [skip ci] 2021-03-18 15:54:33 +00:00
65 changed files with 530 additions and 59 deletions

View File

@@ -2,15 +2,70 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.7.1](https://git.odit.services/lfk/backend/compare/v0.7.1...v0.7.1)
- Merge pull request 'Release 0.8.0' (#176) from dev into main [`3f8e8ce`](https://git.odit.services/lfk/backend/commit/3f8e8ce3a66a943801c0c8e17885e71feeee744f)
- 🧾New changelog file version [CI SKIP] [skip ci] [`c9bd6de`](https://git.odit.services/lfk/backend/commit/c9bd6de4762fec04e1e02cd3b667838d05ef39a7)
- Merge pull request 'Selfservice deletion feature/174-selfservice_deletion' (#175) from feature/174-selfservice_deletion into dev [`e702118`](https://git.odit.services/lfk/backend/commit/e702118d4d80e362e41bb88c74343d50530d1338)
- Added tests for the new endpoint [`20aeed8`](https://git.odit.services/lfk/backend/commit/20aeed87780247dc6401bba725801fc1874e50b5)
- Removed param from test [`97159dd`](https://git.odit.services/lfk/backend/commit/97159dd9f81aed080c174a3eb8da9e66dfea9b10)
- Added selfservice deletion endpoint [`dcb12b0`](https://git.odit.services/lfk/backend/commit/dcb12b0ac289f8df148ba10ae6389727c16f53fd)
- 🧾New changelog file version [CI SKIP] [skip ci] [`88844e1`](https://git.odit.services/lfk/backend/commit/88844e1a44d87a7dc253bf9aedf2fb3f6cdd1cfe)
- Fixed response bug [`ccb7ae2`](https://git.odit.services/lfk/backend/commit/ccb7ae29a39387c0f2762861565dc22996a2493a)
- Updated old hint [`dd12583`](https://git.odit.services/lfk/backend/commit/dd1258333ef67243f8a8df97c176ec5a054a5e3b)
#### [v0.7.1](https://git.odit.services/lfk/backend/compare/v0.7.0...v0.7.1)
> 26 March 2021
- Merge pull request 'Release 0.7.1' (#173) from dev into main [`e76a9ce`](https://git.odit.services/lfk/backend/commit/e76a9cef956b00de7bbb11b6d863d4f33e3d5a34)
- Revert "Set timeout even higher b/c sqlite just kills itself during these tests" [`f159252`](https://git.odit.services/lfk/backend/commit/f159252651942e442026dbcaae09b242e05d8204)
- Set timeout even higher b/c sqlite just kills itself during these tests [`6ab6099`](https://git.odit.services/lfk/backend/commit/6ab60998d4f716aded93bb3b5d15594fc5e0434a)
- Adjusted jest timeout to mitigate sqlite from invalidateing all tests⏱ [`30d220b`](https://git.odit.services/lfk/backend/commit/30d220bc36a28f224406e49ed27ff3f6b4f409e9)
- 🧾New changelog file version [CI SKIP] [skip ci] [`963253c`](https://git.odit.services/lfk/backend/commit/963253cbc84ed07af13ed0925952ec1b7dcc53ad)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3ef3a94`](https://git.odit.services/lfk/backend/commit/3ef3a94b20c1abf6fd2f19472e5f448b4c72bd7f)
- 🚀Bumped version to v0.7.1 [`135852e`](https://git.odit.services/lfk/backend/commit/135852eb9a91010a4ab972ba9efc7b71dfe4d68f)
- Merge pull request 'RESPONSERUNNERCARD fix bugfix/171-responserunnercards' (#172) from bugfix/171-responserunnercards into dev [`539a650`](https://git.odit.services/lfk/backend/commit/539a6509b17cfd373eef8e443eaa7d41168ac7a9)
- Now resolveing runnercards [`24aff3b`](https://git.odit.services/lfk/backend/commit/24aff3bac458a9886ca40163484bc72733dc766a)
- Tests now keep the group [`f3d73d5`](https://git.odit.services/lfk/backend/commit/f3d73d53467a4d00011d280c24e1e12fbb8e443d)
- 🧾New changelog file version [CI SKIP] [skip ci] [`ce63043`](https://git.odit.services/lfk/backend/commit/ce63043887769e1f92a8c064d6647e0deb81b7fa)
#### [v0.7.0](https://git.odit.services/lfk/backend/compare/v0.6.4...v0.7.0)
> 23 March 2021
- Merge pull request 'Release 0.7.0' (#170) from dev into main [`e40017a`](https://git.odit.services/lfk/backend/commit/e40017a6b88d83d5bfc57ff4603abeaca7a9a37b)
- Added bulk card creation tests [`438ff0f`](https://git.odit.services/lfk/backend/commit/438ff0fc3f246f83b1fa04cb11828f4a61dfcd1e)
- Added new "bulk" endpoint [`c1bbda5`](https://git.odit.services/lfk/backend/commit/c1bbda51f067cbd9ac1a9a5378ae3f5d7b9f4eca)
- 🧾New changelog file version [CI SKIP] [skip ci] [`7a49e7c`](https://git.odit.services/lfk/backend/commit/7a49e7c5c98eb23af1cd0d2084914641e9a1bf90)
- 🧾New changelog file version [CI SKIP] [skip ci] [`e843a46`](https://git.odit.services/lfk/backend/commit/e843a464e747c0d41280484cb54495cb2de2a9e8)
- 🚀Bumped version to v0.7.0 [`d0ae50d`](https://git.odit.services/lfk/backend/commit/d0ae50d5579e969ad33d6b9cfd66dac7fa472223)
- Merge pull request 'Bulk card creation feature/168-runnercards_bulk' (#169) from feature/168-runnercards_bulk into dev [`1dd6420`](https://git.odit.services/lfk/backend/commit/1dd64204cc63fb1a8a4a4aa503c21da42945eafd)
- 🧾New changelog file version [CI SKIP] [skip ci] [`4705a39`](https://git.odit.services/lfk/backend/commit/4705a39aabaad894d332a5062df03840c23c6bfa)
#### [v0.6.4](https://git.odit.services/lfk/backend/compare/v0.6.3...v0.6.4)
> 19 March 2021
- Merge pull request 'Release 0.6.4' (#167) from dev into main [`4d721f6`](https://git.odit.services/lfk/backend/commit/4d721f62d9a5f6a1361ef2811a3a2ff63011b2ad)
- 🧾New changelog file version [CI SKIP] [skip ci] [`b0328ff`](https://git.odit.services/lfk/backend/commit/b0328ffdaffc8ef2e6e01e808c29748f58f42cac)
- 🧾New changelog file version [CI SKIP] [skip ci] [`cc6568c`](https://git.odit.services/lfk/backend/commit/cc6568c3810fed3ff2597df0db73a6ca9e072413)
- 🚀Bumped version to v0.6.4 [`031cede`](https://git.odit.services/lfk/backend/commit/031cede5426742dc3c2b9dc6b049951d7c14871c)
- Adjsuted endpoint [`3c69f8c`](https://git.odit.services/lfk/backend/commit/3c69f8c4a824e588977b06dbb45119cccb03c6bc)
#### [v0.6.3](https://git.odit.services/lfk/backend/compare/v0.6.2...v0.6.3)
> 18 March 2021
- Merge pull request 'Release 0.6.3' (#165) from dev into main [`a3a1395`](https://git.odit.services/lfk/backend/commit/a3a1395a46d7970cff1b8cc2e84306a97791ed88)
- The basic bugfix 🐞 [`fbdadbe`](https://git.odit.services/lfk/backend/commit/fbdadbef1f9eb835e1914e8d3770cca836b4c443)
- The basic bugfix 🐞 [`c87c97c`](https://git.odit.services/lfk/backend/commit/c87c97c90f5e1229f92671b1f2ebe1fa0d2307cd)
- Updated tests 🧪 [`f347b7a`](https://git.odit.services/lfk/backend/commit/f347b7ad4982ed3760117c08e11dca5c3f72d495)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3f9a704`](https://git.odit.services/lfk/backend/commit/3f9a7049e31a6948125a07e847233b804f27ba31)
- 🧾New changelog file version [CI SKIP] [skip ci] [`b08acc6`](https://git.odit.services/lfk/backend/commit/b08acc666035ed766cc6ccfa9a410a54db4d7321)
- 🧾New changelog file version [CI SKIP] [skip ci] [`a6bca59`](https://git.odit.services/lfk/backend/commit/a6bca59ffe06a37f03af21500c442cebeaa74c7e)
- 🚀Bumped version to v0.6.3 [`7a303c2`](https://git.odit.services/lfk/backend/commit/7a303c2b2c267d6dd566b1470649e65bc1c1b2ee)
- Merge pull request 'TrackScan Update bug 🐞bugfix/163-trackscan_updates' (#164) from bugfix/163-trackscan_updates into dev [`6249419`](https://git.odit.services/lfk/backend/commit/6249419fae22e0203c046c1a3cd82c07f94f510c)
- 🧾New changelog file version [CI SKIP] [skip ci] [`a6bca59`](https://git.odit.services/lfk/backend/commit/a6bca59ffe06a37f03af21500c442cebeaa74c7e)
#### [v0.6.2](https://git.odit.services/lfk/backend/compare/v0.6.1...v0.6.2)

View File

@@ -1,6 +1,6 @@
{
"name": "@odit/lfk-backend",
"version": "0.6.3",
"version": "0.7.1",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"author": {
@@ -26,6 +26,7 @@
"argon2": "^0.27.1",
"axios": "^0.21.1",
"body-parser": "^1.19.0",
"check-password-strength": "^2.0.2",
"class-transformer": "0.3.1",
"class-validator": "^0.13.1",
"consola": "^2.15.0",
@@ -102,4 +103,4 @@
"docs/*"
]
}
}
}

View File

@@ -1,7 +1,7 @@
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 { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, 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';
@@ -32,7 +32,7 @@ export class MeController {
return new ResponseUser(user);
}
@Get('/')
@Get('/permissions')
@ResponseSchema(ResponseUserPermissions)
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@OnUndefined(UserNotFoundError)
@@ -48,6 +48,10 @@ export class MeController {
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 })
@ResponseSchema(UsernameContainsIllegalCharacterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainUppercaseLetterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainLowercaseLetterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainNumberError, { statusCode: 406 })
@ResponseSchema(PasswordTooShortError, { 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'] });

View File

@@ -28,7 +28,7 @@ export class RunnerCardController {
@OpenAPI({ description: 'Lists all card.' })
async getAll() {
let responseCards: ResponseRunnerCard[] = new Array<ResponseRunnerCard>();
const cards = await this.cardRepository.find({ relations: ['runner'] });
const cards = await this.cardRepository.find({ relations: ['runner', 'runner.group', 'runner.group.parentGroup'] });
cards.forEach(card => {
responseCards.push(new ResponseRunnerCard(card));
});
@@ -42,11 +42,26 @@ export class RunnerCardController {
@OnUndefined(RunnerCardNotFoundError)
@OpenAPI({ description: "Lists all information about the card whose id got provided." })
async getOne(@Param('id') id: number) {
let card = await this.cardRepository.findOne({ id: id }, { relations: ['runner'] });
let card = await this.cardRepository.findOne({ id: id }, { relations: ['runner', 'runner.group', 'runner.group.parentGroup'] });
if (!card) { throw new RunnerCardNotFoundError(); }
return card.toResponse();
}
@Post('/bulk')
@Authorized("CARD:CREATE")
@ResponseSchema(ResponseEmpty, { statusCode: 200 })
@OpenAPI({ description: "Create blank cards in bulk. <br> Just provide the count as a query param and wait for the 200 response." })
async postBlancoBulk(@QueryParam("count") count: number) {
let createPromises = new Array<any>();
for (let index = 0; index < count; index++) {
createPromises.push(this.cardRepository.save({ runner: null, enabled: true }))
}
await Promise.all(createPromises);
let response = new ResponseEmpty();
response.response = `Created ${count} new blanco cards.`
return response;
}
@Post()
@Authorized("CARD:CREATE")
@ResponseSchema(ResponseRunnerCard)
@@ -55,7 +70,7 @@ export class RunnerCardController {
async post(@Body({ validate: true }) createCard: CreateRunnerCard) {
let card = await createCard.toEntity();
card = await this.cardRepository.save(card);
return (await this.cardRepository.findOne({ id: card.id }, { relations: ['runner'] })).toResponse();
return (await this.cardRepository.findOne({ id: card.id }, { relations: ['runner', 'runner.group', 'runner.group.parentGroup'] })).toResponse();
}
@Put('/:id')
@@ -77,7 +92,7 @@ export class RunnerCardController {
}
await this.cardRepository.save(await card.update(oldCard));
return (await this.cardRepository.findOne({ id: id }, { relations: ['runner'] })).toResponse();
return (await this.cardRepository.findOne({ id: id }, { relations: ['runner', 'runner.group', 'runner.group.parentGroup'] })).toResponse();
}
@Delete('/:id')

View File

@@ -1,12 +1,12 @@
import { Request } from "express";
import * as jwt from "jsonwebtoken";
import { Body, Get, JsonController, OnUndefined, Param, Post, QueryParam, Req, UseBefore } from 'routing-controllers';
import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam, Req, UseBefore } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { config } from '../config';
import { InvalidCredentialsError, JwtNotProvidedError } from '../errors/AuthError';
import { MailSendingError } from '../errors/MailErrors';
import { RunnerEmailNeededError, RunnerNotFoundError, RunnerSelfserviceTimeoutError } from '../errors/RunnerErrors';
import { RunnerEmailNeededError, RunnerHasDistanceDonationsError, RunnerNotFoundError, RunnerSelfserviceTimeoutError } from '../errors/RunnerErrors';
import { RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
import { ScanStationNotFoundError } from '../errors/ScanStationErrors';
import { JwtCreator } from '../jwtcreator';
@@ -23,6 +23,9 @@ import { ResponseScanStation } from '../models/responses/ResponseScanStation';
import { ResponseSelfServiceOrganisation } from '../models/responses/ResponseSelfServiceOrganisation';
import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner';
import { ResponseSelfServiceScan } from '../models/responses/ResponseSelfServiceScan';
import { DonationController } from './DonationController';
import { RunnerCardController } from './RunnerCardController';
import { ScanController } from './ScanController';
@JsonController()
export class RunnerSelfServiceController {
@@ -43,11 +46,50 @@ export class RunnerSelfServiceController {
@ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerNotFoundError)
@OpenAPI({ description: 'Lists all information about yourself. <br> Please provide your runner jwt(that code we gave you during registration) for auth. <br> If you lost your jwt/personalized link please contact support.' })
@OpenAPI({ description: 'Lists all information about yourself. <br> Please provide your runner jwt(that code we gave you during registration) for auth. <br> If you lost your jwt/personalized link please use the forgot endpoint.' })
async get(@Param('jwt') token: string) {
return (new ResponseSelfServiceRunner(await this.getRunner(token)));
}
@Delete('/runners/me/:jwt')
@ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerNotFoundError)
@OpenAPI({ description: 'Deletes all information about yourself. <br> Please provide your runner jwt(that code we gave you during registration) for auth. <br> If you lost your jwt/personalized link please use the forgot endpoint.' })
async remove(@Param('jwt') token: string, @QueryParam("force") force: boolean) {
const responseRunner = await this.getRunner(token);
let runner = await this.runnerRepository.findOne({ id: responseRunner.id });
if (!runner) { return null; }
if (!runner) {
throw new RunnerNotFoundError();
}
const runnerDonations = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["distanceDonations"] })).distanceDonations;
if (runnerDonations.length > 0 && !force) {
throw new RunnerHasDistanceDonationsError();
}
const donationController = new DonationController();
for (let donation of runnerDonations) {
await donationController.remove(donation.id, force);
}
const runnerCards = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["cards"] })).cards;
const cardController = new RunnerCardController;
for (let card of runnerCards) {
await cardController.remove(card.id, force);
}
const runnerScans = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["scans"] })).scans;
const scanController = new ScanController;
for (let scan of runnerScans) {
await scanController.remove(scan.id, force);
}
await this.runnerRepository.delete(runner);
return new ResponseSelfServiceRunner(responseRunner);
}
@Get('/runners/me/:jwt/scans')
@ResponseSchema(ResponseSelfServiceScan, { isArray: true })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })

View File

@@ -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 { UserDeletionNotConfirmedError, UserIdsNotMatchingError, UsernameContainsIllegalCharacterError, UserNotFoundError } from '../errors/UserErrors';
import { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, 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';
@@ -66,6 +66,10 @@ export class UserController {
@ResponseSchema(ResponseUser)
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(UsernameContainsIllegalCharacterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainUppercaseLetterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainLowercaseLetterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainNumberError, { statusCode: 406 })
@ResponseSchema(PasswordTooShortError, { statusCode: 406 })
@OpenAPI({ description: 'Create a new user. <br> If you want to grant permissions to the user you have to create them seperately by posting to /api/permissions after creating the user.' })
async post(@Body({ validate: true }) createUser: CreateUser) {
let user;
@@ -85,6 +89,10 @@ export class UserController {
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 })
@ResponseSchema(UsernameContainsIllegalCharacterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainUppercaseLetterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainLowercaseLetterError, { statusCode: 406 })
@ResponseSchema(PasswordMustContainNumberError, { statusCode: 406 })
@ResponseSchema(PasswordTooShortError, { statusCode: 406 })
@OpenAPI({ description: "Update the user whose id you provided. <br> To change the permissions directly granted to the user please use /api/permissions instead. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) updateUser: UpdateUser) {
let oldUser = await this.userRepository.findOne({ id: id });

View File

@@ -71,4 +71,33 @@ export class UserDeletionNotConfirmedError extends NotAcceptableError {
@IsString()
message = "You are trying to delete a user! \n If you're sure about doing this: provide the ?force=true query param."
}
export class PasswordMustContainUppercaseLetterError extends NotAcceptableError {
@IsString()
name = "PasswordMustContainUppercaseLetterError"
@IsString()
message = "Passwords must contain at least one uppercase letter."
}
export class PasswordMustContainLowercaseLetterError extends NotAcceptableError {
@IsString()
name = "PasswordMustContainLowercaseLetterError"
@IsString()
message = "Passwords must contain at least one lowercase letter."
}
export class PasswordMustContainNumberError extends NotAcceptableError {
@IsString()
name = "PasswordMustContainNumberError"
@IsString()
message = "Passwords must contain at least one number."
}
export class PasswordTooShortError extends NotAcceptableError {
@IsString()
name = "PasswordTooShortError"
@IsString()
message = "Passwords must be at least ten characters long."
}

View File

@@ -1,9 +1,10 @@
import * as argon2 from "argon2";
import { passwordStrength } from "check-password-strength";
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import * as uuid from 'uuid';
import { config } from '../../../config';
import { UserEmailNeededError, UsernameContainsIllegalCharacterError } from '../../../errors/UserErrors';
import { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, UserEmailNeededError, UsernameContainsIllegalCharacterError } from '../../../errors/UserErrors';
import { UserGroupNotFoundError } from '../../../errors/UserGroupErrors';
import { User } from '../../entities/User';
import { UserGroup } from '../../entities/UserGroup';
@@ -94,7 +95,13 @@ export class CreateUser {
if (!this.email) {
throw new UserEmailNeededError();
}
if (this.username.includes("@")) { throw new UsernameContainsIllegalCharacterError(); }
if (this.username?.includes("@")) { throw new UsernameContainsIllegalCharacterError(); }
let password_strength = passwordStrength(this.password);
if (!password_strength.contains.includes("uppercase")) { throw new PasswordMustContainUppercaseLetterError(); }
if (!password_strength.contains.includes("lowercase")) { throw new PasswordMustContainLowercaseLetterError(); }
if (!password_strength.contains.includes("number")) { throw new PasswordMustContainNumberError(); }
if (!(password_strength.length > 9)) { throw new PasswordTooShortError(); }
newUser.email = this.email
newUser.username = this.username

View File

@@ -1,12 +1,14 @@
import * as argon2 from "argon2";
import { passwordStrength } from "check-password-strength";
import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { config } from '../../../config';
import { UserEmailNeededError, UsernameContainsIllegalCharacterError } from '../../../errors/UserErrors';
import { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, UserEmailNeededError, UsernameContainsIllegalCharacterError } from '../../../errors/UserErrors';
import { UserGroupNotFoundError } from '../../../errors/UserGroupErrors';
import { User } from '../../entities/User';
import { UserGroup } from '../../entities/UserGroup';
/**
* This class is used to update a User entity (via put request).
*/
@@ -104,6 +106,11 @@ export class UpdateUser {
if (this.username.includes("@")) { throw new UsernameContainsIllegalCharacterError(); }
if (this.password) {
let password_strength = passwordStrength(this.password);
if (!password_strength.contains.includes("uppercase")) { throw new PasswordMustContainUppercaseLetterError(); }
if (!password_strength.contains.includes("lowercase")) { throw new PasswordMustContainLowercaseLetterError(); }
if (!password_strength.contains.includes("number")) { throw new PasswordMustContainNumberError(); }
if (!(password_strength.length > 9)) { throw new PasswordTooShortError(); }
user.password = await argon2.hash(this.password + user.uuid);
user.refreshTokenCount = user.refreshTokenCount + 1;
}

View File

@@ -1,14 +1,14 @@
import * as argon2 from "argon2";
import { Connection } from 'typeorm';
import { Factory, Seeder } from 'typeorm-seeding';
import * as uuid from 'uuid';
import { CreatePermission } from '../models/actions/create/CreatePermission';
import { CreateUser } from '../models/actions/create/CreateUser';
import { CreateUserGroup } from '../models/actions/create/CreateUserGroup';
import { Permission } from '../models/entities/Permission';
import { User } from '../models/entities/User';
import { UserGroup } from '../models/entities/UserGroup';
import { PermissionAction } from '../models/enums/PermissionAction';
import { PermissionTarget } from '../models/enums/PermissionTargets';
/**
* Seeds a admin group with a demo user into the database for initial setup and auto recovery.
* We know that the nameing isn't perfectly fitting. Feel free to change it.
@@ -16,7 +16,7 @@ import { PermissionTarget } from '../models/enums/PermissionTargets';
export default class SeedUsers implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<any> {
let adminGroup: UserGroup = await this.createAdminGroup(connection);
await this.createUser(connection, adminGroup.id);
await this.createUser(connection, adminGroup);
await this.createPermissions(connection, adminGroup.id);
}
@@ -27,15 +27,16 @@ export default class SeedUsers implements Seeder {
return await connection.getRepository(UserGroup).save(await adminGroup.toEntity());
}
public async createUser(connection: Connection, group: number) {
let initialUser = new CreateUser();
public async createUser(connection: Connection, group: UserGroup) {
let initialUser = new User();
initialUser.firstname = "demo";
initialUser.lastname = "demo";
initialUser.username = "demo";
initialUser.password = "demo";
initialUser.uuid = uuid.v4();
initialUser.password = await argon2.hash("demo" + initialUser.uuid);
initialUser.email = "demo@dev.lauf-fuer-kaya.de"
initialUser.groups = group;
return await connection.getRepository(User).save(await initialUser.toEntity());
initialUser.groups = [group];
return await connection.getRepository(User).save(initialUser);
}
public async createPermissions(connection: Connection, principal: number) {

View File

@@ -5,6 +5,7 @@ const base = "http://localhost:" + config.internal_port
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
axios_config = {
validateStatus: undefined
};

View File

@@ -8,14 +8,15 @@ const axios_config = {
};;
beforeAll(async () => {
jest.setTimeout(20000);
const res_login = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
await axios.post(base + '/api/users', {
"firstname": "demo_logout",
"middlename": "demo_logout",
"lastname": "demo_logout",
"username": "demo_logout",
"password": "demo_logout",
"email": "demo_logout@dev.lauf-fuer-kaya.de"
"firstname": "demo_logoutASD123",
"middlename": "demo_logoutASD123",
"lastname": "demo_logoutASD123",
"username": "demo_logoutASD123",
"password": "demo_logoutASD123",
"email": "demo_logoutASD123@dev.lauf-fuer-kaya.de"
}, {
headers: { "authorization": "Bearer " + res_login.data["access_token"] },
validateStatus: undefined
@@ -25,7 +26,7 @@ beforeAll(async () => {
describe('POST /api/auth/logout valid', () => {
let refresh_coookie;
it('valid logout with token in cookie should return 200', async () => {
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logout", password: "demo_logout" });
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logoutASD123", password: "demo_logoutASD123" });
refresh_coookie = res_login.headers["set-cookie"];
const res = await axios.post(base + '/api/auth/logout', null, {
headers: { "Cookie": refresh_coookie },
@@ -34,7 +35,7 @@ describe('POST /api/auth/logout valid', () => {
expect(res.status).toEqual(200);
});
it('valid logout with token in body should return 200', async () => {
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logout", password: "demo_logout" });
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logoutASD123", password: "demo_logoutASD123" });
const res = await axios.post(base + '/api/auth/logout', { token: res_login.data["refresh_token"] }, axios_config);
expect(res.status).toEqual(200);
});

View File

@@ -8,14 +8,15 @@ const axios_config = {
};;
beforeAll(async () => {
jest.setTimeout(20000);
const res_login = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
await axios.post(base + '/api/users', {
"firstname": "demo_refresh",
"middlename": "demo_refresh",
"lastname": "demo_refresh",
"username": "demo_refresh",
"password": "demo_refresh",
"email": "demo_refresh@dev.lauf-fuer-kaya.de"
"firstname": "demo_refreshASD312",
"middlename": "demo_refreshASD312",
"lastname": "demo_refreshASD312",
"username": "demo_refreshASD312",
"password": "demo_refreshASD312",
"email": "demo_refreshASD312@dev.lauf-fuer-kaya.de"
}, {
headers: { "authorization": "Bearer " + res_login.data["access_token"] },
validateStatus: undefined
@@ -24,7 +25,7 @@ beforeAll(async () => {
describe('POST /api/auth/refresh valid', () => {
it('valid refresh with token in cookie should return 200', async () => {
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_refresh", password: "demo_refresh" });
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_refreshASD312", password: "demo_refreshASD312" });
const res = await axios.post(base + '/api/auth/refresh', null, {
headers: { "Cookie": res_login.headers["set-cookie"] },
validateStatus: undefined
@@ -32,7 +33,7 @@ describe('POST /api/auth/refresh valid', () => {
expect(res.status).toEqual(200);
});
it('valid refresh with token in body should return 200', async () => {
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_refresh", password: "demo_refresh" });
const res_login = await axios.post(base + '/api/auth/login', { username: "demo_refreshASD312", password: "demo_refreshASD312" });
const res = await axios.post(base + '/api/auth/refresh', { token: res_login.data["refresh_token"] }, axios_config);
expect(res.status).toEqual(200);
});

View File

@@ -8,25 +8,26 @@ const axios_config = {
};;
beforeAll(async () => {
jest.setTimeout(20000);
const res_login = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
await axios.post(base + '/api/users', {
"firstname": "demo_reset",
"middlename": "demo_reset",
"lastname": "demo_reset",
"username": "demo_reset",
"password": "demo_reset",
"email": "demo_reset1@dev.lauf-fuer-kaya.de"
"firstname": "demo_resetASD312",
"middlename": "demo_resetASD312",
"lastname": "demo_resetASD312",
"username": "demo_resetASD312",
"password": "demo_resetASD312",
"email": "demo_resetASD3121@dev.lauf-fuer-kaya.de"
}, {
headers: { "authorization": "Bearer " + res_login.data["access_token"] },
validateStatus: undefined
});
await axios.post(base + '/api/users', {
"firstname": "demo_reset2",
"middlename": "demo_reset2",
"lastname": "demo_reset2",
"username": "demo_reset2",
"password": "demo_reset2",
"email": "demo_reset2@dev.lauf-fuer-kaya.de"
"firstname": "demo_resetASD3122",
"middlename": "demo_resetASD3122",
"lastname": "demo_resetASD3122",
"username": "demo_resetASD3122",
"password": "demo_resetASD3122",
"email": "demo_resetASD3122@dev.lauf-fuer-kaya.de"
}, {
headers: { "authorization": "Bearer " + res_login.data["access_token"] },
validateStatus: undefined
@@ -36,7 +37,7 @@ beforeAll(async () => {
describe('POST /api/auth/reset valid', () => {
let reset_token;
it('valid reset token request should return 200 (500 w/o correct auth)', async () => {
const res1 = await axios.post(base + '/api/auth/reset', { email: "demo_reset1@dev.lauf-fuer-kaya.de" }, axios_config);
const res1 = await axios.post(base + '/api/auth/reset', { email: "demo_resetASD3121@dev.lauf-fuer-kaya.de" }, axios_config);
reset_token = res1.data.resetToken;
expect(res1.status).toEqual(200);
});
@@ -44,8 +45,8 @@ describe('POST /api/auth/reset valid', () => {
// ---------------
describe('POST /api/auth/reset invalid requests', () => {
it('request another password reset before the timeout should return 406', async () => {
const res1 = await axios.post(base + '/api/auth/reset', { email: "demo_reset2@dev.lauf-fuer-kaya.de" }, axios_config);
const res2 = await axios.post(base + '/api/auth/reset', { email: "demo_reset2@dev.lauf-fuer-kaya.de" }, axios_config);
const res1 = await axios.post(base + '/api/auth/reset', { email: "demo_resetASD3122@dev.lauf-fuer-kaya.de" }, axios_config);
const res2 = await axios.post(base + '/api/auth/reset', { email: "demo_resetASD3122@dev.lauf-fuer-kaya.de" }, axios_config);
expect(res2.status).toEqual(406);
});
});

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {
@@ -85,7 +86,6 @@ describe('POST /api/cards successfully (with runner)', () => {
"lastname": "last",
"group": added_org.id
}, axios_config);
delete res2.data.group;
added_runner = res2.data;
expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json")
@@ -148,4 +148,27 @@ describe('POST /api/cards successfully (with runner)', () => {
"responseType": "RUNNERCARD"
});
});
});
// ---------------
describe('POST /api/cards/bulk successfully', () => {
it('creating a single new bulk card should return 200', async () => {
const res = await axios.post(base + '/api/cards/bulk?count=1', {}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('creating 50 new bulk card should return 200', async () => {
const res = await axios.post(base + '/api/cards/bulk?count=50', {}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('creating 250 new bulk card should return 200', async () => {
const res = await axios.post(base + '/api/cards/bulk?count=250', {}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('creating 2000 new bulk card should return 200', async () => {
const res = await axios.post(base + '/api/cards/bulk?count=2000', {}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
});

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {
@@ -63,7 +64,6 @@ describe('adding + updating card.runner successfully', () => {
"lastname": "last",
"group": added_org.id
}, axios_config);
delete res2.data.group;
added_runner = res2.data;
expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json")
@@ -74,7 +74,6 @@ describe('adding + updating card.runner successfully', () => {
"lastname": "last",
"group": added_org.id
}, axios_config);
delete res2.data.group;
added_runner2 = res2.data;
expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json")

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -5,6 +5,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -5,6 +5,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {
@@ -15,7 +16,7 @@ beforeAll(async () => {
});
// ---------------
describe('adding + deletion (non-existant)', () => {
describe('deletion (non-existant)', () => {
it('delete', async () => {
const res2 = await axios.delete(base + '/api/organizations/0', axios_config);
expect(res2.status).toEqual(204);

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -5,6 +5,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -0,0 +1,66 @@
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
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('delete selfservice runner invalid', () => {
let added_runner;
it('registering as citizen with minimal params should return 200', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"lastname": "string",
"email": "user@example.com"
}, axios_config);
added_runner = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('delete with valid jwt should return 200', async () => {
const res = await axios.delete(base + '/api/runners/me/' + added_runner.token, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('delete with valid jwt but non-existant runner should return 200', async () => {
const res = await axios.delete(base + '/api/runners/me/' + added_runner.token, axios_config);
expect(res.status).toEqual(404);
expect(res.headers['content-type']).toContain("application/json");
});
it('delete with invalid jwt should return 401', async () => {
const res = await axios.delete(base + '/api/runners/me/123.123', axios_config);
expect(res.status).toEqual(401);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('delete selfservice runner valid', () => {
let added_runner;
it('registering as citizen with minimal params should return 200', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"lastname": "string",
"email": "user@example.com"
}, axios_config);
added_runner = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('delete with valid jwt should return 200', async () => {
const res = await axios.delete(base + '/api/runners/me/' + added_runner.token, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
delete added_runner.token;
expect(res.data).toEqual(added_runner);
});
});

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -6,6 +6,7 @@ let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {

View File

@@ -0,0 +1,51 @@
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
let access_token;
let axios_config;
beforeAll(async () => {
jest.setTimeout(20000);
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/users/0?force=true', axios_config);
expect(res2.status).toEqual(204);
});
});
// ---------------
describe('adding + deletion (successfull)', () => {
let added_user
it('valid user creation with minimal parameters should return 200', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "demo_123_123_123asdASD@example.com",
"password": "demo_123_123_123asdASD",
"enabled": true
}
, axios_config);
added_user = res.data;
expect(res.status).toEqual(200);
});
it('delete', async () => {
const res2 = await axios.delete(base + '/api/users/' + added_user.id + "?force=true", axios_config);
expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json")
});
it('check if user really was deleted', async () => {
const res3 = await axios.get(base + '/api/users/' + added_user.id, axios_config);
expect(res3.status).toEqual(404);
expect(res3.headers['content-type']).toContain("application/json")
});
});

View File

@@ -0,0 +1,113 @@
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
let axios_config = {};
beforeAll(async () => {
jest.setTimeout(20000);
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
let access_token = res.data["access_token"];
axios_config = {
headers: { "authorization": "Bearer " + access_token },
validateStatus: undefined
};
});
describe('POST /api/users valid', () => {
it('valid user creation with minimal parameters should return 200', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123",
"lastname": "demo_createASD123",
"password": "demo_createASD123",
"email": "demo_createASD123@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(200);
});
it('valid user creation with all parameters should return 200', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_2",
"middlename": "demo_createASD123_2",
"lastname": "demo_createASD123_2",
"username": "demo_createASD123_2",
"password": "demo_createASD123_2",
"email": "demo_createASD123_2@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(200);
});
});
// ---------------
describe('POST /api/users invalid -> 400', () => {
it('user creation w/o firstname should return 400', async () => {
const res = await axios.post(base + '/api/users', {
"lastname": "demo_createASD123_3",
"password": "demo_createASD123_3",
"email": "demo_createASD123_3@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(400);
});
it('user creation w/o lastname should return 400', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_3",
"password": "demo_createASD123_3",
"email": "demo_createASD123_3@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(400);
});
it('user creation w/o password should return 400', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_3",
"lastname": "demo_createASD123_3",
"email": "demo_createASD123_3@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(400);
});
it('user creation w/o email should return 400', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_3",
"lastname": "demo_createASD123_3",
"password": "demo_createASD123_3"
}, axios_config);
expect(res.status).toEqual(400);
});
});
// ---------------
describe('POST /api/users invalid -> Password errors', () => {
it('user creation w/ invalid password -> No numbers should return 406', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_4",
"lastname": "demo_createASD123_4",
"password": "demo_createASD",
"email": "demo_createASD123_4@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(406);
});
it('user creation w/ invalid password -> No uppercase should return 406', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_4",
"lastname": "demo_createASD123_4",
"password": "demo_create_4",
"email": "demo_createASD123_4@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(406);
});
it('user creation w/ invalid password -> No lowercase should return 406', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_4",
"lastname": "demo_createASD123_4",
"password": "DEMO123123ASD",
"email": "demo_createASD123_4@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(406);
});
it('user creation w/ invalid password -> Too short should return 406', async () => {
const res = await axios.post(base + '/api/users', {
"firstname": "demo_createASD123_4",
"lastname": "demo_createASD123_4",
"password": "1Aa_",
"email": "demo_createASD123_4@dev.lauf-fuer-kaya.de"
}, axios_config);
expect(res.status).toEqual(406);
});
});