Compare commits

...

49 Commits

Author SHA1 Message Date
dd3c9275d6 Merge pull request 'Alpha Release 0.4.6' (#148) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #148
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-02-26 16:50:03 +00:00
764b7ffe00 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-26 16:48:33 +00:00
d870b2fd01 Merge pull request 'Fixed wrong body acceptance type' (#150) from bugfix/146-usergroup_update into dev
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #150
2021-02-26 16:48:16 +00:00
aaec09d2ab Fixed wrong body acceptance type
All checks were successful
continuous-integration/drone/pr Build is passing
ref #146
2021-02-26 17:32:26 +01:00
bce8811925 📖New license file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-25 19:41:04 +00:00
3afc207903 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-25 19:39:39 +00:00
fca997beb8 Merge branch 'dev' of git.odit.services:lfk/backend into dev
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-02-25 20:39:21 +01:00
39ebfbf0b6 Pinned package version to avoid dependency conflicts 📌
yeet
2021-02-25 20:39:16 +01:00
3736b29e54 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-25 19:33:24 +00:00
b4c9369a53 Merge branch 'dev' of git.odit.services:lfk/backend into dev
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is passing
2021-02-25 20:33:04 +01:00
5d6c8c957a Quick bugfix 2021-02-25 20:33:00 +01:00
09fe47b9aa 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-25 19:30:37 +00:00
b4acd157fc 🚀Bumped version to v0.4.6
Some checks failed
continuous-integration/drone/push Build is failing
2021-02-25 20:30:16 +01:00
b1fced7764 📖New license file version [CI SKIP] [skip ci] 2021-02-24 20:00:08 +00:00
c0cafb4d51 🧾New changelog file version [CI SKIP] [skip ci] 2021-02-24 19:59:05 +00:00
45d61b487e Merge pull request 'New org selfservice endpoint feature/146-more_selfservice_endpoints' (#147) from feature/146-more_selfservice_endpoints into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #147
2021-02-24 19:58:47 +00:00
28ef139a70 Added tests for the new org selfservice endpoints
All checks were successful
continuous-integration/drone/pr Build is passing
ref #146
2021-02-24 18:32:56 +01:00
656f63dfd5 Added selfservice org info endpoint
ref #146
2021-02-24 18:23:08 +01:00
ba3b5eeefc Added selfservice org response model
ref #146
2021-02-24 18:20:31 +01:00
ba396e0eba Added selfservice team response model
ref #146
2021-02-24 18:18:10 +01:00
3c11d88557 Added new response types
ref #146
2021-02-24 18:17:30 +01:00
305fa0078d 🧾New changelog file version [CI SKIP] [skip ci] 2021-02-09 18:25:18 +00:00
a46d14278b Merge pull request 'Alpha release 0.4.5' (#145) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #145
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-02-09 18:24:30 +00:00
680ae8ebbb 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-09 18:19:21 +00:00
cc869f69ad 🚀Bumped version to v0.4.5
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-02-09 19:18:46 +01:00
b9aac71676 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-09 18:18:22 +00:00
a30a342e00 Merge pull request 'usergroups/permissions endpoint feature/143-usergroup_permissions_endpoint' (#144) from feature/143-usergroup_permissions_endpoint into dev
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
Reviewed-on: #144
2021-02-09 18:18:04 +00:00
bdcfce88cb Now all /usergroups endpoints return ResponseUserGroup
All checks were successful
continuous-integration/drone/pr Build is passing
ref #143
2021-02-09 18:27:11 +01:00
dd81f4c7e4 Merge branch 'feature/143-usergroup_permissions_endpoint' of git.odit.services:lfk/backend into feature/143-usergroup_permissions_endpoint
# Conflicts:
#	src/models/responses/ResponseUserGroup.ts
2021-02-09 18:26:33 +01:00
416f2a1366 The ResponseUserGroup now returns their permisssions as a string array
ref #143
2021-02-09 18:26:22 +01:00
5e353db206 The ResponseUserGroup now returns their permisssions as a string array
ref #143
2021-02-09 18:26:16 +01:00
0c9867d706 Implemented /groups/permissions endpoint
ref #143
2021-02-09 18:18:00 +01:00
8379c3e29c 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-09 16:47:57 +00:00
c4edccace7 Merge pull request 'Alpha release 0.4.4' (#142) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #142
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-02-09 16:47:31 +00:00
74de6559d7 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-08 16:34:37 +00:00
a6f73c733c 🚀Bumped version to v0.4.4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-02-08 17:34:03 +01:00
ca3d093e54 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-08 16:33:37 +00:00
28cfbaa662 Merge pull request 'Expanded runner response feature/140-runner_group_parent' (#141) from feature/140-runner_group_parent into dev
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
Reviewed-on: #141
2021-02-08 16:33:21 +00:00
90e1ad7db7 Adjusted test for the new response depth
All checks were successful
continuous-integration/drone/pr Build is passing
ref #140
2021-02-08 16:51:09 +01:00
906a1dc9e7 The group/runners endpoints now also deliver the runner's group's parentGroup
ref #140
2021-02-08 16:48:20 +01:00
5872c6335b Adjusted test for the new response depth
ref #140
2021-02-08 16:46:07 +01:00
701706c028 Now loading runner's group's parentgroup with every runner controller request
ref #140
2021-02-08 16:40:17 +01:00
09bbc70f5f 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-07 12:43:57 +00:00
dd9cb6d3ef Merge pull request 'Alpha Release 0.4.3' (#139) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #139
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-02-07 12:43:30 +00:00
23c732b690 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-07 12:40:54 +00:00
656d564baa 🚀Bumped version to v0.4.3
All checks were successful
continuous-integration/drone/push Build is passing
2021-02-07 13:40:32 +01:00
f3f5cb462e 🧾New changelog file version [CI SKIP] [skip ci] 2021-02-07 12:38:54 +00:00
9959172f2a Merge pull request 'Bugfix for @lfk/frontend/#43' (#138) from bugfix/118-encode_jwt_in_mail into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #138
2021-02-07 12:38:34 +00:00
8f0a396dd0 Bugfix for @lfk/frontend/#43
All checks were successful
continuous-integration/drone/pr Build is passing
2021-02-07 13:37:01 +01:00
17 changed files with 411 additions and 144 deletions

View File

@@ -2,8 +2,73 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.4.6](https://git.odit.services/lfk/backend/compare/v0.4.5...v0.4.6)
- Merge pull request 'Fixed wrong body acceptance type' (#150) from bugfix/146-usergroup_update into dev [`d870b2f`](https://git.odit.services/lfk/backend/commit/d870b2fd01b11b1732fcbb6feecaf6a6155fa702)
- Added tests for the new org selfservice endpoints [`28ef139`](https://git.odit.services/lfk/backend/commit/28ef139a70e0c063982b2eb9167b7abe41db1621)
- Added selfservice org response model [`ba3b5ee`](https://git.odit.services/lfk/backend/commit/ba3b5eeefc45f9bd94aef24f9f509f6835f5ea7c)
- Added selfservice team response model [`ba396e0`](https://git.odit.services/lfk/backend/commit/ba396e0eba15647b3004437a5a9949c7a69e828d)
- 📖New license file version [CI SKIP] [skip ci] [`bce8811`](https://git.odit.services/lfk/backend/commit/bce8811925e7f77c64fc507d55335ac45b0e5572)
- 📖New license file version [CI SKIP] [skip ci] [`b1fced7`](https://git.odit.services/lfk/backend/commit/b1fced77640b6c26438331474f368f2b0708b672)
- Added selfservice org info endpoint [`656f63d`](https://git.odit.services/lfk/backend/commit/656f63dfd5fdbe13554fc98440e416be7e56d909)
- 🧾New changelog file version [CI SKIP] [skip ci] [`c0cafb4`](https://git.odit.services/lfk/backend/commit/c0cafb4d510116773fed12592cad1efc2ef09f38)
- 🧾New changelog file version [CI SKIP] [skip ci] [`09fe47b`](https://git.odit.services/lfk/backend/commit/09fe47b9aaac47b65d4e910ef89d558c47fd7364)
- Fixed wrong body acceptance type [`aaec09d`](https://git.odit.services/lfk/backend/commit/aaec09d2ab08a76e9d367fdfefc01cea5588f1b9)
- Pinned package version to avoid dependency conflicts 📌 [`39ebfbf`](https://git.odit.services/lfk/backend/commit/39ebfbf0b633ecc479a33fdf851cd6550616bfee)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3736b29`](https://git.odit.services/lfk/backend/commit/3736b29e5435abb05de03e5d99d9adb438cd7d7e)
- 🧾New changelog file version [CI SKIP] [skip ci] [`305fa00`](https://git.odit.services/lfk/backend/commit/305fa0078d44b39b0391e84ba67b048285cf77b9)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3afc207`](https://git.odit.services/lfk/backend/commit/3afc207903c9cf1e62e6f4a62601b4213f608192)
- Quick bugfix [`5d6c8c9`](https://git.odit.services/lfk/backend/commit/5d6c8c957acd098a20e674ce5529f60cbc9f4151)
- 🚀Bumped version to v0.4.6 [`b4acd15`](https://git.odit.services/lfk/backend/commit/b4acd157fc075154a60946c1ee8876ee5f5dfbee)
- Merge pull request 'New org selfservice endpoint feature/146-more_selfservice_endpoints' (#147) from feature/146-more_selfservice_endpoints into dev [`45d61b4`](https://git.odit.services/lfk/backend/commit/45d61b487e8e6fdd8e00c184a08c9d6e34a1b6bf)
- Added new response types [`3c11d88`](https://git.odit.services/lfk/backend/commit/3c11d88557a2612bf4320ff669323bc048634e94)
#### [v0.4.5](https://git.odit.services/lfk/backend/compare/v0.4.4...v0.4.5)
> 9 February 2021
- Merge pull request 'Alpha release 0.4.5' (#145) from dev into main [`a46d142`](https://git.odit.services/lfk/backend/commit/a46d14278b9a084ca54f8f90e5e70b04739c2dd7)
- 🚀Bumped version to v0.4.5 [`cc869f6`](https://git.odit.services/lfk/backend/commit/cc869f69add1f1a175ff94510d52888f81bccb69)
- 🧾New changelog file version [CI SKIP] [skip ci] [`680ae8e`](https://git.odit.services/lfk/backend/commit/680ae8ebbb39d103085fe1fe8781d71b3c3ed055)
- 🧾New changelog file version [CI SKIP] [skip ci] [`b9aac71`](https://git.odit.services/lfk/backend/commit/b9aac7167681ff0945e538dd177abd6f97771bf2)
- Merge pull request 'usergroups/permissions endpoint feature/143-usergroup_permissions_endpoint' (#144) from feature/143-usergroup_permissions_endpoint into dev [`a30a342`](https://git.odit.services/lfk/backend/commit/a30a342e00ba944f8014044bba28141c0657a17f)
- Implemented /groups/permissions endpoint [`0c9867d`](https://git.odit.services/lfk/backend/commit/0c9867d70616615c8f3c72bbec37a4441e4868ef)
- Now all /usergroups endpoints return ResponseUserGroup [`bdcfce8`](https://git.odit.services/lfk/backend/commit/bdcfce88cbe069f9ba1925fcaac06367a109d2b7)
- The ResponseUserGroup now returns their permisssions as a string array [`416f2a1`](https://git.odit.services/lfk/backend/commit/416f2a1366c570998011d022ebd7f5f44276b2c9)
- The ResponseUserGroup now returns their permisssions as a string array [`5e353db`](https://git.odit.services/lfk/backend/commit/5e353db2061c30b4d10965c47f0dcbecb7f59fc5)
- 🧾New changelog file version [CI SKIP] [skip ci] [`8379c3e`](https://git.odit.services/lfk/backend/commit/8379c3e29c45f0d7c4c84bce1f3abc718158fa84)
#### [v0.4.4](https://git.odit.services/lfk/backend/compare/v0.4.3...v0.4.4)
> 9 February 2021
- Merge pull request 'Alpha release 0.4.4' (#142) from dev into main [`c4edcca`](https://git.odit.services/lfk/backend/commit/c4edccace78765dd5caa0f0e79c52f07c8a3568e)
- 🧾New changelog file version [CI SKIP] [skip ci] [`ca3d093`](https://git.odit.services/lfk/backend/commit/ca3d093e54bfaaa77c97e96738a74eeb25aee440)
- Now loading runner's group's parentgroup with every runner controller request [`701706c`](https://git.odit.services/lfk/backend/commit/701706c0289b357439608b4e2eaa66c617d16e9d)
- 🧾New changelog file version [CI SKIP] [skip ci] [`74de655`](https://git.odit.services/lfk/backend/commit/74de6559d7c5e8c6d257d41dc91396b53bf0c071)
- The group/runners endpoints now also deliver the runner's group's parentGroup [`906a1dc`](https://git.odit.services/lfk/backend/commit/906a1dc9e79ea4eb298a561cf98e6ae42b3ae4ec)
- 🚀Bumped version to v0.4.4 [`a6f73c7`](https://git.odit.services/lfk/backend/commit/a6f73c733c8cfc8d84beb7e0bbd5bcd1313df9d0)
- Merge pull request 'Expanded runner response feature/140-runner_group_parent' (#141) from feature/140-runner_group_parent into dev [`28cfbaa`](https://git.odit.services/lfk/backend/commit/28cfbaa6624d0bc65e2a9b72ffed17060e828735)
- 🧾New changelog file version [CI SKIP] [skip ci] [`09bbc70`](https://git.odit.services/lfk/backend/commit/09bbc70f5fd1f026148be07fe889a6907bc3f75a)
- Adjusted test for the new response depth [`90e1ad7`](https://git.odit.services/lfk/backend/commit/90e1ad7db72732d13002c87461c33560b74befa6)
- Adjusted test for the new response depth [`5872c63`](https://git.odit.services/lfk/backend/commit/5872c6335be573d849cdc3746b261c6cf476c3de)
#### [v0.4.3](https://git.odit.services/lfk/backend/compare/v0.4.2...v0.4.3)
> 7 February 2021
- Merge pull request 'Alpha Release 0.4.3' (#139) from dev into main [`dd9cb6d`](https://git.odit.services/lfk/backend/commit/dd9cb6d3ef60cb118391abc2ba17fd0f83db0b1c)
- 🚀Bumped version to v0.4.3 [`656d564`](https://git.odit.services/lfk/backend/commit/656d564baa8c8bf1f63523b0301ad9ff23e08aa4)
- Bugfix for @lfk/frontend/#43 [`8f0a396`](https://git.odit.services/lfk/backend/commit/8f0a396dd07937fb7ccfb345d1acbac86eb5d9bb)
- 🧾New changelog file version [CI SKIP] [skip ci] [`f3f5cb4`](https://git.odit.services/lfk/backend/commit/f3f5cb462e4ecf932ad55eb519815222b4e5dd17)
- 🧾New changelog file version [CI SKIP] [skip ci] [`23c732b`](https://git.odit.services/lfk/backend/commit/23c732b6905cc9f6479a53a7744b72d01e345ecb)
- Merge pull request 'Bugfix for @lfk/frontend/#43' (#138) from bugfix/118-encode_jwt_in_mail into dev [`9959172`](https://git.odit.services/lfk/backend/commit/9959172f2ae11cbb7a2b8e97bad432956fc70a80)
- 🧾New changelog file version [CI SKIP] [skip ci] [`a18d4d3`](https://git.odit.services/lfk/backend/commit/a18d4d3cee58f8eb9dc428b051a2394bd3ece5c2)
#### [v0.4.2](https://git.odit.services/lfk/backend/compare/v0.4.1...v0.4.2) #### [v0.4.2](https://git.odit.services/lfk/backend/compare/v0.4.1...v0.4.2)
> 2 February 2021
- Merge pull request 'Alpha Release 0.4.2' (#137) from dev into main [`390b36d`](https://git.odit.services/lfk/backend/commit/390b36dfd46cf8829126581bd62dd3d4ce8558fa) - Merge pull request 'Alpha Release 0.4.2' (#137) from dev into main [`390b36d`](https://git.odit.services/lfk/backend/commit/390b36dfd46cf8829126581bd62dd3d4ce8558fa)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3b718f3`](https://git.odit.services/lfk/backend/commit/3b718f3ce58f12007b6068e5db00a00dbe1c5398) - 🧾New changelog file version [CI SKIP] [skip ci] [`3b718f3`](https://git.odit.services/lfk/backend/commit/3b718f3ce58f12007b6068e5db00a00dbe1c5398)
- 🧾New changelog file version [CI SKIP] [skip ci] [`f7a0ec7`](https://git.odit.services/lfk/backend/commit/f7a0ec7174521b1863a4bc58c7ff2b86cafdee66) - 🧾New changelog file version [CI SKIP] [skip ci] [`f7a0ec7`](https://git.odit.services/lfk/backend/commit/f7a0ec7174521b1863a4bc58c7ff2b86cafdee66)

View File

@@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-backend", "name": "@odit/lfk-backend",
"version": "0.4.2", "version": "0.4.6",
"main": "src/app.ts", "main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend", "repository": "https://git.odit.services/lfk/backend",
"author": { "author": {
@@ -40,7 +40,7 @@
"nodemailer": "^6.4.17", "nodemailer": "^6.4.17",
"pg": "^8.5.1", "pg": "^8.5.1",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"routing-controllers": "^0.9.0-alpha.6", "routing-controllers": "0.9.0-alpha.6",
"routing-controllers-openapi": "^2.2.0", "routing-controllers-openapi": "^2.2.0",
"sqlite3": "5.0.0", "sqlite3": "5.0.0",
"typeorm": "^0.2.30", "typeorm": "^0.2.30",
@@ -104,4 +104,4 @@
"docs/*" "docs/*"
] ]
} }
} }

View File

@@ -11,7 +11,7 @@ export const config = {
postalcode_validation_countrycode: getPostalCodeLocale(), postalcode_validation_countrycode: getPostalCodeLocale(),
version: process.env.VERSION || require('../package.json').version, version: process.env.VERSION || require('../package.json').version,
seedTestData: getDataSeeding(), seedTestData: getDataSeeding(),
app_url: process.env.APP_URL || "http://localhost:4010", app_url: process.env.APP_URL || "http://localhost:8080",
mail_server: process.env.MAIL_SERVER, mail_server: process.env.MAIL_SERVER,
mail_port: Number(process.env.MAIL_PORT) || 25, mail_port: Number(process.env.MAIL_PORT) || 25,
mail_user: process.env.MAIL_USER, mail_user: process.env.MAIL_USER,

View File

@@ -1,110 +1,110 @@
import { Body, CookieParam, JsonController, Param, Post, Req, Res } from 'routing-controllers'; import { Body, CookieParam, JsonController, Param, Post, Req, Res } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError';
import { UserNotFoundError } from '../errors/UserErrors'; import { UserNotFoundError } from '../errors/UserErrors';
import { Mailer } from '../mailer'; import { Mailer } from '../mailer';
import { CreateAuth } from '../models/actions/create/CreateAuth'; import { CreateAuth } from '../models/actions/create/CreateAuth';
import { CreateResetToken } from '../models/actions/create/CreateResetToken'; import { CreateResetToken } from '../models/actions/create/CreateResetToken';
import { HandleLogout } from '../models/actions/HandleLogout'; import { HandleLogout } from '../models/actions/HandleLogout';
import { RefreshAuth } from '../models/actions/RefreshAuth'; import { RefreshAuth } from '../models/actions/RefreshAuth';
import { ResetPassword } from '../models/actions/ResetPassword'; import { ResetPassword } from '../models/actions/ResetPassword';
import { ResponseAuth } from '../models/responses/ResponseAuth'; import { ResponseAuth } from '../models/responses/ResponseAuth';
import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { Logout } from '../models/responses/ResponseLogout'; import { Logout } from '../models/responses/ResponseLogout';
@JsonController('/auth') @JsonController('/auth')
export class AuthController { export class AuthController {
private mailer: Mailer; private mailer: Mailer;
constructor() { constructor() {
this.mailer = new Mailer(); this.mailer = new Mailer();
} }
@Post("/login") @Post("/login")
@ResponseSchema(ResponseAuth) @ResponseSchema(ResponseAuth)
@ResponseSchema(InvalidCredentialsError) @ResponseSchema(InvalidCredentialsError)
@ResponseSchema(UserNotFoundError) @ResponseSchema(UserNotFoundError)
@ResponseSchema(UsernameOrEmailNeededError) @ResponseSchema(UsernameOrEmailNeededError)
@ResponseSchema(PasswordNeededError) @ResponseSchema(PasswordNeededError)
@ResponseSchema(InvalidCredentialsError) @ResponseSchema(InvalidCredentialsError)
@OpenAPI({ description: 'Login with your username/email and password. <br> You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)' }) @OpenAPI({ description: 'Login with your username/email and password. <br> You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)' })
async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) { async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) {
let auth; let auth;
try { try {
auth = await createAuth.toAuth(); auth = await createAuth.toAuth();
response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true });
response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true });
return response.send(auth) return response.send(auth)
} catch (error) { } catch (error) {
throw error; throw error;
} }
} }
@Post("/logout") @Post("/logout")
@ResponseSchema(Logout) @ResponseSchema(Logout)
@ResponseSchema(InvalidCredentialsError) @ResponseSchema(InvalidCredentialsError)
@ResponseSchema(UserNotFoundError) @ResponseSchema(UserNotFoundError)
@ResponseSchema(UsernameOrEmailNeededError) @ResponseSchema(UsernameOrEmailNeededError)
@ResponseSchema(PasswordNeededError) @ResponseSchema(PasswordNeededError)
@ResponseSchema(InvalidCredentialsError) @ResponseSchema(InvalidCredentialsError)
@OpenAPI({ description: 'Logout using your refresh token. <br> This instantly invalidates all your access and refresh tokens.', security: [{ "RefreshTokenCookie": [] }] }) @OpenAPI({ description: 'Logout using your refresh token. <br> This instantly invalidates all your access and refresh tokens.', security: [{ "RefreshTokenCookie": [] }] })
async logout(@Body({ validate: true }) handleLogout: HandleLogout, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any) { async logout(@Body({ validate: true }) handleLogout: HandleLogout, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any) {
if (refresh_token && refresh_token.length != 0 && handleLogout.token == undefined) { if (refresh_token && refresh_token.length != 0 && handleLogout.token == undefined) {
handleLogout.token = refresh_token; handleLogout.token = refresh_token;
} }
let logout; let logout;
try { try {
logout = await handleLogout.logout() logout = await handleLogout.logout()
await response.cookie('lfk_backend__refresh_token', "expired", { expires: new Date(Date.now()), httpOnly: true }); await response.cookie('lfk_backend__refresh_token', "expired", { expires: new Date(Date.now()), httpOnly: true });
response.cookie('lfk_backend__refresh_token_expires_at', "expired", { expires: new Date(Date.now()), httpOnly: true }); response.cookie('lfk_backend__refresh_token_expires_at', "expired", { expires: new Date(Date.now()), httpOnly: true });
} catch (error) { } catch (error) {
throw error; throw error;
} }
return response.send(logout) return response.send(logout)
} }
@Post("/refresh") @Post("/refresh")
@ResponseSchema(ResponseAuth) @ResponseSchema(ResponseAuth)
@ResponseSchema(JwtNotProvidedError) @ResponseSchema(JwtNotProvidedError)
@ResponseSchema(IllegalJWTError) @ResponseSchema(IllegalJWTError)
@ResponseSchema(UserNotFoundError) @ResponseSchema(UserNotFoundError)
@ResponseSchema(RefreshTokenCountInvalidError) @ResponseSchema(RefreshTokenCountInvalidError)
@OpenAPI({ description: 'Refresh your access and refresh tokens using a valid refresh token. <br> You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)', security: [{ "RefreshTokenCookie": [] }] }) @OpenAPI({ description: 'Refresh your access and refresh tokens using a valid refresh token. <br> You will receive: \n * access token (use it as a bearer token) \n * refresh token (will also be sent as a cookie)', security: [{ "RefreshTokenCookie": [] }] })
async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Req() req: any) { async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Req() req: any) {
if (refresh_token && refresh_token.length != 0 && refreshAuth.token == undefined) { if (refresh_token && refresh_token.length != 0 && refreshAuth.token == undefined) {
refreshAuth.token = refresh_token; refreshAuth.token = refresh_token;
} }
let auth; let auth;
try { try {
auth = await refreshAuth.toAuth(); auth = await refreshAuth.toAuth();
response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true });
response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true });
} catch (error) { } catch (error) {
throw error; throw error;
} }
return response.send(auth) return response.send(auth)
} }
@Post("/reset") @Post("/reset")
@ResponseSchema(ResponseEmpty, { statusCode: 200 }) @ResponseSchema(ResponseEmpty, { statusCode: 200 })
@ResponseSchema(UserNotFoundError, { statusCode: 404 }) @ResponseSchema(UserNotFoundError, { statusCode: 404 })
@ResponseSchema(UsernameOrEmailNeededError, { statusCode: 406 }) @ResponseSchema(UsernameOrEmailNeededError, { statusCode: 406 })
@OpenAPI({ description: "Request a password reset token. <br> This will provide you with a reset token that you can use by posting to /api/auth/reset/{token}." }) @OpenAPI({ description: "Request a password reset token. <br> This will provide you with a reset token that you can use by posting to /api/auth/reset/{token}." })
async getResetToken(@Body({ validate: true }) passwordReset: CreateResetToken) { async getResetToken(@Body({ validate: true }) passwordReset: CreateResetToken) {
const reset_token: String = await passwordReset.toResetToken(); const reset_token: string = await passwordReset.toResetToken();
await this.mailer.sendResetMail(passwordReset.email, reset_token); await this.mailer.sendResetMail(passwordReset.email, reset_token);
return new ResponseEmpty(); return new ResponseEmpty();
} }
@Post("/reset/:token") @Post("/reset/:token")
@ResponseSchema(ResponseAuth) @ResponseSchema(ResponseAuth)
@ResponseSchema(UserNotFoundError) @ResponseSchema(UserNotFoundError)
@ResponseSchema(UsernameOrEmailNeededError) @ResponseSchema(UsernameOrEmailNeededError)
@OpenAPI({ description: "Reset a user's utilising a valid password reset token. <br> This will set the user's password to the one you provided in the body. <br> To get a reset token post to /api/auth/reset with your username." }) @OpenAPI({ description: "Reset a user's utilising a valid password reset token. <br> This will set the user's password to the one you provided in the body. <br> To get a reset token post to /api/auth/reset with your username." })
async resetPassword(@Param("token") token: string, @Body({ validate: true }) passwordReset: ResetPassword) { async resetPassword(@Param("token") token: string, @Body({ validate: true }) passwordReset: ResetPassword) {
passwordReset.resetToken = token; passwordReset.resetToken = token;
return await passwordReset.resetPassword(); return await passwordReset.resetPassword();
} }
} }

View File

@@ -32,7 +32,7 @@ export class RunnerController {
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' }) @OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
async getAll() { async getAll() {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>(); let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
const runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'scans.track', 'cards'] }); const runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] });
runners.forEach(runner => { runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner)); responseRunners.push(new ResponseRunner(runner));
}); });
@@ -46,7 +46,7 @@ export class RunnerController {
@OnUndefined(RunnerNotFoundError) @OnUndefined(RunnerNotFoundError)
@OpenAPI({ description: 'Lists all information about the runner whose id got provided.' }) @OpenAPI({ description: 'Lists all information about the runner whose id got provided.' })
async getOne(@Param('id') id: number) { async getOne(@Param('id') id: number) {
let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'scans.track', 'cards'] }) let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] })
if (!runner) { throw new RunnerNotFoundError(); } if (!runner) { throw new RunnerNotFoundError(); }
return new ResponseRunner(runner); return new ResponseRunner(runner);
} }
@@ -91,7 +91,7 @@ export class RunnerController {
} }
runner = await this.runnerRepository.save(runner) runner = await this.runnerRepository.save(runner)
return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'scans.track', 'cards'] })); return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }));
} }
@Put('/:id') @Put('/:id')
@@ -112,7 +112,7 @@ export class RunnerController {
} }
await this.runnerRepository.save(await runner.update(oldRunner)); await this.runnerRepository.save(await runner.update(oldRunner));
return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'scans.track', 'cards'] })); return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }));
} }
@Delete('/:id') @Delete('/:id')
@@ -125,7 +125,7 @@ export class RunnerController {
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let runner = await this.runnerRepository.findOne({ id: id }); let runner = await this.runnerRepository.findOne({ id: id });
if (!runner) { return null; } if (!runner) { return null; }
const responseRunner = await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'scans.track', 'cards'] }); const responseRunner = await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] });
if (!runner) { if (!runner) {
throw new RunnerNotFoundError(); throw new RunnerNotFoundError();

View File

@@ -58,8 +58,8 @@ export class RunnerOrganizationController {
async getRunners(@Param('id') id: number, @QueryParam('onlyDirect') onlyDirect: boolean) { async getRunners(@Param('id') id: number, @QueryParam('onlyDirect') onlyDirect: boolean) {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>(); let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
let runners: Runner[]; let runners: Runner[];
if (!onlyDirect) { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.scans', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.group', 'teams.runners.scans', 'teams.runners.scans.track'] })).allRunners; } if (!onlyDirect) { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.group', 'teams.runners.group.parentGroup', 'teams.runners.scans', 'teams.runners.scans.track'] })).allRunners; }
else { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.scans', 'runners.scans.track'] })).runners; } else { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners; }
runners.forEach(runner => { runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner)); responseRunners.push(new ResponseRunner(runner));
}); });

View File

@@ -12,10 +12,11 @@ import { CreateSelfServiceRunner } from '../models/actions/create/CreateSelfServ
import { Runner } from '../models/entities/Runner'; import { Runner } from '../models/entities/Runner';
import { RunnerGroup } from '../models/entities/RunnerGroup'; import { RunnerGroup } from '../models/entities/RunnerGroup';
import { RunnerOrganization } from '../models/entities/RunnerOrganization'; import { RunnerOrganization } from '../models/entities/RunnerOrganization';
import { ResponseSelfServiceOrganisation } from '../models/responses/ResponseSelfServiceOrganisation';
import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner'; import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner';
@JsonController('/runners') @JsonController()
export class RunnerSelfServiceController { export class RunnerSelfServiceController {
private runnerRepository: Repository<Runner>; private runnerRepository: Repository<Runner>;
private orgRepository: Repository<RunnerOrganization>; private orgRepository: Repository<RunnerOrganization>;
@@ -28,7 +29,7 @@ export class RunnerSelfServiceController {
this.orgRepository = getConnectionManager().get().getRepository(RunnerOrganization); this.orgRepository = getConnectionManager().get().getRepository(RunnerOrganization);
} }
@Get('/me/:jwt') @Get('/runners/me/:jwt')
@ResponseSchema(ResponseSelfServiceRunner) @ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerNotFoundError) @OnUndefined(RunnerNotFoundError)
@@ -37,7 +38,7 @@ export class RunnerSelfServiceController {
return (new ResponseSelfServiceRunner(await this.getRunner(token))); return (new ResponseSelfServiceRunner(await this.getRunner(token)));
} }
@Post('/register') @Post('/runners/register')
@ResponseSchema(ResponseSelfServiceRunner) @ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerEmailNeededError, { statusCode: 406 }) @ResponseSchema(RunnerEmailNeededError, { statusCode: 406 })
@OpenAPI({ description: 'Create a new selfservice runner in the citizen org. <br> This endpoint shoud be used to allow "everyday citizen" to register themselves. <br> You have to provide a mail address, b/c the future we\'ll implement email verification.' }) @OpenAPI({ description: 'Create a new selfservice runner in the citizen org. <br> This endpoint shoud be used to allow "everyday citizen" to register themselves. <br> You have to provide a mail address, b/c the future we\'ll implement email verification.' })
@@ -50,7 +51,7 @@ export class RunnerSelfServiceController {
return response; return response;
} }
@Post('/register/:token') @Post('/runners/register/:token')
@ResponseSchema(ResponseSelfServiceRunner) @ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a new selfservice runner in a provided org. <br> The orgs get provided and authorized via api tokens that can be optained via the /organizations endpoint.' }) @OpenAPI({ description: 'Create a new selfservice runner in a provided org. <br> The orgs get provided and authorized via api tokens that can be optained via the /organizations endpoint.' })
@@ -65,6 +66,17 @@ export class RunnerSelfServiceController {
return response; return response;
} }
@Get('/organizations/selfservice/:token')
@ResponseSchema(ResponseSelfServiceOrganisation, { isArray: false })
@ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Get the basic info and teams for a org.' })
async getSelfserviceOrg(@Param('token') token: string) {
const orgid = (await this.getOrgansisation(token)).id;
const org = await this.orgRepository.findOne({ id: orgid }, { relations: ['teams'] })
return new ResponseSelfServiceOrganisation(<RunnerOrganization>org);
}
/** /**
* Get's a runner by a provided jwt token. * Get's a runner by a provided jwt token.
* @param token The runner jwt provided by the runner to identitfy themselves. * @param token The runner jwt provided by the runner to identitfy themselves.

View File

@@ -55,7 +55,7 @@ export class RunnerTeamController {
@OpenAPI({ description: 'Lists all runners from this team. <br> This includes the runner\'s group and distance ran.' }) @OpenAPI({ description: 'Lists all runners from this team. <br> This includes the runner\'s group and distance ran.' })
async getRunners(@Param('id') id: number) { async getRunners(@Param('id') id: number) {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>(); let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
const runners = (await this.runnerTeamRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.scans', 'runners.scans.track'] })).runners; const runners = (await this.runnerTeamRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners;
runners.forEach(runner => { runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner)); responseRunners.push(new ResponseRunner(runner));
}); });

View File

@@ -1,13 +1,13 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { getConnectionManager, Repository } from 'typeorm';
import { EntityFromBody } from 'typeorm-routing-controllers-extensions';
import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors'; import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors';
import { CreateUserGroup } from '../models/actions/create/CreateUserGroup'; import { CreateUserGroup } from '../models/actions/create/CreateUserGroup';
import { UpdateUserGroup } from '../models/actions/update/UpdateUserGroup'; import { UpdateUserGroup } from '../models/actions/update/UpdateUserGroup';
import { UserGroup } from '../models/entities/UserGroup'; import { UserGroup } from '../models/entities/UserGroup';
import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseUserGroup } from '../models/responses/ResponseUserGroup'; import { ResponseUserGroup } from '../models/responses/ResponseUserGroup';
import { ResponseUserGroupPermissions } from '../models/responses/ResponseUserGroupPermissions';
import { PermissionController } from './PermissionController'; import { PermissionController } from './PermissionController';
@@ -25,20 +25,37 @@ export class UserGroupController {
@Get() @Get()
@Authorized("USERGROUP:GET") @Authorized("USERGROUP:GET")
@ResponseSchema(UserGroup, { isArray: true }) @ResponseSchema(ResponseUserGroup, { isArray: true })
@OpenAPI({ description: 'Lists all groups. <br> The information provided might change while the project continues to evolve.' }) @OpenAPI({ description: 'Lists all groups. <br> The information provided might change while the project continues to evolve.' })
getAll() { async getAll() {
return this.userGroupsRepository.find({ relations: ["permissions"] }); let responseGroups: ResponseUserGroup[] = new Array<ResponseUserGroup>();
const groups = await this.userGroupsRepository.find({ relations: ['permissions'] });
groups.forEach(group => {
responseGroups.push(group.toResponse());
});
return responseGroups;
} }
@Get('/:id') @Get('/:id')
@Authorized("USERGROUP:GET") @Authorized("USERGROUP:GET")
@ResponseSchema(UserGroup) @ResponseSchema(ResponseUserGroup)
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 }) @ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@OnUndefined(UserGroupNotFoundError) @OnUndefined(UserGroupNotFoundError)
@OpenAPI({ description: 'Lists all information about the group whose id got provided. <br> The information provided might change while the project continues to evolve.' }) @OpenAPI({ description: 'Lists all information about the group whose id got provided. <br> The information provided might change while the project continues to evolve.' })
getOne(@Param('id') id: number) { async getOne(@Param('id') id: number) {
return this.userGroupsRepository.findOne({ id: id }, { relations: ["permissions"] }); return await (await (this.userGroupsRepository.findOne({ id: id }, { relations: ["permissions"] }))).toResponse();
}
@Get('/:id/permissions')
@Authorized("USERGROUP:GET")
@ResponseSchema(ResponseUserGroupPermissions)
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@OnUndefined(UserGroupNotFoundError)
@OpenAPI({ description: 'Lists all permissions granted to the group as permission response objects.' })
async getPermissions(@Param('id') id: number) {
let group = await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions', 'permissions.principal'] })
if (!group) { throw new UserGroupNotFoundError(); }
return new ResponseUserGroupPermissions(group);
} }
@Post() @Post()
@@ -54,7 +71,8 @@ export class UserGroupController {
throw error; throw error;
} }
return this.userGroupsRepository.save(userGroup); userGroup = await this.userGroupsRepository.save(userGroup);
return (await (this.userGroupsRepository.findOne({ id: userGroup.id }, { relations: ["permissions"] }))).toResponse();
} }
@Put('/:id') @Put('/:id')
@@ -63,7 +81,7 @@ export class UserGroupController {
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 }) @ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(UserGroupIdsNotMatchingError, { statusCode: 406 }) @ResponseSchema(UserGroupIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the group whose id you provided. <br> To change the permissions granted to the group please use /api/permissions instead. <br> Please remember that ids can't be changed." }) @OpenAPI({ description: "Update the group whose id you provided. <br> To change the permissions granted to the group please use /api/permissions instead. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @EntityFromBody() updateGroup: UpdateUserGroup) { async put(@Param('id') id: number, @Body({ validate: true }) updateGroup: UpdateUserGroup) {
let oldGroup = await this.userGroupsRepository.findOne({ id: id }); let oldGroup = await this.userGroupsRepository.findOne({ id: id });
if (!oldGroup) { if (!oldGroup) {
@@ -75,7 +93,7 @@ export class UserGroupController {
} }
await this.userGroupsRepository.save(await updateGroup.update(oldGroup)); await this.userGroupsRepository.save(await updateGroup.update(oldGroup));
return (await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions', 'groups'] })).toResponse(); return (await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions'] })).toResponse();
} }
@Delete('/:id') @Delete('/:id')
@@ -85,7 +103,7 @@ export class UserGroupController {
@OnUndefined(204) @OnUndefined(204)
@OpenAPI({ description: 'Delete the group whose id you provided. <br> If there are any permissions directly granted to the group they will get deleted as well. <br> Users associated with this group won\'t get deleted - just deassociated. <br> If no group with this id exists it will just return 204(no content).' }) @OpenAPI({ description: 'Delete the group whose id you provided. <br> If there are any permissions directly granted to the group they will get deleted as well. <br> Users associated with this group won\'t get deleted - just deassociated. <br> If no group with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let group = await this.userGroupsRepository.findOne({ id: id }, { relations: ["permissions"] }); let group = await this.userGroupsRepository.findOne({ id: id });
if (!group) { return null; } if (!group) { return null; }
const responseGroup = await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions'] }); const responseGroup = await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions'] });

View File

@@ -38,8 +38,8 @@ export class Mailer {
* @param to_address The address the mail will be sent to. Should always get pulled from a user object. * @param to_address The address the mail will be sent to. Should always get pulled from a user object.
* @param token The requested password reset token - will be combined with the app_url to generate a password reset link. * @param token The requested password reset token - will be combined with the app_url to generate a password reset link.
*/ */
public async sendResetMail(to_address: string, token: String) { public async sendResetMail(to_address: string, token: string) {
const reset_link = `${config.app_url}/reset/${token}` const reset_link = `${config.app_url}/reset/${(Buffer.from(token)).toString("base64")}`
const body_html = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }).replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`); const body_html = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }).replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`);
const body_txt = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }).replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`); const body_txt = fs.readFileSync(__dirname + '/static/mail_templates/pw-reset.html', { encoding: 'utf8' }).replace("{{reset_link}}", reset_link).replace("{{recipient_mail}}", to_address).replace("{{copyright_owner}}", "LfK!").replace("{{link_imprint}}", `${config.app_url}/imprint`).replace("{{link_privacy}}", `${config.app_url}/privacy`);

View File

@@ -23,7 +23,7 @@ export class CreateResetToken {
/** /**
* Create a password reset token based on this. * Create a password reset token based on this.
*/ */
public async toResetToken(): Promise<any> { public async toResetToken(): Promise<string> {
if (!this.email) { if (!this.email) {
throw new UserEmailNeededError(); throw new UserEmailNeededError();
} }
@@ -37,7 +37,7 @@ export class CreateResetToken {
await getConnectionManager().get().getRepository(User).save(found_user); await getConnectionManager().get().getRepository(User).save(found_user);
//Create the reset token //Create the reset token
let reset_token = JwtCreator.createReset(found_user); let reset_token: string = JwtCreator.createReset(found_user);
return reset_token; return reset_token;
} }

View File

@@ -21,6 +21,8 @@ export enum ResponseObjectType {
SCANSTATION = 'SCANSTATION', SCANSTATION = 'SCANSTATION',
SELFSERVICEDONATION = 'SELFSERVICEDONATION', SELFSERVICEDONATION = 'SELFSERVICEDONATION',
SELFSERVICERUNNER = 'SELFSERVICRUNNER', SELFSERVICERUNNER = 'SELFSERVICRUNNER',
SELFSERVICETEAM = 'SELFSERVICETEAM',
SELFSERVICEORGANIZATION = 'SELFSERVICEORGANIZATION',
STATS = 'STATS', STATS = 'STATS',
STATSCLIENT = 'STATSCLIENT', STATSCLIENT = 'STATSCLIENT',
STATSORGANIZATION = 'STATSORGANIZATION', STATSORGANIZATION = 'STATSORGANIZATION',

View File

@@ -0,0 +1,38 @@
import { IsArray, IsNotEmpty, IsString } from 'class-validator';
import { RunnerOrganization } from '../entities/RunnerOrganization';
import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse';
import { ResponseSelfServiceTeam } from './ResponseSelfServiceTeam';
/**
* Defines the runner selfservice organization response.
* Why? B/C runner's are not allowed to view all information available to admin users.
*/
export class ResponseSelfServiceOrganisation implements IResponse {
/**
* The responseType.
* This contains the type of class/entity this response contains.
*/
responseType: ResponseObjectType = ResponseObjectType.SELFSERVICEORGANIZATION;
/**
* The org's name.
*/
@IsNotEmpty()
@IsString()
name: string;
/**
* The org's teams (just containing name and id).
*/
@IsArray()
teams: ResponseSelfServiceTeam[];
public constructor(org: RunnerOrganization) {
this.name = org.name;
this.teams = new Array<ResponseSelfServiceTeam>();
for (let team of org.teams) {
this.teams.push(new ResponseSelfServiceTeam(team));
}
}
}

View File

@@ -0,0 +1,36 @@
import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator';
import { RunnerTeam } from '../entities/RunnerTeam';
import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse';
/**
* Defines the runner selfservice team response.
* Why? B/C runner's are not allowed to view all information available to admin users.
*/
export class ResponseSelfServiceTeam implements IResponse {
/**
* The responseType.
* This contains the type of class/entity this response contains.
*/
responseType: ResponseObjectType = ResponseObjectType.SELFSERVICETEAM;
/**
* The team's name.
*/
@IsNotEmpty()
@IsString()
name: string;
/**
* The team's id.
* Will be used to insert runners it into that team.
*/
@IsInt()
@IsPositive()
id: number;
public constructor(team: RunnerTeam) {
this.name = team.name;
this.id = team.id;
}
}

View File

@@ -2,7 +2,6 @@ import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator";
import { UserGroup } from '../entities/UserGroup'; import { UserGroup } from '../entities/UserGroup';
import { ResponseObjectType } from '../enums/ResponseObjectType'; import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse'; import { IResponse } from './IResponse';
import { ResponsePermission } from './ResponsePermission';
import { ResponsePrincipal } from './ResponsePrincipal'; import { ResponsePrincipal } from './ResponsePrincipal';
/** /**
@@ -34,7 +33,7 @@ export class ResponseUserGroup extends ResponsePrincipal implements IResponse {
*/ */
@IsArray() @IsArray()
@IsOptional() @IsOptional()
permissions: ResponsePermission[]; permissions: string[] = new Array<string>();
/** /**
* Creates a ResponseUserGroup object from a userGroup. * Creates a ResponseUserGroup object from a userGroup.
@@ -46,7 +45,7 @@ export class ResponseUserGroup extends ResponsePrincipal implements IResponse {
this.description = group.description; this.description = group.description;
if (group.permissions) { if (group.permissions) {
for (let permission of group.permissions) { for (let permission of group.permissions) {
this.permissions.push(permission.toResponse()); this.permissions.push(permission.toString());
} }
} }
} }

View File

@@ -0,0 +1,43 @@
import {
IsArray,
IsOptional
} from "class-validator";
import { UserGroup } from '../entities/UserGroup';
import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse';
import { ResponsePermission } from './ResponsePermission';
/**
* Defines the group permission response (get /api/groups/:id/permissions).
*/
export class ResponseUserGroupPermissions implements IResponse {
/**
* The responseType.
* This contains the type of class/entity this response contains.
*/
responseType: ResponseObjectType = ResponseObjectType.USERPERMISSIONS;
/**
* The permissions directly granted to the group.
*/
@IsArray()
@IsOptional()
directlyGranted: ResponsePermission[] = new Array<ResponsePermission>();
/**
* Is just here for compatability.
*/
@IsArray()
@IsOptional()
inherited: ResponsePermission[] = new Array<ResponsePermission>();
/**
* Creates a ResponseUserPermissions object from a group.
* @param group The group the response shall be build for.
*/
public constructor(group: UserGroup) {
for (let permission of group.permissions) {
this.directlyGranted.push(permission.toResponse());
}
}
}

View File

@@ -0,0 +1,54 @@
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 invalid org', () => {
it('getting random org via selfservice should return 4040', async () => {
const res = await axios.get(base + '/api/organizations/selfservice/asfdasfasdfsdafsadfsadfasdfasdfsdf', axios_config);
expect(res.status).toEqual(404);
});
});
// ---------------
describe('get valid org w/teams', () => {
let added_org;
let added_team;
it('creating a new org with just a name and registration enabled should return 200', async () => {
const res = await axios.post(base + '/api/organizations', {
"name": "test123",
"registrationEnabled": true
}, axios_config);
added_org = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('creating a new team with a parent org should return 200', async () => {
const res = await axios.post(base + '/api/teams', {
"name": "test_team",
"parentGroup": added_org.id
}, axios_config);
added_team = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('getting org via selfservice should return 200', async () => {
const res = await axios.get(base + '/api/organizations/selfservice/' + added_org.registrationKey, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
expect(res.data.name).toEqual(added_org.name);
expect(res.data.teams[0]).toEqual({ name: added_team.name, id: added_team.id });
});
});