Compare commits

..

884 Commits

Author SHA1 Message Date
881eedbf3a Merge pull request 'Alpha Release 0.0.12' (#98) from dev into main
Some checks failed
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is failing
Reviewed-on: #98
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-13 19:33:07 +00:00
09cb6f7b2b 🧾New changelog file version [CI SKIP] [skip ci]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-13 18:25:55 +00:00
bd091d5cb9 🚀Bumped version to v0.0.12
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-13 19:25:28 +01:00
8cb67a8d20 🧾New changelog file version [CI SKIP] [skip ci] 2021-01-13 18:22:48 +00:00
290bb29e64 Disabled auto clone
All checks were successful
continuous-integration/drone/push Build is passing
ref #63
2021-01-13 19:22:19 +01:00
d0769a5e37 Added secondary full clone for tags
Some checks failed
continuous-integration/drone/push Build is failing
ref #63
2021-01-13 19:20:42 +01:00
c5b28df2ae Merge branch 'dev' of git.odit.services:lfk/backend into dev
All checks were successful
continuous-integration/drone/push Build is passing
# Conflicts:
#	.drone.yml
2021-01-13 19:18:39 +01:00
c108fa509f Updated step order
ref #63
2021-01-13 19:18:31 +01:00
1e5e9801be Updated step order
ref #63
2021-01-13 19:18:08 +01:00
09b16c980b 📖New license file version [CI SKIP] [skip ci] 2021-01-13 18:15:22 +00:00
4c26fc808e Fixed spellings
All checks were successful
continuous-integration/drone/push Build is passing
ref #63
2021-01-13 19:14:16 +01:00
525b11b346 Revert "🚀Bumped version to v0.0.12."
Some checks failed
continuous-integration/drone/push Build encountered an error
This reverts commit 86679b498b.
2021-01-13 19:13:04 +01:00
86679b498b 🚀Bumped version to v0.0.12. 2021-01-13 19:12:50 +01:00
46df8b0528 Updated the release machanics
ref #63
2021-01-13 19:12:43 +01:00
1a4f896a8a Merge branch 'dev' of git.odit.services:lfk/backend into dev 2021-01-13 19:07:57 +01:00
aaaa15a0ef Moved changelog generation to dev build for now
ref #63
2021-01-13 19:07:50 +01:00
de65b1c699 🧾New changelog file version [CI SKIP] [skip ci]
Some checks failed
continuous-integration/drone/pr Build was killed
2021-01-13 17:58:33 +00:00
f9437065ee 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-01-13 18:57:17 +01:00
b495cadae9 Added new ci skipping flags
ref #63
2021-01-13 18:57:11 +01:00
47995b77f7 🧾New changelog file version [CI SKIP]
Some checks failed
continuous-integration/drone/pr Build was killed
2021-01-13 17:55:17 +00:00
bc24ec5272 🧾New changelog file version [CI SKIP]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-13 17:54:26 +00:00
2947c41a72 🧾New changelog file version [CI SKIP]
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-13 17:54:00 +00:00
ef53035f70 Reenabled dev build
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
ref #63
2021-01-13 18:53:38 +01:00
290afc3f8f Disabled verification skip
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
ref #63
2021-01-13 18:50:50 +01:00
d6e89b0880 Merge branch 'dev' of git.odit.services:lfk/backend into dev
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2021-01-13 18:47:03 +01:00
2b72552b1f tmp: skip verification 2021-01-13 18:47:00 +01:00
df69418855 tmp: skip verification
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2021-01-13 18:45:04 +01:00
472e402521 disabled dev build temporary
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
ref #63
2021-01-13 18:42:33 +01:00
a3f282667c Merge branch 'dev' of git.odit.services:lfk/backend into dev
# Conflicts:
#	.drone.yml
2021-01-13 18:42:01 +01:00
b86263d972 Disabled custom clone
ref #63
2021-01-13 18:41:02 +01:00
f278320b93 Disabled custom clone
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
ref #63
2021-01-13 18:38:05 +01:00
6345666ae6 Added new pipeline to automagicly generate changelogs on pr to main
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
ref #63
2021-01-13 18:35:12 +01:00
7b5ebab453 Merge pull request 'New user features feature/93-user_endpoints' (#95) from feature/93-user_endpoints into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #95
2021-01-13 17:30:25 +00:00
d4d713b12d Merge branch 'dev' into feature/93-user_endpoints
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-13 17:21:22 +00:00
ab3af54e15 Merge pull request 'Donation API Endpoint feature/66-donation_api' (#94) from feature/66-donation_api into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #94
2021-01-13 17:20:08 +00:00
b01e1eb8a1 Added a new endpoint that returns a users permissions as objects sorted into two arrays
All checks were successful
continuous-integration/drone/pr Build is passing
ref #93
2021-01-13 18:19:59 +01:00
0724932152 Updated some openapi descriptions
All checks were successful
continuous-integration/drone/pr Build is passing
ref #94
2021-01-13 18:01:53 +01:00
cd7b15aadf First part of resolving user inherited permissions
ref #93
2021-01-13 17:57:42 +01:00
37fc167002 Added '@' as a illegal character for usernames
ref #93
2021-01-13 17:51:42 +01:00
9feeb302e8 Switched emails to being mandetory for users
ref #93
2021-01-13 17:44:22 +01:00
bba35d189e Added donor donation amount to the donor response
Some checks failed
continuous-integration/drone/pr Build is failing
ref #66
2021-01-13 17:32:10 +01:00
cd5e4bbd60 Added donation update validtests
ref #66
2021-01-13 17:19:57 +01:00
a513bf13ca Added donation update invalid tests
ref #66
2021-01-12 20:43:07 +01:00
e3e570e664 Added donation add validtests
ref #66
2021-01-12 20:15:51 +01:00
badff85e28 Fixed typos
ref #66
2021-01-12 20:14:23 +01:00
4a0f75044f Added donation add invalid tests
ref #66
2021-01-12 20:09:00 +01:00
b729a7cead Added cascading runner deletion tests
ref #66
2021-01-12 20:01:56 +01:00
4375ca92d3 Added cascading donor deletion tests
ref #66
2021-01-12 20:00:02 +01:00
71537b283f Added donation delete tests
ref #66
2021-01-12 19:53:03 +01:00
63506dac1c Added donation get tests
ref #66
2021-01-12 19:44:15 +01:00
e716fae1c5 Implmented cascading donation deletion for runners and donors
ref #66
2021-01-12 19:33:54 +01:00
f7370bc802 Implemented distance donation updateing
ref #66
2021-01-12 19:06:26 +01:00
72c3fc78b3 Added the basics for distance donation updateing
ref #66
2021-01-12 19:03:33 +01:00
110387dbd3 Merge branch 'feature/66-donation_api' of git.odit.services:lfk/backend into feature/66-donation_api
# Conflicts:
#	src/controllers/DonationController.ts
2021-01-12 19:01:14 +01:00
2820f151e8 Implemented fixed donation updateing
ref #66
2021-01-12 19:01:03 +01:00
9517df5082 Implemented fixed donation updateing
ref #66
2021-01-12 19:00:35 +01:00
56cedf0144 Fixed typo
ref #66
2021-01-12 18:55:20 +01:00
bbaee7cd4d Added the basics for fixed donation updateing
ref #66
2021-01-12 18:53:59 +01:00
8ee2bdf488 Implemented distance donation creation
ref #66
2021-01-12 18:50:55 +01:00
97ecc83fe4 Implemented fixed donation creation
ref #66
2021-01-12 18:50:47 +01:00
57f62a6087 Implemented donation deletion
ref #66
2021-01-12 18:46:02 +01:00
2e760ff461 Implemented the donation creation action models
ref #66
2021-01-12 18:39:14 +01:00
0df26cbd54 Implemented donation getting
ref #66
2021-01-12 18:29:55 +01:00
5f1ab4a2f3 Added donation errors
ref #66
2021-01-12 18:26:55 +01:00
e1ff8c03e1 Added donation permission target
ref #66
2021-01-12 18:21:52 +01:00
55f72c35a6 Implemented the distance donation response
ref #66
2021-01-12 18:20:36 +01:00
6c53701a59 Implemented the donation response
ref #66
2021-01-12 18:16:09 +01:00
02bb634257 Implemented a response donation interface
ref #66
2021-01-12 18:07:41 +01:00
5581c03f77 Added barebones donation controller
ref #66
2021-01-12 18:01:03 +01:00
cf788fe07b Merge pull request 'Fixed backend version related bugs' (#92) from bugfix/91-backend_version into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #92
closes #91
2021-01-12 16:46:37 +00:00
4bf425e1ca Merge branch 'dev' into bugfix/91-backend_version
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-12 16:46:08 +00:00
a2f4fd5d9b Introduces a very basic version getting endpoint
All checks were successful
continuous-integration/drone/pr Build is passing
ref #91
2021-01-12 17:41:42 +01:00
295a1524d8 Fixed the version getting process
ref #91
2021-01-12 17:39:40 +01:00
234154255c Merge pull request 'Bugfix: resolved missing relation' (#89) from bugfix/88-user_update into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #89
closes #88
2021-01-12 16:34:36 +00:00
7b087840ec Bugfix: resolved missing relation
All checks were successful
continuous-integration/drone/pr Build is passing
ref #88
2021-01-12 16:53:39 +01:00
16b594ebdd Merge branch 'main' into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-10 18:28:09 +01:00
67b3101fd1 Updated some trone pipeline names and messages
Some checks failed
continuous-integration/drone/push Build is failing
2021-01-10 18:26:11 +01:00
b3ce56c605 Merge pull request 'Alpha Release 0.0.11' (#87) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #87
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-10 17:16:09 +00:00
28cefa792c Version bump
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-01-10 18:13:08 +01:00
0803abc168 Merge pull request 'General cleanup and optimisation feature/76-cleanup' (#86) from feature/76-cleanup into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #86
2021-01-10 17:11:31 +00:00
02ae883fa4 Removed everything comit related from the release-it config
All checks were successful
continuous-integration/drone/pr Build is passing
ref #76
2021-01-10 18:09:57 +01:00
be4050768e Moded group updateing to a updateusergroup action model
All checks were successful
continuous-integration/drone/pr Build is passing
ref #76
2021-01-10 18:01:22 +01:00
dc6ec23cb9 Implmented basic release mgnt
ref #76
2021-01-10 17:47:31 +01:00
1bb98c13d1 Dependency bump
ref #76
2021-01-10 17:29:30 +01:00
bca979bab5 Unified remove parameters
ref #76
2021-01-10 17:16:42 +01:00
e4fafd764c Cleaner implementation of the api version getter
ref #76
2021-01-10 17:14:42 +01:00
172159414b Unified the openapi generation
ref #76
2021-01-10 17:10:25 +01:00
9355138a8c App now automagicly displays the current package version as the openapi version
ref #76
2021-01-10 16:59:39 +01:00
343cd8b772 Merge branch 'feature/76-cleanup' of git.odit.services:lfk/backend into feature/76-cleanup 2021-01-10 16:57:43 +01:00
01e0d5b94d Renamed the auth response call to ResponseAuth
ref #76
2021-01-10 16:57:40 +01:00
ac00667465 Renamed the auth response call to ResponseAuth
ref #76
2021-01-10 16:54:19 +01:00
3deae2bfeb Moved all update() and toEntity action model functions to async
ref #76
2021-01-10 16:53:59 +01:00
3f7b0f6563 Renamed the update>Entity Name>() functiuons to update()
ref #76
2021-01-10 16:35:52 +01:00
e6b9d4f273 Renamed the to>Entity Name>() functiuons to toEntity()
ref #76
2021-01-10 16:31:55 +01:00
a00231dd3c Updated imports
ref #76
2021-01-10 16:23:09 +01:00
3bc172e7e0 Intruduced a new folder structure for action models
ref #76
2021-01-10 16:10:02 +01:00
ee9df21ae5 Fixed some typos in errors
ref #76
2021-01-10 16:07:37 +01:00
f96b256ad3 Fixed some typos and extended comments for the middlewares
ref #76
2021-01-10 16:03:56 +01:00
f2c50e929e Merge branch 'dev' of git.odit.services:lfk/backend into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-09 19:05:00 +01:00
02e3239848 Reverted temporary logging 2021-01-09 19:04:07 +01:00
8a54b027d0 Reverted temporary logging
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-09 18:55:16 +01:00
3b11e896d4 Merge branch 'dev' of git.odit.services:lfk/backend into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-09 18:50:50 +01:00
89926b2c31 Temporary: extended live logging 2021-01-09 18:50:48 +01:00
7b4e89555e Temporary: extended live logging
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-09 18:47:11 +01:00
1e37186247 Revert "Temporary: extended live logging"
This reverts commit 154c763719.
2021-01-09 18:45:44 +01:00
154c763719 Temporary: extended live logging
All checks were successful
continuous-integration/drone/push Build is passing
ref lfk/frontend#28
2021-01-09 18:08:36 +01:00
80197d5834 Merge pull request 'feature/78-trackscan' (#85) from feature/78-trackscan into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #85
2021-01-09 16:33:09 +00:00
7e95103a2d added trackscan update tests
All checks were successful
continuous-integration/drone/pr Build is passing
ref #78
2021-01-09 17:18:33 +01:00
efe1a1f543 added trackscan delete tests
ref #78
2021-01-09 16:56:57 +01:00
4fea690670 Added missing parameter fro negative-test
ref #78
2021-01-09 16:54:19 +01:00
f1dee1061d added trackscan get tests
ref #78
2021-01-09 16:49:17 +01:00
61cf0fc08d Implemented proper scan invalidation
ref #78
2021-01-09 16:47:54 +01:00
0c86e5dae1 added trackscan add tests
ref #78
2021-01-09 16:44:52 +01:00
638898fa28 Implemented trackscan updateing
ref #78
2021-01-09 16:17:50 +01:00
e7cd68e1c8 removed distance checks from tests
ref #78
2021-01-09 15:59:36 +01:00
e40e6faebd Merge branch 'feature/78-trackscan' of git.odit.services:lfk/backend into feature/78-trackscan
# Conflicts:
#	src/controllers/RunnerController.ts
2021-01-09 15:45:35 +01:00
3d07aac944 Implemented cascading scan, track and card deletion
ref #78
2021-01-09 15:45:17 +01:00
1a5493facf Implemented cascading scan, track and card deletion
ref #78
2021-01-09 15:43:52 +01:00
9013b9492c Fixed runner distance resolution
ref #78
2021-01-09 15:25:11 +01:00
188f26ad65 Fixed manual trackscan creation
ref #78
2021-01-09 14:52:08 +01:00
3ceb5a0c0f Removed total distance from tests
ref #78
2021-01-09 14:24:16 +01:00
e1ce052d3c Fixed runner total distance not getting resolved
ref #78
2021-01-09 14:23:47 +01:00
70a379edef Merge pull request 'New feature: runner cards (feature/77-runner_cards)' (#84) from feature/77-runner_cards into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #84
2021-01-09 13:01:50 +00:00
35ea3154d1 Added card update tests
All checks were successful
continuous-integration/drone/pr Build is passing
ref #77
2021-01-09 12:42:41 +01:00
ebf66821a2 Added card delete tests
ref #77
2021-01-09 12:41:59 +01:00
8463bee253 added card add tests
ref #77
2021-01-09 12:32:47 +01:00
860680d001 Implmented the EAN generation
ref #77
2021-01-09 12:24:05 +01:00
df39166279 Added card get tests
ref #77
2021-01-09 11:59:20 +01:00
32fda46f0a Implemented runner updateing
ref #77
2021-01-09 11:55:32 +01:00
36ecae7e6e Added card creation
#17
2021-01-09 11:48:13 +01:00
a5bfe4e3d5 Added card deletion + errors
ref #77
2021-01-09 11:28:59 +01:00
4faeddc3f3 Added runner card get endpoints
ref #77
2021-01-09 11:23:12 +01:00
98f7bf366f Added card permission target
ref #77
2021-01-09 11:21:52 +01:00
af3a9e5ce2 Added basic response calss for runner cards
ref #77
2021-01-09 11:15:29 +01:00
52eb7b1afe Added a barebones runnercard controller
ref #77
2021-01-09 11:10:05 +01:00
490fbd241d Merge pull request 'Alpha Release 0.0.10' (#83) from dev into main
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #83
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-08 20:15:27 +00:00
f132131156 Version bump
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-01-08 21:14:20 +01:00
c1e680a063 Fixed responsescheme for the user controller
Some checks failed
continuous-integration/drone/push Build is failing
2021-01-08 21:13:41 +01:00
c66b06c2c9 Merge pull request 'Alpha Release 0.0.9' (#82) from dev into main
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #82
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-08 19:52:55 +00:00
65e605cdc4 Version bump
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-01-08 20:49:19 +01:00
d2fdb4efd9 Merge pull request 'All users get profile pics feature/79-profile_pics' (#81) from feature/79-profile_pics into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #81
closes #79
2021-01-08 19:48:22 +00:00
d0deb9d647 Fixed wrong relation getting resolved
All checks were successful
continuous-integration/drone/pr Build is passing
ref #79
2021-01-08 20:40:15 +01:00
5495c90eaf Merge branch 'dev' into feature/79-profile_pics
Some checks failed
continuous-integration/drone/pr Build is failing
2021-01-08 20:19:08 +01:00
bf3ffae67c Merge pull request 'Added scan (station) apis feature/67-scan_apis' (#80) from feature/67-scan_apis into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #80
closes #67
2021-01-08 19:18:39 +00:00
aa0337ea33 Fixed getting all permissions for users
ref #79
2021-01-08 20:17:05 +01:00
4991d735bf Pinned sqlite3 to 5.0.0 as a temporary bugfix
All checks were successful
continuous-integration/drone/pr Build is passing
ref #67
2021-01-08 20:04:04 +01:00
398e61bddb Merge branch 'feature/67-scan_apis' of git.odit.services:lfk/backend into feature/67-scan_apis
Some checks failed
continuous-integration/drone/pr Build is failing
# Conflicts:
#	.drone.yml
2021-01-08 19:37:25 +01:00
e6576f4a54 Finned node version for ci
ref #67
2021-01-08 19:37:13 +01:00
c3b9e135b0 Finned node version for ci
Some checks failed
continuous-integration/drone/pr Build is failing
ref #67
2021-01-08 19:34:39 +01:00
3bd4948c43 Merge branch 'feature/79-profile_pics' of git.odit.services:lfk/backend into feature/79-profile_pics 2021-01-08 19:32:13 +01:00
f3cd1380be First part of the permission return (buggy!)
ref #79
2021-01-08 19:32:11 +01:00
a2c3dfbf85 First part of the permission return (buggy!)
ref #71
2021-01-08 19:32:04 +01:00
3c37aafe1f Added profile pics to all user related models
ref #79
2021-01-08 19:11:50 +01:00
c591c182b3 Updated comments
Some checks failed
continuous-integration/drone/pr Build is failing
ref #67
2021-01-08 18:37:33 +01:00
9cc50078d1 Merge branch 'dev' into feature/67-scan_apis 2021-01-08 18:29:33 +01:00
7728759bcd Added openapi sec scheme for the scan station auth
ref #67
2021-01-08 18:28:35 +01:00
ce8fed350e Updated OPENAPI Descriptions for the new controllers
ref #67
2021-01-08 18:25:29 +01:00
a005945e9e Added scan add tests with the station based auth
ref #67
2021-01-08 18:09:47 +01:00
cf86520fae Fixed wrong auth type being used
ref #67
2021-01-08 18:08:13 +01:00
db6fdf6baf Implemented scan auth middleware
ref #67
2021-01-08 17:50:29 +01:00
975ad50afc Added scan update tests
ref #67
2021-01-08 17:42:05 +01:00
0c27df7754 Added scan add tests
ref #67
2021-01-08 17:27:56 +01:00
102a860ba3 Added scan delete tests
ref #67
2021-01-08 16:47:52 +01:00
3a886714a0 Merge branch 'feature/67-scan_apis' of git.odit.services:lfk/backend into feature/67-scan_apis
# Conflicts:
#	src/tests/scanstations/scanstations_delete.spec.ts
2021-01-07 20:35:05 +01:00
09ab638239 Added scan station delete tests
ref #67
2021-01-07 20:34:48 +01:00
a4f88c78f4 Added scan station delete tests
ref #67
2021-01-07 20:34:36 +01:00
ccf2a3b617 Added scan station update tests
ref #67
2021-01-07 20:31:29 +01:00
c8f941a779 Fixed wrong error getting thrown
ref #67
2021-01-07 20:22:58 +01:00
5510cbb8e9 Added scan station add tests
ref #67
2021-01-07 20:16:14 +01:00
a434173b54 Added scan station get tests
ref #67
2021-01-07 20:04:15 +01:00
7387f700fb Added alias for posting track scans
ref #67
2021-01-07 19:46:20 +01:00
4f01baaa23 Added the enabled flag for scanstations
ref #67
2021-01-07 19:37:15 +01:00
09b37f0ff2 Fixed typo
ref #67
2021-01-07 19:36:57 +01:00
324d5709e3 Added tmp files to gitignore
ref #67
2021-01-07 19:19:21 +01:00
3f23e4f1f1 Added scan get tests
ref #67
2021-01-07 19:18:26 +01:00
9776a35f9f Track deletion now recognizes associated stations
ref #67
2021-01-07 18:53:09 +01:00
9b9ee70288 Implemented cascading station deletion
ref #67
2021-01-07 18:48:58 +01:00
2628f69651 Implemented scan station creation
ref #67
2021-01-07 18:39:38 +01:00
b9c0a32862 Implemented single scan station get +e errors
ref #67
2021-01-07 18:35:19 +01:00
82644a2ff4 Implmented getting all scan stations
ref #67
2021-01-07 18:05:54 +01:00
3d2c93b5ac Added (scan) stations as a new permission target
ref #67
2021-01-07 17:35:36 +01:00
c447114297 Added a ScanStation response class
ref #67
2021-01-07 17:31:44 +01:00
857de9ffcc Added Creation class for ScanSatations
ref #67
2021-01-07 17:29:22 +01:00
eea656bd7b Added a barebones scanstation controller
ref #67
2021-01-07 17:16:36 +01:00
eec5284306 Implemented "normal" scan updateing
ref #67
2021-01-07 17:12:12 +01:00
88a6a768c4 Implemented scan deletion
ref #67
2021-01-07 17:03:40 +01:00
edac1a224c Fixed runner scan validation bug
ref #67
2021-01-07 16:59:57 +01:00
e67d1c5697 Fixed scan runner in response
ref #67
2021-01-07 16:38:41 +01:00
30502ec949 Fixed Creation of normal scans
ref #67
2021-01-07 16:32:16 +01:00
a2c3913601 Merge branch 'feature/67-scan_apis' of git.odit.services:lfk/backend into feature/67-scan_apis 2021-01-07 16:13:44 +01:00
f1c7713da2 Adusted the way scan distances are implemented
ref #67
2021-01-07 16:13:41 +01:00
d6a41d5a82 Ajusted the way scan distances are implemented 2021-01-07 16:13:31 +01:00
72b5ca4153 Added basics for scan creation (to be tested after scanstations got added)
ref #67
2021-01-06 19:44:20 +01:00
aeec2e1c32 Added single scan get w/ errors
ref #67
2021-01-03 19:36:38 +01:00
f9889bea3d Implemented scans get including the response classes
ref #67
2021-01-03 19:26:06 +01:00
2cad2ac2e9 Implemented the second round of the toResponse normalisationf for all classes
ref #67
2021-01-03 19:18:31 +01:00
d948fe2631 Merge pull request 'Fixed relative paths not being updated + version bump for bugfix release' (#75) from dev into main
Some checks failed
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is failing
Reviewed-on: #75
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-03 18:13:10 +00:00
2b5525323b Fixed relative paths not being updated + version bump for bugfix release
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-01-03 19:10:46 +01:00
58156e0d61 Implemented the first route of the toResponse normalisationf for all classes
ref #67
2021-01-03 19:09:06 +01:00
a4b0dfe43e Defined responses for scans and trackscans
ref #67
2021-01-03 19:02:06 +01:00
ee2433a5ae Added barebones scans controller
ref #67
2021-01-03 18:49:33 +01:00
2151b8502d Added Scan permission target
ref #67
2021-01-03 18:48:05 +01:00
b57fde9b0a Merge pull request 'Bugfix for the openapi exporter' (#74) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #74
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-03 17:29:35 +00:00
86706f9422 Merge branch 'main' into dev
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-01-03 17:29:24 +00:00
0687f268fc Fixed switch up between node/js and ts-node/ts
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-01-03 18:27:58 +01:00
bc426831db Merge pull request 'Alpha Release 0.0.7' (#73) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #73
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2021-01-03 17:22:25 +00:00
276e553e13 Version bump
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
ref #73
2021-01-03 18:18:51 +01:00
e7ab302c61 Merge pull request 'Minimum lap times for tracks feature/71-track_times' (#72) from feature/71-track_times into dev
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
Reviewed-on: #72
closes #71
2021-01-03 17:17:59 +00:00
a5d70ce4b5 Removed useless console.log
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-03 18:13:53 +01:00
d67be313e6 Added track update tests
All checks were successful
continuous-integration/drone/pr Build is passing
ref #71
2021-01-03 18:08:04 +01:00
15d2d029dc Added track delete tests
ref #71
2021-01-03 18:07:33 +01:00
b6ea5e6549 Fixed copy-paste mistake
ref #71
2021-01-03 18:01:21 +01:00
f378b0651a Added helpful comment about the tracktime's unit
ref #71
2021-01-03 17:52:36 +01:00
1a0573e0d0 Added track add tests
ref #71
2021-01-03 17:52:16 +01:00
9f103d8df1 Added track get tests
ref #71
2021-01-03 17:49:55 +01:00
daa899a1ef Removed the old basic test class
ref #71
2021-01-03 17:49:44 +01:00
59cb72a11d Implemented track upodates using the "new" method
ref #71
2021-01-03 17:30:17 +01:00
28c1b6d31d Improved error handling for negative lap times
ref #71
2021-01-03 17:21:53 +01:00
dcb791c9a2 Added the laptime to the track response
ref #71
2021-01-03 17:06:57 +01:00
907259bf73 Added the laptime to createtrack
ref #71
2021-01-03 17:05:43 +01:00
02f7ddbb37 Marked property as optional
ref #71
2021-01-03 17:04:09 +01:00
63b1ca9b56 Added the minimum lap time to the track entity
ref #71
2021-01-03 16:51:36 +01:00
39857cf6e6 Merge pull request 'New Feature: Donor endpoints feature/65-donor_controllers' (#69) from feature/65-donor_controllers into dev
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #69
closes #65

Donors go 💲💲💲
2021-01-02 21:06:08 +00:00
3090ae69f3 Merge branch 'dev' into feature/65-donor_controllers
All checks were successful
continuous-integration/drone/pr Build is passing
2021-01-02 20:55:31 +00:00
92186a86cc Merge pull request 'bugfix/68-address_circular_dependencies' (#70) from bugfix/68-address_circular_dependencies into feature/65-donor_controllers
All checks were successful
continuous-integration/drone/pr Build is passing
Reviewed-on: #70
closes #68
2021-01-02 20:55:02 +00:00
97e8470b0d Change requested by @philipp
All checks were successful
continuous-integration/drone/pr Build is passing
ref #70
2021-01-02 21:53:21 +01:00
6b0e3503a7 Dependency: Bumped license-exporter version
All checks were successful
continuous-integration/drone/push Build is passing
ref odit/license-exporter#1 odit/license-exporter#3
2021-01-02 20:49:20 +01:00
1e2de7656e Reenabled addresses in org responses
All checks were successful
continuous-integration/drone/pr Build is passing
ref #68
2021-01-02 20:03:02 +01:00
56c6a7efb0 Revert "Removed addresses from tests until the circular dependencies are solved"
This reverts commit 599296c4e3.
2021-01-02 19:57:55 +01:00
9c4e54fc6e Added comments to the bugfix 2021-01-02 19:57:33 +01:00
2c47436259 Implemented a possible bugfix
ref #68
2021-01-02 19:56:04 +01:00
9b5d16ae92 Added todo relateing to the bugfix issue
All checks were successful
continuous-integration/drone/pr Build is passing
ref #65 #68
2021-01-02 19:39:02 +01:00
deb13674b2 Added donor put (update) tests
ref #65
2021-01-02 19:25:58 +01:00
17c82ff409 Added donor delete tests
ref #65
2021-01-02 19:13:59 +01:00
f9e314bf9f Added donor add test for address needed error
ref #65
2021-01-02 19:12:02 +01:00
e4c1930dd1 Added donor post (add) tests
ref #65
2021-01-02 19:10:23 +01:00
b337ab424d Added donor get tests
ref #65
2021-01-02 19:02:31 +01:00
82a0e194cb Updated track tests for paralellism
ref #65
2021-01-02 19:02:16 +01:00
599296c4e3 Removed addresses from tests until the circular dependencies are solved
ref #65
2021-01-02 19:01:55 +01:00
2594a607dc Added address check for donors that want a receipt on update
ref #65
2021-01-02 18:30:03 +01:00
335d4e24da Added address check for donors that want a receipt
ref #65
2021-01-02 18:28:22 +01:00
becc277123 Merge branch 'feature/65-donor_controllers' of git.odit.services:lfk/backend into feature/65-donor_controllers 2021-01-02 18:19:51 +01:00
52cdd41ec8 Fixed not null constraint
ref #65
2021-01-02 18:19:45 +01:00
53548ba7a6 Fixed not null constraint
ref #56
2021-01-02 18:19:40 +01:00
1dc438beb2 Mitigated circular dependency (to be fixed)
ref #65
2021-01-02 18:12:18 +01:00
c9ba69792f Extended todo w/ issue link
ref #65
2021-01-02 17:07:17 +01:00
ab67e5f4aa Added basic runner updateing
ref #65
2021-01-02 16:55:27 +01:00
557608e318 Added everything for basic donor creation
ref #65
2021-01-02 16:51:33 +01:00
a83fedc9b8 Added first donor-specific errors
ref #65
2021-01-02 16:47:06 +01:00
61a17b198f Implemented basic donor deletion
ref #65
2021-01-02 16:45:01 +01:00
3df1db4ad8 Added the base logic for donor getters
ref #65
2021-01-02 16:42:55 +01:00
e46cfa0d77 Added donor response class
ref #65
2021-01-02 16:40:38 +01:00
4126d31a5e Added copy of runnerController with some stuff reanames for donors
ref #65
2021-01-02 16:38:07 +01:00
9d9549cdd4 Added new donor permission target
ref #65
2021-01-02 16:37:17 +01:00
eb40de6eb4 Removed legacy license txt file
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-31 18:05:21 +01:00
6efd09db73 new license file version [CI SKIP] 2020-12-31 17:02:56 +00:00
3f09e3d387 Merge pull request 'Automatic and manual license collection 📖' (#62) from feature/59-license_collection into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #62
closes #59
2020-12-31 17:02:08 +00:00
05868e0e00 Bumped license lib version
All checks were successful
continuous-integration/drone/pr Build is passing
ref #59
2020-12-31 18:00:46 +01:00
580a73f9a5 Switched to automatic license attribution generation via oss-attribution-generator
All checks were successful
continuous-integration/drone/pr Build is passing
#59
2020-12-31 15:14:51 +01:00
ab7110d49f Merge branch 'dev' into feature/59-license_collection
All checks were successful
continuous-integration/drone/pr Build is passing
# Conflicts:
#	.drone.yml
2020-12-30 21:26:07 +01:00
875781335c Removed the testing pipeline and updated the dev license pipeline
ref #59
2020-12-30 21:24:51 +01:00
625340cf8a Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-30 21:23:37 +01:00
8d9dbc3957 Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection 2020-12-30 21:23:33 +01:00
07d813082b Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection 2020-12-30 21:23:04 +01:00
a684f60252 Added secondary dependency for piupeline
ref #59
2020-12-30 21:22:59 +01:00
931cae3c98 new license file version [CI SKIP] 2020-12-30 20:22:35 +00:00
dfd82a6293 Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection
All checks were successful
continuous-integration/drone/push Build is passing
# Conflicts:
#	.drone.yml
2020-12-30 21:21:50 +01:00
82d4b11de3 Adjusted ci dependencies
ref #59
2020-12-30 21:21:40 +01:00
75473937cf Adjusted ci dependencies
ref #59
2020-12-30 21:21:08 +01:00
a68bbab8ab Canged drone branch
All checks were successful
continuous-integration/drone/push Build is passing
ref #59
2020-12-30 21:18:40 +01:00
5cfd2c9a52 Revert "Added license exporter (to json)"
All checks were successful
continuous-integration/drone/push Build is passing
This reverts commit 84a0bd2cd9.
2020-12-30 21:17:27 +01:00
6c7b31d76c Revert "Moved package script related files to their own folder"
This reverts commit 395b0101a8.
2020-12-30 21:17:23 +01:00
2924ac2900 Revert "Added automatic license export on dev push/merge"
This reverts commit 18e3ef9a79.
2020-12-30 21:17:18 +01:00
a501625dd6 Revert "Added --full option for the license exporter to export the license path and text as well"
This reverts commit 62c7f26540.
2020-12-30 21:17:13 +01:00
cc64ce4498 Revert "Added test pipeline for automatic license export"
This reverts commit c9378e6cae.
2020-12-30 21:17:09 +01:00
c9378e6cae Added test pipeline for automatic license export
All checks were successful
continuous-integration/drone/push Build is passing
ref #59
2020-12-30 21:13:32 +01:00
62c7f26540 Added --full option for the license exporter to export the license path and text as well
ref #59
2020-12-30 21:05:16 +01:00
18e3ef9a79 Added automatic license export on dev push/merge
ref #59
2020-12-30 20:40:28 +01:00
395b0101a8 Moved package script related files to their own folder
ref #59
2020-12-30 20:22:18 +01:00
84a0bd2cd9 Added license exporter (to json)
ref #59
2020-12-30 20:18:28 +01:00
9cd181c5b8 Merge pull request 'Merge for alpha 0.0.6' (#61) from dev into main
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #61
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2020-12-30 17:58:24 +00:00
41828a6e41 Version bump
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2020-12-30 18:55:16 +01:00
356e398caf Merge pull request 'feature/56-stats_endpoint' (#60) from feature/56-stats_endpoint into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #60
closes #56
2020-12-30 16:49:18 +00:00
6cb978df98 Updated security for the stats endpoints
All checks were successful
continuous-integration/drone/pr Build is passing
ref #56 requested by @philipp
2020-12-30 17:40:18 +01:00
4cb0efa6bd Added response schemas
All checks were successful
continuous-integration/drone/pr Build is passing
ref #56
2020-12-30 17:35:21 +01:00
e0fa58da57 Added some comments
All checks were successful
continuous-integration/drone/pr Build is passing
ref #56
2020-12-30 17:27:24 +01:00
5d31d8d1a2 Added stats and stats responses for orgs
ref #56
2020-12-30 16:59:07 +01:00
53a01ad977 Added stats response
ref #56
2020-12-30 16:31:18 +01:00
d7791756dc Added mission relation resolving
ref #56
2020-12-30 16:13:57 +01:00
dd48ee2f7e Added ResponseSchemas and fixed donation resolution bug
ref #56
2020-12-30 15:07:13 +01:00
ec64ec3d63 Added a response class for team stats
ref #56
2020-12-30 14:41:07 +01:00
35dbfeb5e7 Added donation amount to the stats runner response
ref #56
2020-12-30 14:34:10 +01:00
a9ecfccfd2 Added response schemas
ref #56
2020-12-30 14:31:07 +01:00
d850650aeb Added response class for the runner stats
ref #56
2020-12-30 14:30:31 +01:00
43e256f38c Impelemented stats api auth via token or the usual auth (jwt with get for runners, teams and orgs).
ref #56
2020-12-30 14:19:54 +01:00
b5f9cf201d Moved the authchecker to the middleware folder (b/c it pretty much is a glolified middleware)
ref #56
2020-12-30 14:01:37 +01:00
6e121a3ce2 Implemented more stats endpoints
ref #56
2020-12-29 22:17:29 +01:00
555e37eaf7 Added authed stats routes
ref #56
2020-12-29 21:48:21 +01:00
9675e79441 Added openapi scheme for the stats api tokens.
ref #56
2020-12-29 21:38:48 +01:00
345851bf1d Added example endpoint for stats auth 2020-12-29 21:34:49 +01:00
7c5a3893ef Added basic status api key checking middleware
ref #56
2020-12-29 21:32:45 +01:00
b53b5cf91f Update: keys cant be updated (for security reasons)
ref #56
2020-12-29 21:00:43 +01:00
04813173e4 Updated the method of api key creation.
ref #56
2020-12-29 20:49:45 +01:00
c4270b0839 Adapted the new async behaviour
ref #56
2020-12-29 20:21:45 +01:00
bb24ed53a4 Switched to hased tokens based on uuid (to be canged)
ref #56
2020-12-29 20:20:59 +01:00
1b74b21420 Renamed class
ref #56
2020-12-29 20:07:43 +01:00
b7cbe2a0b4 Adjusted the validation type
ref #56
2020-12-29 20:05:35 +01:00
500b94b44a Added a controller for stats clients (todo: put)
ref #56
2020-12-29 20:01:40 +01:00
641466a731 Added basic errors for stats clients
ref #56
2020-12-29 20:00:31 +01:00
e3ea83bb47 Removed async flag, b/c this doesn't need to perform anything async
ref #56
2020-12-29 19:57:19 +01:00
b6043744a9 Added STATSCLIENT as a new permission target
ref #56
2020-12-29 19:48:35 +01:00
2b38044271 Created a response for the statsClient
ref #56
2020-12-29 19:45:30 +01:00
4c3d2643c1 Added enabled flag for the stats clients
ref #56
2020-12-29 19:37:55 +01:00
e2cc0c0b80 Added Create action for the statsclients
ref #56
2020-12-29 19:34:14 +01:00
ce55dce011 Removed abstract flag from class
ref #56
2020-12-29 19:32:20 +01:00
a738c19316 Added the new statsClient class for stats api auth
ref #56
2020-12-29 19:29:16 +01:00
63b8176bdf Merge branch 'dev' into feature/56-stats_endpoint 2020-12-29 19:18:56 +01:00
bc76afafce Merge pull request 'Updates for the tag build pipeline' (#58) from dev into main
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #58
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2020-12-29 18:08:09 +00:00
1f49ad43a1 Merge branch 'main' into dev
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2020-12-29 18:07:47 +00:00
6a762f570d Added team and org stats
ref #56
2020-12-29 16:08:50 +01:00
1b7424f750 Added stats endpoint with some basic stats (more to come) - to be tested
ref #56
2020-12-29 15:25:40 +01:00
bdd4f705be Adjusted return type, since async is no longer needed here (thanks to db relations)
ref #56
2020-12-29 15:23:29 +01:00
ded14b1b3b Changed method of triggering lib builds
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2020-12-29 14:57:00 +01:00
fbd3f615ad Changed docker image tag
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-29 14:56:37 +01:00
a22a7a19c2 Merge pull request 'Final fix for the tag pipeline triggers' (#57) from dev into main
Some checks failed
continuous-integration/drone/tag Build was killed
Reviewed-on: #57
Reviewed-by: odit_bot <bot@odit.services>
2020-12-29 13:18:39 +00:00
2d263814db Merge branch 'main' into dev 2020-12-29 13:17:33 +00:00
a79bed259b Moved to the official tag recognition
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-29 14:13:48 +01:00
f2970f4cd8 Added branch to when
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 19:09:01 +01:00
b3f741234e Back to when syntax for triggering tag builds
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:51:07 +01:00
6a8247f88a Now using the exact trigger snytax the gitea project uses
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:46:38 +01:00
b737fe6a08 Set trigger to ref tags only
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:39:44 +01:00
607630c4f9 Tried switching to global when
Some checks failed
continuous-integration/drone/push Build was killed
2020-12-23 18:38:01 +01:00
a7976c0ee2 Switched from trigger to when
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:36:37 +01:00
b51da15007 Added pushing to tags as trigger
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:33:56 +01:00
5ed5f181d1 Added tag as ref to tag build
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:32:32 +01:00
e33076c04d Removed push from tag build triggers
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:30:08 +01:00
ae35f50da2 Added push as drone tag build event trigger
Some checks failed
continuous-integration/drone/push Build was killed
2020-12-23 18:28:10 +01:00
cc5d90cb4f Merge pull request 'Bugfix for the release pipeline (no other changes)' (#55) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #55
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2020-12-23 17:18:29 +00:00
c33236c516 Merge branch 'main' into dev
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2020-12-23 18:11:47 +01:00
eee2bbcac7 Merge branch 'dev' of git.odit.services:lfk/backend into dev
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 18:11:23 +01:00
519d11beef Removed the branch requirements from dev
ref #47
2020-12-23 18:11:20 +01:00
cbed5fc0b2 Merge pull request 'Merge alpha 0.0.5 to master' (#54) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #54
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>

ref #47
2020-12-23 17:05:32 +00:00
59fdfe9f40 Merge branch 'main' into dev
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2020-12-23 17:02:12 +00:00
c93e93be31 Set package version (+openapi version)
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
ref #47
2020-12-23 18:00:53 +01:00
d3760f7b80 Merge pull request 'feature/52-alternative_openapi_viewers' (#53) from feature/52-alternative_openapi_viewers into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #53
closes #52
2020-12-23 16:57:17 +00:00
11c7d041ef 🎨 fixed landing html + styling
All checks were successful
continuous-integration/drone/pr Build is passing
ref #52
2020-12-23 17:55:44 +01:00
9ab6eb5314 Added tests for the api docs
All checks were successful
continuous-integration/drone/pr Build is passing
ref #52
2020-12-23 17:01:18 +01:00
ce0500ef8c Removed the firsttests jest tests (they were redundant)
ref #52
2020-12-23 17:01:03 +01:00
0b4d30b3f3 Updated the openapi json path for the ci testing script
Some checks failed
continuous-integration/drone/pr Build is failing
ref #52
2020-12-23 16:54:45 +01:00
bb70bf58fb Added the static files to the build step
Some checks failed
continuous-integration/drone/pr Build is failing
ref #52
2020-12-23 15:43:03 +01:00
9fc282d858 Removed everything concerning the swaggerUI express middleware
ref #52
2020-12-23 15:21:55 +01:00
39ad43bbb2 switched over to using the static deployment of swaggerUI
ref #52
2020-12-23 15:20:06 +01:00
bd46a48f76 Merge branch 'feature/52-alternative_openapi_viewers' of git.odit.services:lfk/backend into feature/52-alternative_openapi_viewers 2020-12-23 15:11:17 +01:00
ebedea97ed Added very basic api doc chooser
ref #52
2020-12-23 15:11:14 +01:00
5c3c3eb167 Added very basic api doc chooser
ref #52
2020-12-23 15:11:04 +01:00
d8e38f404d Renamed the package to fit the scheme for the project
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-22 20:43:49 +01:00
aa1042ca51 Merge pull request 'feature/49-openapi_cookie_schema' (#51) from feature/49-openapi_cookie_schema into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #51
closes #49
2020-12-22 19:33:03 +00:00
9994f8ddc4 Merge branch 'dev' into feature/49-openapi_cookie_schema
All checks were successful
continuous-integration/drone/pr Build is passing
2020-12-22 19:32:35 +00:00
3ac536ef23 Merge pull request 'feature/45-auth_tests' (#50) from feature/45-auth_tests into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #50
closes #45
2020-12-22 19:32:20 +00:00
5d75f70296 fixed typo
All checks were successful
continuous-integration/drone/pr Build is passing
ref #49
2020-12-22 20:29:18 +01:00
c34bde7d4f Fixed typo
All checks were successful
continuous-integration/drone/pr Build is passing
ref #49
2020-12-22 20:19:28 +01:00
1f061c7ea6 Updated the openapi descriptions for all group routes
ref #49
2020-12-22 20:18:30 +01:00
578f9301db Updated the openapi descriptions for all user routes
ref #49
2020-12-22 20:13:16 +01:00
9b47f3ab05 Updated the openapi descriptions for all track routes
ref #49
2020-12-22 20:07:41 +01:00
84b97bee8d Updated the openapi descriptions for all status routes
ref #49
2020-12-22 20:05:29 +01:00
767841d405 Merge branch 'feature/49-openapi_cookie_schema' of git.odit.services:lfk/backend into feature/49-openapi_cookie_schema
# Conflicts:
#	src/controllers/RunnerTeamController.ts
2020-12-22 20:04:19 +01:00
16e5b6921d Updated the openapi descriptions for all team routes
ref #49
2020-12-22 20:04:08 +01:00
58a12c7fa1 Updated the openapi descriptions for all team routes
ref #49
2020-12-22 20:03:49 +01:00
f256dec121 Updated the openapi descriptions for all organisation routes
ref #49
2020-12-22 20:01:25 +01:00
9bb4865b2d Merge branch 'feature/49-openapi_cookie_schema' of git.odit.services:lfk/backend into feature/49-openapi_cookie_schema
# Conflicts:
#	src/controllers/RunnerController.ts
2020-12-22 19:58:25 +01:00
66631f5e0a Updated the openapi descriptions for all runner routes
ref #49
2020-12-22 19:57:46 +01:00
8de35f3431 Updated the openapi descriptions for all runner routes
ref #49
2020-12-22 19:55:37 +01:00
05319e6f6e Updated the openapi descriptions for all permission routes
ref #49
2020-12-22 19:51:37 +01:00
b7827fef54 Updated the openapi descriptions for all import routes
ref #49
2020-12-22 19:45:09 +01:00
a4ddeee8e4 Fixed uniqueness error
All checks were successful
continuous-integration/drone/pr Build is passing
ref #45
2020-12-22 19:38:12 +01:00
50f2462eb9 Updated the openapi descriptions for all auth routes
ref #49
2020-12-22 19:23:35 +01:00
dae51cfd47 Added openapi cookie security schema
ref #49
2020-12-22 19:13:20 +01:00
e1341fc126 Merge branch 'dev' into feature/45-auth_tests
Some checks failed
continuous-integration/drone/pr Build is failing
2020-12-22 18:50:13 +01:00
a9dbf1d0d2 Added login test after logout
Some checks failed
continuous-integration/drone/pr Build is failing
ref #45
2020-12-22 18:49:10 +01:00
c6ecde29b5 Added auth reset tests
ref #45
2020-12-22 18:48:54 +01:00
13949af938 Added auth refresh tests
ref #45
2020-12-22 18:29:23 +01:00
3c003a60b2 Added logut tests
ref #45
2020-12-22 18:26:20 +01:00
69796a888f Added wron password auth test
ref #45
2020-12-22 17:04:22 +01:00
a85e914759 Added validator as a explicit dependency, b/c pnpm doesn't fallback to peer dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-22 16:57:01 +01:00
af2744885f added the first login tests
ref #45
2020-12-22 16:56:02 +01:00
8d73a9dd59 Merge pull request 'feature/40-pw_reset' (#48) from feature/40-pw_reset into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #48
closes #40
2020-12-22 15:29:43 +00:00
853876a09c Merge branch 'dev' into feature/40-pw_reset
All checks were successful
continuous-integration/drone/pr Build is passing
2020-12-22 16:05:27 +01:00
cdc90b0770 Merge pull request 'feature/43-postal_from_env' (#46) from feature/43-postal_from_env into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #46
closes #43
2020-12-22 14:55:37 +00:00
d0cfc16f8b Merge branch 'dev' into feature/43-postal_from_env
All checks were successful
continuous-integration/drone/pr Build is passing
2020-12-22 15:55:12 +01:00
ce5f4b467d Updated ci to trigger the builds for the new libs
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-22 15:44:00 +01:00
84a7f30a60 Merge branch 'dev' into feature/43-postal_from_env
All checks were successful
continuous-integration/drone/pr Build is passing
2020-12-22 12:41:15 +01:00
f3008979f3 Added the POSTALCODE_COUNTRYCODE to the sample and ci env files
ref #43
2020-12-22 12:40:11 +01:00
b8c93bf476 Implemented the getter for loading the postalcodelocale from env
ref #43
2020-12-22 12:38:53 +01:00
146787fd66 Added comments
All checks were successful
continuous-integration/drone/pr Build is passing
ref #40
2020-12-22 11:48:06 +01:00
9458b774ea Removed the user disableing
ref #40
2020-12-22 11:35:33 +01:00
bf4250babd All things auth now check if the user is disabled
ref #40
2020-12-22 11:29:52 +01:00
a16c4c564a Users now can be disabled from the start
ref #40
2020-12-22 11:27:21 +01:00
8d860cb2e1 Fixed weired query behaviour
ref #40
2020-12-22 11:26:45 +01:00
2f7b0d5606 Removed bs enabled check
ref #40
2020-12-22 11:20:11 +01:00
4b9bfe3b79 Now disableing users while they're in the process of resetting their password
ref #40
2020-12-22 11:18:31 +01:00
17ee682029 Implemented a password reset timeout
ref #40
2020-12-22 11:12:24 +01:00
48685451be Set reset token expiry to 15 mins
rer #40
2020-12-22 11:07:01 +01:00
5aad581c2d Implemented toe password reset route
ref #40
2020-12-22 10:57:25 +01:00
caeb17311b Implemented basic password reset
ref #40
2020-12-22 10:57:08 +01:00
5aa83fe2f0 Renamed the return variable to fit the class
ref #40
2020-12-22 10:44:43 +01:00
aef8485f59 Renamed the password reset token creation class to better fit the scheme
ref #40
2020-12-22 10:39:42 +01:00
61aff5e629 Added a password reset token request route
ref #40
2020-12-22 10:39:17 +01:00
aa146cd6c1 Added a basic pw reset action
ref #40
2020-12-22 10:38:48 +01:00
6042089074 Added pw reset jwt generation
ref #40
2020-12-22 10:24:25 +01:00
b6cf3b24d4 Merge pull request 'Disabled the x-served-by and x-powered-by Headers' (#44) from feature/41-owasp_headers into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #44
2020-12-21 17:27:12 +00:00
19422edbae Disabled the x-served-by and x-powered-by Headers
All checks were successful
continuous-integration/drone/pr Build is passing
ref #41
2020-12-21 17:48:04 +01:00
1bf6d3d564 Merge pull request 'Updated the put methods and cleaned up a shitload of comments' (#42) from feature/39-update_puts into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #42
closes #39
2020-12-21 16:39:19 +00:00
7d5f3b092f Reverted simplification that created loops
All checks were successful
continuous-integration/drone/pr Build is passing
ref #39
2020-12-21 17:22:07 +01:00
0ef6d9cc48 Small bugfix
Some checks failed
continuous-integration/drone/pr Build is failing
ref #39
2020-12-21 16:58:51 +01:00
48bef8db60 Second part of the action comment refactoring
Some checks failed
continuous-integration/drone/pr Build is failing
ref #39
2020-12-21 16:21:12 +01:00
1d0d79f3da First part of the action comment refactoring
ref #39
Why did i volunteer for this? It's just a glorified sleeping aid 😴
2020-12-21 16:08:10 +01:00
d20d738218 Code + comment cleanup for the entities
ref #39
2020-12-21 15:29:32 +01:00
a03f1a438d Code + comment cleanup for the enums
ref #39
2020-12-20 19:39:13 +01:00
75332983c2 Code + comment cleanup for the response models
ref #39
2020-12-20 19:38:22 +01:00
a85d52437b Code + comment cleanup for the seeds
ref #39
2020-12-20 19:11:28 +01:00
a88c0389c1 Code + Comment cleanup for the middlewares
ref #39
2020-12-20 19:08:02 +01:00
43a4f1118d Updated loader comments and descriptions
ref #39
2020-12-20 19:01:03 +01:00
de91d491e5 Added a missing poiunt/exclamation mark
ref #39
2020-12-20 18:55:52 +01:00
2199cb0aef Fixed messages and comments for UserGroupErrors
ref #39
2020-12-20 18:50:45 +01:00
ee76f1c0e8 Fixed messages and comments for UserErrors
ref #39
2020-12-20 18:50:06 +01:00
75b6489f8d Fixed messages and comments for TrackErrors + spelling for some other errors
ref #39
2020-12-20 18:48:59 +01:00
389f6347c3 Fixed messages and comments for RunnerTeamErrors
ref #39
2020-12-20 18:47:42 +01:00
37afc10e44 Fixed messages and comments for RunnerOrganisationErrors
ref #39
2020-12-20 18:46:43 +01:00
82ced34750 Fixed messages and comments for RunnerGroupErrors
ref #39
2020-12-20 18:45:33 +01:00
5de81ad093 Fixed messages and comments for RunnerErrors
ref #39
2020-12-20 18:45:10 +01:00
c1d784e29c Fixed messages and comments for PermissionErrors
ref #39
2020-12-20 18:42:57 +01:00
4ca85a1f22 Fixed messages and comments for AuthErrors
ref #39
2020-12-20 18:41:25 +01:00
7a4238f1f7 Fixed some stuff not getting checked against null
ref #39 gosh i sometimes hate js types
2020-12-20 18:18:32 +01:00
fbe2b358bd Moved tracks to the new put mechanism
ref #39
2020-12-20 18:07:45 +01:00
532b5a56a5 Switched runner orgs to the cleaner syntax via a update entity
ref #39
2020-12-20 18:07:33 +01:00
18ede29ea5 Moved usergroups to the new put mechanism
ref #39
2020-12-20 17:37:20 +01:00
ec4d75128b Fixed some weired toString beviour
ref #39 #6
2020-12-20 17:36:22 +01:00
b2bd6173a5 Moved permissions to the new put mechanism
ref #39
2020-12-20 17:29:04 +01:00
cc68948a20 Moved runners to the new put mechanism
ref #39
2020-12-20 17:27:21 +01:00
24de82f6df Moved runner teams to the new put mechanism
ref #39
2020-12-20 17:25:41 +01:00
cf583a22fa Added missing username property to the responseuser
ref #39
2020-12-20 17:19:33 +01:00
b55d210aff Fixed wrong error type
ref #39
2020-12-20 17:18:16 +01:00
adec2bcc5b removed useless deletes
ref #39
2020-12-20 17:17:42 +01:00
3850bd9681 Renamed function to better reflect it's function
ref #39
2020-12-20 17:17:30 +01:00
14b6651f96 Merge pull request 'Fixed a bug concerning user updates' (#38) from bugfix/37-user_update into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #38
closes #37
2020-12-20 15:58:19 +00:00
4a21c1fb5c Updated some nameing to fit with the rest of the models
All checks were successful
continuous-integration/drone/pr Build is passing
ref #37
2020-12-20 16:51:59 +01:00
ca142376b3 Fixed some weired user update behaviour
ref #37
2020-12-20 16:49:05 +01:00
314606addd Merge pull request 'feature/34-status_health' (#36) from feature/34-status_health into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #36
closes #34
2020-12-18 22:02:34 +00:00
a0a08f7724 Formatting implemented for @philipp
All checks were successful
continuous-integration/drone/pr Build is passing
ref #34
2020-12-18 23:00:27 +01:00
cea5993049 added a simple health route
ref #34
2020-12-18 22:58:24 +01:00
3e940c2db5 Merge pull request 'Auth for everything (and everything auth) #6' (#35) from feature/6-api_auth into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #35

closes #6
2020-12-18 21:53:16 +00:00
631310f158 Fixed import for linux
All checks were successful
continuous-integration/drone/pr Build is passing
ref #6
2020-12-18 22:49:01 +01:00
c3e3c6bed1 Manual overwrite
Some checks failed
continuous-integration/drone/pr Build is failing
ref #6
2020-12-18 22:46:59 +01:00
8f48d2593b Merge branch 'feature/6-api_auth' of git.odit.services:lfk/backend into feature/6-api_auth
Some checks failed
continuous-integration/drone/pr Build is failing
2020-12-18 22:44:29 +01:00
23758e7a91 Bugfix for bs file names
ref #6
2020-12-18 22:44:27 +01:00
c7fd0593fb Bugfix for bs file names
Some checks failed
continuous-integration/drone/pr Build is failing
ref #6
2020-12-18 22:42:48 +01:00
b19f18ada1 Added auth to all tests
Some checks failed
continuous-integration/drone/pr Build is failing
ref #6
2020-12-18 22:11:41 +01:00
d742ccd581 Jwt's now feature group permissions and permission deduplication
ref #6
2020-12-18 21:44:30 +01:00
d670b814a4 Fixed the user->Group relation
ref #6
2020-12-18 21:42:43 +01:00
1a9c860188 Formatting #6 2020-12-18 20:53:35 +01:00
f25ae9ba4f Added a admin group with all permissions to seeding 2020-12-18 20:33:27 +01:00
744faba7ee Added auth to all endpoints 2020-12-18 20:33:13 +01:00
cdfd0e0d64 Added the openapi security header to all routes that need some kind of auth
ref #6
2020-12-18 20:07:05 +01:00
e25fc795fe Added additional targets and actions for permissions
ref #6
2020-12-18 20:06:27 +01:00
2240a45a91 Added class validation for the enum
ref #6
2020-12-18 19:49:39 +01:00
595a9213c1 Added comments and formatting to the auth checker
ref #6
2020-12-18 19:42:08 +01:00
428e2c38ce Added coments to the jwt creator 2020-12-18 19:33:10 +01:00
1d54fb085b Shoothed out variable nameing scheme
ref #6
2020-12-18 19:19:47 +01:00
6403e386ab Now with smooth access token refreshing
ref #6
2020-12-18 19:07:31 +01:00
65a8449ea3 Now with 1000% cleaner jwt generation
ref #6
2020-12-18 17:57:48 +01:00
b21dd6f0c0 Added tracks/get as test-route for auth
ref #6
2020-12-18 17:19:02 +01:00
445e96dcdf Added toString for permissions
ref #6
2020-12-18 17:17:02 +01:00
6237e62a03 Reimplmented the old permission checking system
ref #6
2020-12-18 17:15:44 +01:00
b9e91502cd Cleaned up the auth checker a little bit 2020-12-18 17:11:44 +01:00
9dc336f0bb Added permission deletion on group deletion
ref #6
2020-12-18 16:21:59 +01:00
6a7e8ccc37 Now with duplication avoidance
ref #6
2020-12-18 16:10:33 +01:00
882065470a Implemented permission updateing
ref #6
2020-12-18 16:05:25 +01:00
ff3a5b4545 User deletion now also delete's the users permissons
ref #6
2020-12-18 15:49:42 +01:00
d4293c164d Implemented permission deletion
ref #6
2020-12-18 15:37:45 +01:00
145a08b1b4 Now with cleaner participants in the responses
ref #6
2020-12-18 15:26:54 +01:00
dc485c02ea Added Permission creation
ref #11
2020-12-18 15:19:44 +01:00
ebb0c5faca Added specific permission getting
ref #6
2020-12-18 15:16:15 +01:00
d89fcb84a2 Implemented permission getting
ref #6
2020-12-18 15:12:06 +01:00
388fc6ba6a Fixed typo 2020-12-18 14:52:31 +01:00
bb4ea485fd Merge branch 'dev' into feature/6-api_auth 2020-12-18 14:40:40 +01:00
5dc9edfe40 Pulled out some linguini-esc code
ref #6
2020-12-18 14:40:19 +01:00
eb9473e230 Cleaned up relation types
ref #6
2020-12-18 14:29:31 +01:00
476afc6a99 Updated nameing to fit the usual scheme
ref #6
2020-12-18 14:29:17 +01:00
ed53627bbe Merge pull request 'Runner import' (#33) from feature/22-runner_import into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #33
closes #22
2020-12-18 13:24:51 +00:00
efecffb72d Added responseusers
ref #6
2020-12-17 21:12:45 +01:00
3aae8f85c4 Added status codes
All checks were successful
continuous-integration/drone/pr Build is passing
ref #22
2020-12-17 20:54:01 +01:00
cc5a30980a Implemented new Permission system on the DB side.
ref #22
2020-12-17 20:46:54 +01:00
c90f9f1dd4 Fixed path
All checks were successful
continuous-integration/drone/pr Build is passing
2020-12-17 19:27:38 +01:00
15ed9f58d5 Added responseschemas and content types
All checks were successful
continuous-integration/drone/pr Build is passing
ref #22
2020-12-17 19:17:35 +01:00
9db4344153 Expanded API Decriptions
ref #22
2020-12-17 19:15:11 +01:00
03b7e346ab Working csv import
ref #22
2020-12-17 18:36:51 +01:00
0d8fbf1eca Consolidated the json import for a cleaner result
ref #22
2020-12-17 17:25:17 +01:00
71228fbf33 Now organisations and teams can import runners 2020-12-17 17:14:08 +01:00
97494aeaf7 Runners can now be imported into a org 2020-12-17 16:46:00 +01:00
4801e010b4 Removed useless console.log
ref #22
2020-12-17 16:33:54 +01:00
1b59d58c60 Abstracted a little bit more for potential company runner import 2020-12-17 16:32:29 +01:00
cad30c7f63 Fixed the dynamic class creation 2020-12-17 16:26:33 +01:00
a8ec0142b0 Added import-action classes
ref #22
2020-12-17 16:21:02 +01:00
30952aa14f Marked csv import as not implemented 2020-12-17 16:20:20 +01:00
2e4a4f1661 Added endpoints for runner import by json and csv 2020-12-16 19:03:27 +01:00
b9fd2379f4 Added rawbody if needed
ref #22
2020-12-16 19:00:25 +01:00
1b1f8f2b09 Added a basic import controller
ref #22
2020-12-16 18:20:31 +01:00
39b932a81c Merge pull request 'feature/31-lib_generation' (#32) from feature/31-lib_generation into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #32
2020-12-15 15:41:41 +00:00
ec69f6caf3 removed the lib generation part
All checks were successful
continuous-integration/drone/pr Build is passing
2020-12-13 19:20:36 +01:00
ad908a3555 Fixed broken substitution
All checks were successful
continuous-integration/drone/pr Build is passing
ref #31
2020-12-13 12:57:09 +01:00
3e6c7b6302 Cleanup
Some checks failed
continuous-integration/drone/pr Build encountered an error
2020-12-13 10:06:32 +01:00
d0c5323cb6 Push
ref #31
2020-12-13 10:04:09 +01:00
fcb3e35b29 Removed the test pipeline
ref #31
2020-12-13 09:42:29 +01:00
4705b5a0b4 I just need to trigger sth
All checks were successful
continuous-integration/drone/push Build is passing
ref #31
2020-12-13 09:21:50 +01:00
0c6f3d1f12 Added downstream trigger
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-13 09:18:54 +01:00
ff178f9d77 Removed the bs code
ref #31
2020-12-12 22:37:11 +01:00
e59630b17e More switching
Some checks failed
continuous-integration/drone/push Build is failing
ref #31
2020-12-12 22:34:07 +01:00
20ec6e0cd6 fixed command order
Some checks failed
continuous-integration/drone/push Build is failing
ref #31
2020-12-12 22:32:43 +01:00
e10a3947ba fixed duplicate name
Some checks failed
continuous-integration/drone/push Build is failing
ref #31
2020-12-12 22:31:44 +01:00
8d00487359 test drone pipeline
Some checks failed
continuous-integration/drone/push Build encountered an error
ref #31
2020-12-12 22:31:06 +01:00
f304b86cb6 Added lib to gitignore
ref #31
2020-12-12 22:22:33 +01:00
421ddc50ed Added rlly basic lib generation
ref #31
2020-12-12 22:21:45 +01:00
c3aa88c212 Renamed some drone steps [skip-ci}
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-12 20:05:43 +01:00
10dbd233a0 Merge pull request 'feature/24-production_dockerfile' (#30) from feature/24-production_dockerfile into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #30
closes #24
2020-12-12 19:03:22 +00:00
c321da613a Switched env to dev for tests(ci)
All checks were successful
continuous-integration/drone/pr Build is passing
ref #24
2020-12-12 20:01:26 +01:00
ff84209683 Merge branch 'dev' into feature/24-production_dockerfile
Some checks failed
continuous-integration/drone/pr Build was killed
2020-12-12 18:54:02 +00:00
df3c231fd2 Merge pull request 'feature/25-refresh-token-cookie' (#29) from feature/25-refresh-token-cookie into dev
Reviewed-on: #29
closed #25
2020-12-12 18:52:28 +00:00
ac2da0af63 Now w/ working logout
All checks were successful
continuous-integration/drone/pr Build is passing
ref #25
2020-12-12 19:50:12 +01:00
40fb081332 Cleaned up the pipelines
Some checks failed
continuous-integration/drone/pr Build is failing
ref #24
2020-12-12 19:37:21 +01:00
30928180e6 Switched to prefering body provided tokens over cookie tokens
All checks were successful
continuous-integration/drone/pr Build is passing
ref #25
2020-12-12 19:27:56 +01:00
6aa1e0d573 Cleaned up some errors
ref #25
2020-12-12 19:26:04 +01:00
aca3eaaeea Now w/ working cookie based refresh
ref #25
2020-12-12 19:25:40 +01:00
615b54ec4f Removed secure flag and added expiry basd on ht refresh token
ref#25
2020-12-12 19:13:18 +01:00
c07d40ae93 Added cookie-parser to app.use
ref #25
2020-12-12 19:01:31 +01:00
db5da3d3c2 Removed useless return
ref #25
2020-12-12 18:34:22 +01:00
0e003d2dc4 Set cookies to secure
ref #25
2020-12-12 18:32:48 +01:00
a1c3751164 🚀 CI build on feature branch tags
ref #24
2020-12-12 18:13:23 +01:00
359e955926 🚀 CI/CD
ref #24
2020-12-12 17:48:45 +01:00
c391201570 🐳 optimize Dockerfile in speed and size (pnpm + layers)
ref #24
2020-12-12 17:48:32 +01:00
e3980096e2 🚧 move sqlite to to production
ref #24
2020-12-12 17:48:02 +01:00
a7e27c6f6c drop unused packages
ref #24
2020-12-12 13:27:57 +01:00
bcb266e29b move to node:14.15.1-alpine3.12
ref #24
2020-12-12 13:24:27 +01:00
95f40a9c28 🩺🐳 Docker healthcheck
ref #24
2020-12-12 13:15:29 +01:00
8bcaf710ad integrate pm2 process manager to keep the app up and running
ref #24
2020-12-12 13:14:38 +01:00
b8aebc14e8 🐳 working Dockerfile
ref #24
2020-12-12 13:04:37 +01:00
5ccdfe1540 package.json - drop nodemon delay
ref #24
2020-12-12 13:04:20 +01:00
a1e3289a88 🐞 fixed app.ts for production use
ref #24
2020-12-12 12:39:53 +01:00
47e4f6cd7e basic build works 2020-12-12 12:29:14 +01:00
36fbccb286 🚧 implementation in AuthController@login
ref #25
2020-12-12 11:55:45 +01:00
7429407843 Merge pull request 'New Feature: User seeding feature/19-user_seeding' (#26) from feature/19-user_seeding into dev
Reviewed-on: #26
closes #19
2020-12-11 19:40:44 +00:00
10640f40aa Merge branch 'dev' into feature/19-user_seeding
All checks were successful
continuous-integration/drone/pr Build is passing
# Conflicts:
#	package.json
2020-12-11 20:38:33 +01:00
1e625b0775 Merge pull request 'Added drone pipeline that automaticly runs on prs (or at least it should)' (#27) from feature/23-tests_on_pr into dev
Reviewed-on: #27
closes #23
2020-12-11 19:33:40 +00:00
6cfaec8397 Added ci env
All checks were successful
continuous-integration/drone/pr Build is passing
ref #23
2020-12-11 20:29:33 +01:00
0f419625d2 switched to using the ci testing script
Some checks failed
continuous-integration/drone/pr Build was killed
ref #23
2020-12-11 20:25:26 +01:00
a83a23a647 fixed typo
Some checks failed
continuous-integration/drone/pr Build is failing
ref #23
2020-12-11 20:24:03 +01:00
553a35bb8e switched to custom clone logic
Some checks failed
continuous-integration/drone/pr Build is failing
ref #23
2020-12-11 20:23:12 +01:00
ef3fcee2a9 testing branch parameter
Some checks failed
continuous-integration/drone/pr Build is failing
2020-12-11 20:22:31 +01:00
61b2baaee7 renamed step
Some checks failed
continuous-integration/drone/pr Build is failing
ref #23
2020-12-11 20:18:53 +01:00
31e7d074dc Added dedicated clone step
Some checks failed
continuous-integration/drone/pr Build encountered an error
ref #23
2020-12-11 20:18:03 +01:00
1fbddf5ef8 Added source
Some checks failed
continuous-integration/drone/pr Build is failing
2020-12-11 20:13:32 +01:00
7a79f35b58 Test for branch restrictions
All checks were successful
continuous-integration/drone/pr Build is passing
ref #23
2020-12-11 20:07:52 +01:00
79e418f918 Added a test:ci script (for testing in ci enviornments)
Some checks failed
continuous-integration/drone/pr Build is failing
ref #23
2020-12-11 19:56:27 +01:00
abb13045e6 Switched to yarn
Some checks failed
continuous-integration/drone/pr Build is failing
ref #23
2020-12-11 19:47:35 +01:00
d543dfb201 Added drone pipeline that automaticly runs on prs (or at least it should)
Some checks failed
continuous-integration/drone/pr Build is failing
ref #23
2020-12-11 19:45:56 +01:00
5eabc1fe18 Merge branch 'dev' into feature/19-user_seeding
# Conflicts:
#	ormconfig.ts
#	package.json
2020-12-11 19:32:53 +01:00
473033aa50 User seeding now automaticly runs if no users are detected
ref #19
2020-12-11 19:29:23 +01:00
effa79032b Added seed yarn script
ref #19
2020-12-11 19:14:48 +01:00
57f6775140 Merge pull request 'feature/17-automated_tests' (#21) from feature/17-automated_tests into dev
Reviewed-on: #21
closes: #17
2020-12-10 19:36:07 +00:00
5a27689e80 new get test
ref #17
2020-12-10 20:33:36 +01:00
d295100a48 refactoring: cleaned up the names
ref #17
2020-12-10 20:32:57 +01:00
09decd5600 Added first demo seed
ref #19
2020-12-10 20:26:46 +01:00
6eee80d357 Runner update tests now run clean
ref #17
2020-12-10 20:08:20 +01:00
cada962e5a Merge branch 'dev' into feature/17-automated_tests
# Conflicts:
#	src/controllers/RunnerTeamController.ts
2020-12-10 20:05:52 +01:00
721af32989 Bugfix for runner team updates
ref #13 #17
2020-12-10 20:05:20 +01:00
92dee666ee Added team update test
ref #17
2020-12-10 19:53:19 +01:00
6e12b014e7 future proved the group update failture
ref #17
2020-12-10 19:48:50 +01:00
c20f01f485 Added runner update tests 2020-12-10 19:48:03 +01:00
eda8abb668 Merge branch 'dev' into feature/17-automated_tests
# Conflicts:
#	src/controllers/RunnerController.ts
#	src/models/actions/CreateParticipant.ts
2020-12-10 19:37:52 +01:00
02877ece9c Little comment cleanup
ref #13
2020-12-10 19:36:49 +01:00
f3000f14cd Runner updateing now works with it's own class
ref #13
2020-12-10 19:31:48 +01:00
068e5bd72b Merge branch 'dev' into feature/17-automated_tests
# Conflicts:
#	src/models/responses/ResponseEmpty.ts
2020-12-10 18:51:50 +01:00
bd07763455 Fix for the 404 in the swagger doc 2020-12-10 18:50:18 +01:00
64725d9e7a Added basic update test 2020-12-10 18:39:40 +01:00
d2e0384f3c Added runner deletion tests
ref #17
2020-12-10 18:30:26 +01:00
e223c060d4 Fixed runner get test
ref #17
2020-12-10 18:30:09 +01:00
49ac7be367 Moded runner get tests to a new file and added more of them
ref #17
2020-12-10 17:59:12 +01:00
9df86953cf Merge branch 'dev' into feature/17-automated_tests
# Conflicts:
#	src/app.ts
#	src/controllers/RunnerController.ts
#	src/controllers/RunnerOrganisationController.ts
#	src/controllers/RunnerTeamController.ts
#	src/models/actions/CreateParticipant.ts
2020-12-10 17:45:23 +01:00
aaeef4a27e Replaced a console log with a consola.error 2020-12-10 17:44:17 +01:00
d5e5e27ca3 Merge branch 'feature/13-runner_controllers' into dev 2020-12-10 17:43:15 +01:00
7fe9480c94 Removed console logs 2020-12-10 17:43:00 +01:00
bc80be947d Fixed optional property
ref #13 #17
2020-12-10 17:42:49 +01:00
47862f2e1d Added runner creation tests
ref #17
2020-12-10 17:41:15 +01:00
d0d050e6c6 Added basic runner get tests
ref #17
2020-12-10 16:18:23 +01:00
e2feffa1c5 Merge branch 'dev' into feature/17-automated_tests 2020-12-10 16:13:40 +01:00
ff6a4eaca1 Removed sqlite jurnal (however it managed to end up here) 2020-12-10 16:13:05 +01:00
3e961e34a1 Added squlite jurnal tmp file to the gitignore 2020-12-10 16:12:26 +01:00
32a92b1ad7 Added org deletion tests (orgs that still have teams)
ref #17
2020-12-10 16:10:35 +01:00
105efdd454 Added team update tests
ref #17
2020-12-09 20:08:01 +01:00
6e316a7533 Cleanup
ref #17
2020-12-09 19:57:02 +01:00
71e5be2ba4 added non-existant deletion test for teams
ref #17
2020-12-09 19:55:36 +01:00
e3a5b41b5e Merge pull request 'latest work' (#20) from dev into main
Reviewed-on: #20
Reviewed-by: Nicolai Ort <info@nicolai-ort.com>
2020-12-09 18:49:30 +00:00
80ef7e8c3a Adjustes responsecode 2020-12-09 19:43:51 +01:00
d2898ff60f Merge branch 'dev' into feature/17-automated_tests 2020-12-09 19:42:51 +01:00
429041fef1 Merge branch 'dev' into feature/13-runner_controllers 2020-12-09 19:41:31 +01:00
df5b8ac141 Went back to using id's for deletion (for cleaner query params)
ref #13 #17
2020-12-09 19:41:15 +01:00
cbecff85f0 Merge branch 'feature/18-exported-env-vars' into dev
close #16, close #18
2020-12-09 19:41:09 +01:00
622bdf7a3f move to dotenv + custom env validations
ref #18
2020-12-09 19:40:08 +01:00
a068c4d318 Deletes now return 204 instead of 404 (better rest compatability)
ref #13
2020-12-09 19:34:49 +01:00
6396fffc04 Added test for non-existant deletion
ref #17
2020-12-09 19:20:33 +01:00
5845a91f15 Fixed typos 2020-12-09 19:20:19 +01:00
f4abbfcee4 Added test for getting an non-existant team 2020-12-09 19:16:10 +01:00
c3258b9304 Added team delete test 2020-12-09 19:15:54 +01:00
4cfe9df429 final phone validation move to ZZ default
close #16
2020-12-09 19:09:20 +01:00
0fc0b87c67 Merge branch 'dev' into feature/18-exported-env-vars 2020-12-09 19:04:42 +01:00
ff96ba23d7 Merge branch 'dev' into feature/17-automated_tests 2020-12-09 19:02:29 +01:00
3ae124ef68 Merge branch 'dev' into feature/13-runner_controllers 2020-12-09 19:02:06 +01:00
09f4998499 Merge branch 'dev' of https://git.odit.services/lfk/backend into dev 2020-12-09 19:01:39 +01:00
18ef8df3a9 Merge branch 'feature/12-jwt-creation' into dev
close #12
2020-12-09 19:01:17 +01:00
77b769446f Now throwing errors 2020-12-09 18:59:01 +01:00
00215a81a7 Merge branch 'dev' into feature/17-automated_tests 2020-12-09 18:54:06 +01:00
af1ad482d4 Now throwing errors to the next instance
ref #13
2020-12-09 18:53:36 +01:00
b4b52717fc Added more negative tests for the teams
ref #17
2020-12-09 18:47:15 +01:00
02236caa41 send empty array for user permissions if null
ref #12
2020-12-09 18:46:09 +01:00
2d603a1467 resolve groups + permissions
ref #12
2020-12-09 18:45:39 +01:00
862834c877 Added first team creation tests 2020-12-09 18:42:08 +01:00
76065538c9 Renamed b/c runner teams also need dedicated tests
ref #17
2020-12-09 18:14:29 +01:00
99209981d9 Merge branch 'dev' into feature/17-automated_tests 2020-12-09 18:13:12 +01:00
204e2352a9 Fix for getting one
ref #13
2020-12-09 18:11:23 +01:00
13f96e3190 Added delete test
ref #17
2020-12-09 18:08:45 +01:00
4e3b038dec Added bad test to the put 2020-12-09 17:56:37 +01:00
42d3f9cb98 Merge branch 'dev' into feature/17-automated_tests 2020-12-09 17:52:22 +01:00
0a0050368f Added put tests for runner orgs 2020-12-09 17:52:04 +01:00
e4cb8eba1d Removed relations resolution that broke the update 2020-12-09 17:48:24 +01:00
6da7c23c04 Renamed to better fit the content 2020-12-09 16:28:18 +01:00
db5feb00cc Added more basic tests for the runner orgs
ref #17
2020-12-09 16:27:01 +01:00
381ce9c828 Merge branch 'dev' into feature/17-automated_tests 2020-12-09 16:11:46 +01:00
7bb7da4eed Merge branch 'dev' into feature/13-runner_controllers 2020-12-09 16:11:27 +01:00
4df63a8cc0 Fixxed missing plural
ref #13
2020-12-09 16:10:56 +01:00
34fa94ea4f First tests for orgs
ref #17
2020-12-09 16:10:17 +01:00
fcfc10f7d1 phone countrycode validation in env vars
ref #18 #16
2020-12-06 11:21:10 +01:00
9f7d004c3b Merge branch 'dev' of https://git.odit.services/lfk/backend into dev 2020-12-06 10:48:51 +01:00
39cefbc593 ⚙ use new config loader
ref #18 ,ref #17
2020-12-06 10:48:25 +01:00
2cdc91ec83 Merge branch 'feature/18-exported-env-vars' into feature/17-automated_tests 2020-12-06 10:45:15 +01:00
99d8a0360f 🚚 basic move to config.ts
ref #18
2020-12-06 10:29:56 +01:00
1748fd4034 Merge branch 'feature/17-automated_tests' of https://git.odit.services/lfk/backend into feature/17-automated_tests 2020-12-05 20:45:38 +01:00
34567f24c3 test:watch script 2020-12-05 20:45:22 +01:00
def7ca3eb2 🧪tracks.spec.ts - move to baseurl
ref #17
2020-12-05 20:45:06 +01:00
4dd0217c93 Merge branch 'feature/17-automated_tests' of git.odit.services:lfk/backend into feature/17-automated_tests 2020-12-05 20:33:41 +01:00
a3e8973004 Merge branch 'dev' into feature/17-automated_tests 2020-12-05 20:33:31 +01:00
29acabfca3 🧪tracks.spec.ts - adding + getting + updating tracks
ref #17
2020-12-05 20:32:38 +01:00
4ff6f8c540 ⚙ nodemon config - ignore tests
ref #17
2020-12-05 20:32:15 +01:00
a671bf8bcb 🚧 tracks.spec.ts - sample track adding + getting
ref #17
2020-12-05 20:19:41 +01:00
15e3d04215 🚧tracks.spec.ts - check if track was added
ref #17
2020-12-05 20:17:42 +01:00
07e03ff04e basic track testing
ref #17
2020-12-05 20:11:52 +01:00
5103e8a6e5 Updated folders in the readme 2020-12-05 20:01:06 +01:00
ad6c9e7211 Removed garbage file 2020-12-05 19:15:56 +01:00
1fb09e577c Cleaned up up the middlewares
ref #11
2020-12-05 19:14:04 +01:00
f58a715c45 Cleaned up the loaders
ref #11
2020-12-05 19:09:08 +01:00
a3a809bb40 Merge branch 'feature/11-new_classes' of git.odit.services:lfk/backend into feature/11-new_classes 2020-12-05 19:01:51 +01:00
33b3bcb8c2 Error cleanup
#11 #13 #14
2020-12-05 19:01:48 +01:00
1ae466a6f4 Error cleanup
#11 #13 #14
2020-12-05 19:01:30 +01:00
431fd608a6 sample json validation
ref #17
2020-12-05 18:52:36 +01:00
21ad622c10 Removed console logs
ref #11
2020-12-05 18:49:59 +01:00
61e7ae4f86 Cleanup: Renamed Responses to represent their response nature
ref #11 #13 #14
2020-12-05 18:49:13 +01:00
8ae5cea631 basic jest + typescript support
ref #17
2020-12-05 18:49:09 +01:00
0e924449d6 Cleanup: Renamed the creation folder to the more fitting "actions"
ref #11 #13
2020-12-05 18:45:47 +01:00
5c259484ee remove sampletoken generation 2020-12-05 18:02:57 +01:00
740d7f10f5 remove routes/v1/test 2020-12-05 18:02:49 +01:00
993096741d Merge branch 'dev' of https://git.odit.services/lfk/backend into dev 2020-12-05 18:00:48 +01:00
8607af62b5 Merge branch 'feature/12-jwt-creation' of https://git.odit.services/lfk/backend into feature/12-jwt-creation 2020-12-05 17:59:50 +01:00
76e19ca28d implement proper jwt checking in authchecker
ref #12
2020-12-05 17:59:43 +01:00
3ac150331a Merge branch 'feature/12-jwt-creation' of git.odit.services:lfk/backend into feature/12-jwt-creation 2020-12-05 17:47:35 +01:00
5a4a6cdcef Added basic openapi security scheme for the bearer auth header
ref #12
2020-12-05 17:47:32 +01:00
e5b605cc55 🧹 cleanups 2020-12-05 17:25:57 +01:00
7e4ce00c30 added await (async stuff und so)
ref #12
2020-12-05 17:20:39 +01:00
13d568ba3f implemented refreshcount increase
ref #12
2020-12-05 17:20:18 +01:00
65b2399eaa Reverted to id based relation setter
ref #13
2020-12-05 17:04:22 +01:00
4352910d54 More dynamic creation of objects
ref #13
2020-12-05 15:50:28 +01:00
8c229dba82 add response schemas to AuthController 2020-12-05 13:40:59 +01:00
675717f8ca 🚧 starting work on LogoutHandler
ref #12
2020-12-05 13:38:59 +01:00
0d21497c2f 🚧 AuthController - add proper response schemas 2020-12-05 13:31:46 +01:00
e5f65d0b80 note on refreshtokencount checking
ref #12
2020-12-05 13:30:22 +01:00
51addd4a31 🚧 RefreshAuth - refresh tokens now working
ref #12
2020-12-05 13:12:47 +01:00
126799dab9 basic RefreshAuth checking
ref #12
2020-12-05 13:07:33 +01:00
82f31185a1 🚧 CreateAuth - use proper refreshTokenCount
ref #12
2020-12-05 13:07:18 +01:00
c0c95056bf better errors
ref #12
2020-12-05 13:06:58 +01:00
093f6f5f78 🚧 UserNotFoundOrRefreshTokenCountInvalidError
ref #12
2020-12-05 12:59:02 +01:00
2f902755c4 🚧 starting work on RefreshAuth
ref #12
2020-12-05 12:55:38 +01:00
975d30e411 Smoothed out the participant creation process regarting addresses
ref #13
2020-12-05 12:39:11 +01:00
a0fe8c0017 🚧 CreateAuth - basic jwt creation with user details
ref #12
2020-12-05 12:34:07 +01:00
c33097f773 first accesstoken generation
ref #12
2020-12-05 12:28:59 +01:00
28c2b862f0 🚧 AuthController with multiple endpoints
ref #12
2020-12-05 12:28:43 +01:00
d23ed002b2 🚧 JwtNotProvidedError
ref #12
2020-12-05 12:28:06 +01:00
8870b26ce6 Deletes now work based on EntityFromParam
ref #14
2020-12-05 12:24:38 +01:00
0e3cf07b91 TrackController now also deletes based on a entityfromparam
ref #13
2020-12-05 12:21:47 +01:00
179add80f4 Now throwing errors even faster
ref #13
2020-12-05 12:18:24 +01:00
45675b0699 All things deletion for runner* now are clean af and cascadeing
ref #13
2020-12-05 12:15:51 +01:00
9c63a34fe1 Little bugfix
ref #13
2020-12-05 11:36:33 +01:00
1850dd542d 🧹 clean up CreateAuth
ref #12
2020-12-05 11:22:59 +01:00
2a1b65f424 🚧AuthController - add all Error response schemas to post
ref #12
2020-12-05 11:22:45 +01:00
bd0c7ce042 🚧 CreateAuth - credential validation
ref #12
2020-12-05 11:18:12 +01:00
d46ad59546 🚧 CreateAuth now returns a sample jwt
ref #12
2020-12-05 11:14:26 +01:00
b8bc39d691 🚧 User - mark columns as unique
ref #11 #12
2020-12-05 11:14:06 +01:00
52dfe83354 Merge branch 'dev' into feature/12-jwt-creation 2020-12-05 11:07:01 +01:00
aca13f7308 Fixed bugs concerning posts
ref #13
2020-12-05 10:59:15 +01:00
ef54dd5e9c Merge branch 'dev' into feature/13-runner_controllers 2020-12-05 10:44:27 +01:00
a1105f06ab Cleaned up a load of relations and optional stuff
ref #11
2020-12-05 10:43:28 +01:00
109e145a19 Cleaned up the createUserGroup a little bit
ref #11 #14
2020-12-05 10:31:24 +01:00
a42595bd15 Cleaned up the createUser a little bit
ref #11 #14
2020-12-05 10:23:53 +01:00
dadaacfaae first part of the user class cleanuo
ref #11 #14
2020-12-05 10:16:47 +01:00
74ee77f814 Cleaned up some relations for users
ref #14
2020-12-05 09:48:01 +01:00
6ae0c1b955 first jwt generation
ref #12
2020-12-04 23:03:24 +01:00
6244c969af integrate UserNotFoundError
ref #12
2020-12-04 23:03:10 +01:00
d803704eee UserNotFoundError
ref #12
2020-12-04 23:02:23 +01:00
5d7d80d2e7 A step towards inheritance for the create* objects relating to runner groups
ref #13
2020-12-04 22:58:34 +01:00
a5b1804e19 Merge branch 'dev' into feature/12-jwt-creation 2020-12-04 22:51:57 +01:00
a7854fbe81 CreateUser - remove uuid from params
ref #11
2020-12-04 22:51:44 +01:00
3e38bc5950 Merge branch 'dev' into feature/12-jwt-creation 2020-12-04 22:48:57 +01:00
7f3358d284 🚧 User entity - add @Column
ref #11
2020-12-04 22:48:42 +01:00
92cd58e641 Merge branch 'dev' into feature/12-jwt-creation 2020-12-04 22:45:54 +01:00
6cb01090d0 working on AuthController + CreateAuth
ref #12
2020-12-04 22:43:41 +01:00
48484f04c9 Merge branch 'dev' into feature/13-runner_controllers 2020-12-04 22:43:29 +01:00
56202ec309 Create models now feature the createparticipant abstract
ref #13
2020-12-04 22:40:14 +01:00
c4b7ece974 class-validator on Auth model
ref #12
2020-12-04 22:34:03 +01:00
c5c3058f3d clean up jwtauth
ref #12
2020-12-04 22:28:17 +01:00
a7afcf4cd1 CreateAuth model
ref #12
2020-12-04 22:19:55 +01:00
f251b7acdb authchecker - use new custom Errors
ref #12
2020-12-04 22:18:54 +01:00
b0a24c6a74 basic Auth model
ref #12
2020-12-04 22:18:40 +01:00
b9bbdee826 🚧 basic AuthErrors 🔒
ref #12
2020-12-04 22:17:03 +01:00
afef95e14e Fixed amount calculations 2020-12-04 22:07:30 +01:00
b480912bd8 Now with even more inheritance and fancy stuff: RunnerResponses now get their information from participant responses
ref #13
2020-12-04 22:00:48 +01:00
7b08489533 Now with working runner orga controller including responses
ref #13
2020-12-04 21:55:09 +01:00
1f3b312675 🚧 basic JWTAuth Middleware
ref #12
2020-12-04 21:39:55 +01:00
a437ada3b3 Runnerteams now with resolving relations and response types :O
ref #13
2020-12-04 21:38:28 +01:00
fe46e5d667 - close #14 2020-12-04 21:30:10 +01:00
c53e94d205 Part 1 of the relation fix 2020-12-04 21:18:44 +01:00
056413560e Now all runner endpoints return a response runner
ref #13
2020-12-04 19:40:00 +01:00
a7cf86eae4 🚧 CreateUser - add group as object instead of nested array 2020-12-04 19:32:17 +01:00
c30922e325 Still broken distance, we'll fix this together
ref #13
2020-12-04 19:31:20 +01:00
d4753a02d4 🐞 fixed UserGroupNotFoundError throwing
ref #14
2020-12-04 19:31:10 +01:00
451d0c92dd trying to fix UserGroupNotFoundError (false/not triggering)
ref #14
2020-12-04 19:02:07 +01:00
8beb658bcc New response model for runners
ref #13
2020-12-04 19:01:36 +01:00
a3b79ef21d Fix
ref #14
2020-12-04 18:36:46 +01:00
b101682e3c CreateUser
ref #14
2020-12-04 18:34:24 +01:00
3275b5fd80 🚧 UserGroups
ref #14
2020-12-04 18:34:14 +01:00
913033373b Switched to using a response model for tracks 2020-12-04 18:34:01 +01:00
65f995cb9f Removed console logging only used for dev
ref #13
2020-12-04 18:16:34 +01:00
795599fd38 Working(tm) implementation of group and team deletion
ref #13
2020-12-04 18:15:38 +01:00
5b7f3ae12f 🚧 CreateUser group search + adding
ref #14
2020-12-04 18:02:28 +01:00
d556e9ba19 🚧 UserController
ref #14
2020-12-04 17:56:09 +01:00
1efca47336 🚧 reference new Errors from CreateUser 2020-12-04 17:55:51 +01:00
091b455460 🚧 move to uuidV4 2020-12-04 17:53:49 +01:00
a0e6424d48 🚧 better/ more errors
ref #14
2020-12-04 17:53:28 +01:00
c4f02023b9 Shortened db call
ref #13
2020-12-04 17:51:27 +01:00
ca917b0577 Added basics for the runner team controller
ref #13
2020-12-04 17:50:10 +01:00
ce2c38e188 🔒argon2 password hashing w/ salt
ref #14
2020-12-04 17:25:15 +01:00
ae24c3394b 📏 fit to new structure 2020-12-04 17:10:00 +01:00
acd9a691f8 Merge branch 'dev' into feature/14-user-controllers
# Conflicts:
#	src/models/entities/User.ts
2020-12-04 17:07:34 +01:00
838cedfe6c Merge branch 'dev' into feature/13-runner_controllers 2020-12-04 17:06:59 +01:00
0c6528bdc5 Impementing more methods for the runner orgs 2020-12-04 17:06:37 +01:00
658009c401 Merge branch 'dev' of https://git.odit.services/lfk/backend into dev 2020-12-04 17:05:41 +01:00
5e0fcf1f4a 🐞 VSCode formatting broke code by removing all unused 2020-12-04 17:05:13 +01:00
f1629440fe 🚧 better uuid + starting hashing implementation
ref #14
2020-12-04 17:04:33 +01:00
b47fad2c3a Merge branch 'dev' into feature/14-user-controllers 2020-12-04 17:02:15 +01:00
330cbd5f57 Added comments and decorators for existing create models
ref #13
2020-12-03 20:49:55 +01:00
36b2e82f4e Merge branch 'dev' into feature/11-new_classes 2020-12-03 20:41:42 +01:00
92bafb0cf4 ⚙ vscode setting - import organize + fix 2020-12-03 20:40:05 +01:00
e8727ca922 Moved to a "cleaner" directory structure
ref #11
2020-12-03 20:38:47 +01:00
8292ec3a1e Merge branch 'dev' into feature/14-user-controllers 2020-12-03 20:33:39 +01:00
3a04bb54bd Merge branch 'dev' into feature/11-new_classes 2020-12-03 20:33:01 +01:00
32edc3c68f Merge branch 'dev' into feature/13-runner_controllers 2020-12-03 20:28:28 +01:00
a8956223c2 Emergency fix: Switched to table inheritances
ref #11 #13
2020-12-03 20:28:07 +01:00
e3133e0d5e Added missing import 2020-12-03 20:24:43 +01:00
5bbf522362 Fixed missing child declaration 2020-12-03 20:23:56 +01:00
32c4270dff Attention: Broken 2020-12-03 20:19:58 +01:00
ec2ff981b2 Now creating runner orgs again
ref #13
2020-12-03 19:25:02 +01:00
af75d6cfec Formatting 2020-12-03 19:22:32 +01:00
a35e6d0a9f Added basics for runnerorg controller
ref #13
2020-12-03 19:20:53 +01:00
a191d8ca2e Merge branch 'dev' into feature/14-user-controllers 2020-12-03 19:00:44 +01:00
0d5a2109d5 Merge branch 'dev' into feature/13-runner_controllers 2020-12-03 18:50:11 +01:00
1fe00c5b0e Merge branch 'dev' of https://git.odit.services/lfk/backend into dev 2020-12-03 18:49:32 +01:00
9051b7565c ⚙target: es2017 ▶ ES2020 2020-12-03 18:49:21 +01:00
ffc31506e3 ⚙tsconfig - no sourcemaps 2020-12-03 18:48:51 +01:00
8ef6f933a7 ⚙ tsconfig - includes + excludes 2020-12-03 18:48:35 +01:00
ee35da7342 Fixxed dockerfile 2020-12-03 18:48:24 +01:00
084691c294 Now returning the saved runner
ref #13
2020-12-03 18:46:53 +01:00
983fa41cba 🚧 CreateUserErrors model
ref #14
2020-12-03 18:33:30 +01:00
d2c826c7c9 🚧 CreateUser model
ref #14
2020-12-03 18:33:20 +01:00
34d4ebc7cb Merge branch 'feature/11-new_classes' into feature/14-user-controllers 2020-12-03 18:26:08 +01:00
8d1dd78194 🚧 User.ts - optional phone number 2020-12-03 18:25:52 +01:00
098699e09a 🐞 CreateRunner - optional orgId & teamId 2020-12-03 18:07:49 +01:00
9e3ee433d2 Moved Create Runner to it's own file 2020-12-03 18:03:43 +01:00
9395813f5a 🚧 Scan.ts - secondsSinceLastScan 2020-12-03 17:55:27 +01:00
6d81fc1309 Added Comments.
ref #11 #13
2020-12-03 17:46:32 +01:00
da4597fa62 Moded track controller related models to a new file 2020-12-03 17:43:24 +01:00
33d159dbcf 🚧 RunnerCard EAN 2020-12-03 17:26:54 +01:00
684e7c4ddb ⚙ settings - standard imports + quote formatting 2020-12-03 17:12:27 +01:00
a86465c554 Merge branch 'dev' into feature/13-runner_controllers 2020-12-02 19:46:05 +01:00
efd75823f9 Merge branch 'feature/11-new_classes' into dev 2020-12-02 19:45:54 +01:00
6464033a58 Merge branch 'feature/11-new_classes' of git.odit.services:lfk/backend into feature/11-new_classes
# Conflicts:
#	src/models/User.ts
2020-12-02 19:45:30 +01:00
4c80ab1516 Updated relationships to be nullable
ref #11 #13
2020-12-02 19:45:02 +01:00
3ade01def9 temp commit: added first part of create runner
ref #13
2020-12-02 19:41:47 +01:00
cb5d5e546d Added more runner errors
ref #13
2020-12-02 19:41:03 +01:00
1cf35f016b 🚧 Permissions 2020-12-02 19:34:43 +01:00
f50e7f0b3a 🚧 UserAction relation 2020-12-02 19:29:40 +01:00
52e9d3a908 Merge branch 'dev' into feature/13-runner_controllers 2020-12-02 19:14:58 +01:00
6932dd9e6e Merge branch 'feature/11-new_classes' into dev 2020-12-02 19:14:52 +01:00
aa565c6b34 Updated a bunch of optional collumns to be nullable
ref #11 #13
2020-12-02 19:14:45 +01:00
7bbf769bdd Added basic creation class 2020-12-02 19:05:58 +01:00
980ac64688 Added basic runner related errors 2020-12-02 18:50:49 +01:00
18fdd367ac Merge branch 'dev' into feature/13-runner_controllers 2020-12-02 18:48:53 +01:00
7d9e003a6d Merge pull request 'feature/11-new_classes' (#15) from feature/11-new_classes into dev
Reviewed-on: #15
2020-12-02 17:48:16 +00:00
701207e100 Created basic runner controller
ref #13
2020-12-02 18:46:40 +01:00
a78bbb1de5 🚧 User + Permissions 2020-12-02 18:46:36 +01:00
e4d5afbebe 🚧 Permission 2020-12-02 18:28:48 +01:00
63843cc4c9 Merge branch 'feature/11-new_classes' of https://git.odit.services/lfk/backend into feature/11-new_classes 2020-12-02 18:27:16 +01:00
1d57264922 🚧 Permissions 2020-12-02 18:27:06 +01:00
82ca8f48dc 🚧 UserAction 2020-12-02 18:27:00 +01:00
4a9fd57356 Fixed user<-> Group relationship 2020-12-02 18:20:53 +01:00
d47983a032 🚧 User class WIP 2020-12-02 18:11:23 +01:00
4ad8afd512 Merge branch 'feature/11-new_classes' of https://git.odit.services/lfk/backend into feature/11-new_classes 2020-12-02 18:07:36 +01:00
48e28e7b7a User + UserGroup 2020-12-02 18:07:33 +01:00
932e782a14 Added defaults back in 2020-12-02 18:05:18 +01:00
ac0ce799f9 Fixed the cirvular import BS
ref #11
2020-12-02 17:40:03 +01:00
5bf978d32d Turned the abstracts into entities
ref #11
2020-12-02 16:07:18 +01:00
dd5f4488be Cleaned up relations
ref #11
2020-12-02 16:00:09 +01:00
d0a1ea3292 Renamed getter
ref #11
2020-12-02 15:49:19 +01:00
84dd1fe4a5 Added missing getter 2020-12-02 15:46:53 +01:00
abf7aaeda3 Fixed import
ref #11
2020-12-02 15:46:43 +01:00
c82cc9a670 Moved attribute to super
ref #11
2020-12-02 15:44:56 +01:00
c1242b2a2a Added TrackScan relationships
ref #11
2020-12-02 15:40:25 +01:00
4d593eb840 Removed relation that was already implemented in the super
ref #11
2020-12-02 15:36:11 +01:00
f32291d714 Added scan station relationship
ref #11
2020-12-02 15:34:04 +01:00
8e2eac9dc0 Added relations for Scans
ref #11
2020-12-02 15:32:11 +01:00
0d9d72c223 Added relations for RunnerTeams
ref #11
2020-12-01 19:51:16 +01:00
7ac46a7cc7 Added relations to RunnerOrganisation 2020-12-01 19:48:20 +01:00
f28b08ed65 Added relations to RunnerGroup
ref #11
2020-12-01 19:44:51 +01:00
029e4beaf5 Added relations for runner cards
ref #11
2020-12-01 19:27:36 +01:00
a6222a8025 Added relations for runners
ref #11
2020-12-01 19:20:27 +01:00
4075276130 Added relations for participants
ref #11
2020-12-01 19:17:53 +01:00
2b693917b0 Added relationships for donation
ref #11
2020-12-01 19:13:56 +01:00
1c43442300 Relations for distanceDonation
ref #11
2020-12-01 19:10:52 +01:00
dca9aef258 Other classed are now using the new Address class rather than the old location placeholder
ref #11
2020-12-01 19:06:56 +01:00
2bd0cbadbe Added the address class
ref #11
2020-12-01 19:03:41 +01:00
8b2d6840a8 Added the track scan class
ref #11
2020-12-01 18:57:44 +01:00
df3715d8d6 Changed the distance to be an abstract
ref #11
2020-12-01 18:57:34 +01:00
084e2d9930 Renamed property, so it fits with the rest of the nameing
ref #11
2020-12-01 18:50:06 +01:00
79eecbb329 fixxed missing imports and commented out a non-implemented function call
ref #11
2020-12-01 18:48:28 +01:00
f7beebce3f Added scanstation class
ref #11
2020-12-01 18:39:33 +01:00
fbbb5df64f Added runnerCard class
ref #11
2020-12-01 18:16:17 +01:00
96d70d5048 Added group contact class
ref #11
2020-12-01 18:07:39 +01:00
ac40527fa2 Added the runnerteam class
ref #11
2020-12-01 18:01:32 +01:00
66f7a7928c Added the runner org class
ref #11
2020-12-01 17:58:23 +01:00
deae0bb84b Added finxed donations
ref #11
2020-12-01 17:53:43 +01:00
6c32a9ebe9 Added distance Donation 2020-12-01 17:51:30 +01:00
a8d1ec6f9b Marked amount as abstract
ref #11
2020-12-01 17:50:43 +01:00
daea0568a8 Amount no longer is a column by default 2020-12-01 17:45:59 +01:00
b632c09924 Added donor
ref #11
2020-12-01 17:41:56 +01:00
7ce8c375a2 Fixed copy-paste slip up
ref #11
2020-12-01 17:39:03 +01:00
5a04e61d1c Added the runner class
ref #11
2020-12-01 17:38:28 +01:00
748fff5c32 Cleaned up imports and descriptions
ref #11
2020-12-01 17:32:21 +01:00
57ba0c3051 Added the donation abstract/interface 2020-12-01 17:31:05 +01:00
72f80859a9 Added todo's for relationships 2020-12-01 17:27:48 +01:00
f999c416c4 Added Runnergroup abstract class
ref #11
2020-12-01 17:27:18 +01:00
f8e1bf715b Changed nameing scheme for the abstract classes since we're not useing interfaces
ref #11
2020-12-01 17:21:44 +01:00
f350007ae5 Added participant abstract class
ref #11
2020-12-01 17:20:43 +01:00
a2cf8d1f2c Switched from implementing the "interfaces" as interface to abstract classes
ref #11
This was done to take advantage of typeorm and class validator
2020-12-01 17:16:50 +01:00
abb7f7f894 Added Basic Scan interface
ref #11
2020-12-01 17:10:17 +01:00
96a99c4e3b Merge pull request 'Added our branch structure to the readme' (#10) from bugfix/readmeupdate into main
Reviewed-on: #10
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2020-11-27 21:46:45 +00:00
5b4224b8f5 Added our branch structure to the readme 2020-11-27 21:45:29 +00:00
f0a7cbbcae Adjusted the comments for tsdoc
ref #8 #3
2020-11-27 22:19:07 +01:00
15552eff54 Merge branch 'main' of https://git.odit.services/lfk/backend into main 2020-11-27 21:41:09 +01:00
6e0447165b tsdoc generation
ref #7 , close #8
2020-11-27 21:40:42 +01:00
26499658a4 Extended error message 2020-11-27 21:40:00 +01:00
624ea6ba33 Merge branch 'main' of git.odit.services:lfk/backend into main
# Conflicts:
#	src/controllers/TrackController.ts
2020-11-27 21:38:47 +01:00
01542ae6a8 Added custom errors
ref #4 #5
2020-11-27 21:35:28 +01:00
d85c126c27 implementation details
ref #6
2020-11-27 21:24:55 +01:00
e29c0cb7a1 Merge branch 'main' into feature/authed-routes
# Conflicts:
#	src/app.ts
#	src/controllers/TrackController.ts
2020-11-27 21:19:58 +01:00
37baa4ea45 default to only jwt checking (empty @Authorized() )
ref #6
2020-11-27 21:18:42 +01:00
5f4aed2f02 fixed auth parsing
ref #6
2020-11-27 21:16:15 +01:00
cb5f5b9ecb debugging
ref #6
2020-11-27 20:15:48 +01:00
c15b650181 sample in TrackController
ref #6
2020-11-27 19:55:49 +01:00
e29d59ac02 move to module
ref #6 #4
2020-11-27 19:55:35 +01:00
d5c6c9238f sample implementation of authorizationChecker 2020-11-27 19:45:44 +01:00
215 changed files with 30559 additions and 298 deletions

146
.drone.yml Normal file
View File

@@ -0,0 +1,146 @@
---
kind: pipeline
name: tests:node_latest
clone:
disable: true
steps:
- name: checkout pr
image: alpine/git
commands:
- git clone $DRONE_REMOTE_URL .
- git checkout $DRONE_SOURCE_BRANCH
- mv .env.ci .env
- name: run tests
image: node:latest
commands:
- yarn
- yarn test:ci
trigger:
event:
- pull_request
---
kind: pipeline
type: docker
name: build:dev
clone:
disable: true
steps:
- name: clone
image: alpine/git
commands:
- git clone $DRONE_REMOTE_URL .
- git checkout dev
- name: build dev
image: plugins/docker
depends_on: [clone]
settings:
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
repo: registry.odit.services/lfk/backend
tags:
- dev
registry: registry.odit.services
- name: run changelog export
depends_on: ["clone"]
image: node:latest
commands:
- npx auto-changelog --commit-limit false -p -u --hide-credit
- name: push new changelog to repo
depends_on: ["run changelog export"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: true
commit_message: 🧾New changelog file version [CI SKIP] [skip ci]
author_email: bot@odit.services
remote: git@git.odit.services:lfk/backend.git
ssh_key:
from_secret: GITLAB_SSHKEY
- name: run full license export
depends_on: ["clone"]
image: node:14.15.1-alpine3.12
commands:
- yarn
- yarn licenses:export
- name: push new licenses file to repo
depends_on: ["run full license export"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: true
commit_message: 📖New license file version [CI SKIP] [skip ci]
author_email: bot@odit.services
remote: git@git.odit.services:lfk/backend.git
skip_verify: true
ssh_key:
from_secret: GITLAB_SSHKEY
trigger:
branch:
- dev
event:
- push
---
kind: pipeline
type: docker
name: build:latest
steps:
- name: build latest
image: plugins/docker
depends_on: [clone]
settings:
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
repo: registry.odit.services/lfk/backend
tags:
- latest
registry: registry.odit.services
trigger:
branch:
- main
event:
- push
---
kind: pipeline
type: docker
name: build:tags
steps:
- name: build $DRONE_TAG
image: plugins/docker
depends_on: [clone]
settings:
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
repo: registry.odit.services/lfk/backend
tags:
- '${DRONE_TAG}'
registry: registry.odit.services
- name: trigger node lib build
image: idcooldi/drone-webhook
settings:
urls: https://ci.odit.services/api/repos/lfk/lfk-client-node/builds?SOURCE_TAG=${DRONE_TAG}
bearer:
from_secret: BOT_DRONE_KEY
- name: trigger js lib build
image: idcooldi/drone-webhook
settings:
urls: https://ci.odit.services/api/repos/lfk/lfk-client-js/builds?SOURCE_TAG=${DRONE_TAG}
bearer:
from_secret: BOT_DRONE_KEY
trigger:
event:
- tag

9
.env.ci Normal file
View File

@@ -0,0 +1,9 @@
APP_PORT=4010
DB_TYPE=sqlite
DB_HOST=unused
DB_PORT=unused
DB_USER=unused
DB_PASSWORD=bla
DB_NAME=./test.sqlite
NODE_ENV=dev
POSTALCODE_COUNTRYCODE=null

View File

@@ -5,4 +5,5 @@ DB_PORT=bla
DB_USER=bla
DB_PASSWORD=bla
DB_NAME=bla
NODE_ENV=production
NODE_ENV=production
POSTALCODE_COUNTRYCODE=null

7
.gitignore vendored
View File

@@ -130,4 +130,9 @@ yarn.lock
package-lock.json
build
*.sqlite
*.sqlite
*.sqlite-jurnal
/docs
lib
/oss-attribution
*.tmp

12
.vscode/settings.json vendored
View File

@@ -7,6 +7,14 @@
},
"prettier.enable": false,
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
"editor.defaultFormatter": "vscode.typescript-language-features",
"editor.codeActionsOnSave": {
"source.organizeImports": true,
// "source.fixAll": true
}
},
"javascript.preferences.quoteStyle": "single",
"javascript.preferences.importModuleSpecifierEnding": "minimal",
"typescript.preferences.importModuleSpecifierEnding": "minimal",
"typescript.preferences.includePackageJsonAutoImports": "on"
}

901
CHANGELOG.md Normal file
View File

@@ -0,0 +1,901 @@
### Changelog
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.0.12](https://git.odit.services/lfk/backend/compare/v0.0.11...v0.0.12)
- Merge pull request 'Fixed backend version related bugs' (#92) from bugfix/91-backend_version into dev [`#91`](https://git.odit.services/lfk/backend/issues/91)
- Merge pull request 'Bugfix: resolved missing relation' (#89) from bugfix/88-user_update into dev [`#88`](https://git.odit.services/lfk/backend/issues/88)
- 🧾New changelog file version [CI SKIP] [skip ci] [`8cb67a8`](https://git.odit.services/lfk/backend/commit/8cb67a8d202527dcaa26d5f37b3fd03d90a897ca)
- 📖New license file version [CI SKIP] [skip ci] [`09b16c9`](https://git.odit.services/lfk/backend/commit/09b16c980b01db3233db7cd3161e58aa33498993)
- 🧾New changelog file version [CI SKIP] [`2947c41`](https://git.odit.services/lfk/backend/commit/2947c41a7241417d51f278d2e4f6195a3f3bc30d)
- Switched emails to being mandetory for users [`9feeb30`](https://git.odit.services/lfk/backend/commit/9feeb302e89049843564015c2dc2820ac2886e2d)
- Added a new endpoint that returns a users permissions as objects sorted into two arrays [`b01e1eb`](https://git.odit.services/lfk/backend/commit/b01e1eb8a1a36fc8e04e009cd6024495a70a10dd)
- Added new pipeline to automagicly generate changelogs on pr to main [`6345666`](https://git.odit.services/lfk/backend/commit/6345666ae67846463f1dadeb13c0f5c46a0c74ae)
- Updated some openapi descriptions [`0724932`](https://git.odit.services/lfk/backend/commit/0724932152278a1dce94f17835e00fd1bbd808f9)
- Updated step order [`c108fa5`](https://git.odit.services/lfk/backend/commit/c108fa509fc26118b5f805b2c2392f52afd4eacd)
- Updated step order [`1e5e980`](https://git.odit.services/lfk/backend/commit/1e5e9801be98242030733af7ea8030c3ad869a1f)
- Added '@' as a illegal character for usernames [`37fc167`](https://git.odit.services/lfk/backend/commit/37fc167002caa297f865832ba9237a33fb7d9219)
- Reenabled dev build [`ef53035`](https://git.odit.services/lfk/backend/commit/ef53035f70a09aa24bf57696ad0a1b5ecca1b065)
- Moved changelog generation to dev build for now [`aaaa15a`](https://git.odit.services/lfk/backend/commit/aaaa15a0efa3c7d72a0cee5571d5b5653a101713)
- disabled dev build temporary [`472e402`](https://git.odit.services/lfk/backend/commit/472e4025215c04303eecc276b413d28ba2cbb371)
- First part of resolving user inherited permissions [`cd7b15a`](https://git.odit.services/lfk/backend/commit/cd7b15aadfe66353033e976393fc143368ba0ba8)
- Disabled auto clone [`290bb29`](https://git.odit.services/lfk/backend/commit/290bb29e64ac185c17040770b3cffdc970c8a766)
- Updated the release machanics [`46df8b0`](https://git.odit.services/lfk/backend/commit/46df8b05286a9a7962904044657f05df65e6ef65)
- Added secondary full clone for tags [`d0769a5`](https://git.odit.services/lfk/backend/commit/d0769a5e37e3c778d2ca1bf91957a621065bd1f3)
- Disabled custom clone [`b86263d`](https://git.odit.services/lfk/backend/commit/b86263d972dfbe245f27e71d68bcec30a8b79cc5)
- 🚀Bumped version to v0.0.12 [`bd091d5`](https://git.odit.services/lfk/backend/commit/bd091d5cb9b8a95c2e52327cab7a8480bf2ddffc)
- Fixed spellings [`4c26fc8`](https://git.odit.services/lfk/backend/commit/4c26fc808e13a2d91c2a69284bc9f5391ca66273)
- Revert "🚀Bumped version to v0.0.12." [`525b11b`](https://git.odit.services/lfk/backend/commit/525b11b3465af530807857ec088a79808896831f)
- 🚀Bumped version to v0.0.12. [`86679b4`](https://git.odit.services/lfk/backend/commit/86679b498b7cf45aab6a5c36847735c6a79b1984)
- Added new ci skipping flags [`b495cad`](https://git.odit.services/lfk/backend/commit/b495cadae93789b66e3fcfb46e339c80be703ca4)
- Disabled custom clone [`f278320`](https://git.odit.services/lfk/backend/commit/f278320b936c992c9cf0f1226fc663650c451f89)
- 🧾New changelog file version [CI SKIP] [skip ci] [`de65b1c`](https://git.odit.services/lfk/backend/commit/de65b1c6994bcd03eaf3597b64a1f05272c0d986)
- 🧾New changelog file version [CI SKIP] [`47995b7`](https://git.odit.services/lfk/backend/commit/47995b77f7eebc288895b8b143acc77718ff7030)
- 🧾New changelog file version [CI SKIP] [`bc24ec5`](https://git.odit.services/lfk/backend/commit/bc24ec527203ab84302480e5c1130691bc32d44d)
- Disabled verification skip [`290afc3`](https://git.odit.services/lfk/backend/commit/290afc3f8f2b344ace15e5318a0c409c3031f3c3)
- tmp: skip verification [`2b72552`](https://git.odit.services/lfk/backend/commit/2b72552b1f189aaf10a886f497e8698e516d3ec7)
- tmp: skip verification [`df69418`](https://git.odit.services/lfk/backend/commit/df694188551184499b5c3d45eb9e4855b71b6c76)
- Merge pull request 'New user features feature/93-user_endpoints' (#95) from feature/93-user_endpoints into dev [`7b5ebab`](https://git.odit.services/lfk/backend/commit/7b5ebab453f5ad6f059e13c3434bda0134c0f665)
- Merge pull request 'Donation API Endpoint feature/66-donation_api' (#94) from feature/66-donation_api into dev [`ab3af54`](https://git.odit.services/lfk/backend/commit/ab3af54e154e3a91f05ff0b50bc545b083c014be)
- Added donation add invalid tests [`4a0f750`](https://git.odit.services/lfk/backend/commit/4a0f75044f728fadd274b4ffaee7ebb01652176a)
- Added donation add validtests [`e3e570e`](https://git.odit.services/lfk/backend/commit/e3e570e664c5a36d944fca3fb1214a18e474a254)
- Added donation update validtests [`cd5e4bb`](https://git.odit.services/lfk/backend/commit/cd5e4bbd6060debf37e6b64b6e42a95afedde881)
- Added donation update invalid tests [`a513bf1`](https://git.odit.services/lfk/backend/commit/a513bf13ca8d04952ba0f72905fd5306c9fd9c87)
- Added barebones donation controller [`5581c03`](https://git.odit.services/lfk/backend/commit/5581c03f770782d69fe17861e8e23bba942956bf)
- Implemented the donation creation action models [`2e760ff`](https://git.odit.services/lfk/backend/commit/2e760ff46149a25183172a8793275c6c76d39c75)
- Added donation delete tests [`71537b2`](https://git.odit.services/lfk/backend/commit/71537b283fed68a311c355718038dad702574db7)
- Added cascading donor deletion tests [`4375ca9`](https://git.odit.services/lfk/backend/commit/4375ca92d3a2aec3b7243049cd66ac1f3248b55e)
- Implemented fixed donation updateing [`2820f15`](https://git.odit.services/lfk/backend/commit/2820f151e873f342a03b656385ca08d7ea8bc0a5)
- Implemented fixed donation updateing [`9517df5`](https://git.odit.services/lfk/backend/commit/9517df50826aff1a1cb03e611b990de5829e2132)
- Added donation get tests [`63506da`](https://git.odit.services/lfk/backend/commit/63506dac1c86e4bf4cfae9d4b94d98ac3856bbaa)
- Added cascading runner deletion tests [`b729a7c`](https://git.odit.services/lfk/backend/commit/b729a7ceadf25787066ddc4d9cb5f08d140c4cd8)
- Implemented donation getting [`0df26cb`](https://git.odit.services/lfk/backend/commit/0df26cbd54bf914166bcb9ac1b03dee0c5dba07d)
- Implemented distance donation updateing [`f7370bc`](https://git.odit.services/lfk/backend/commit/f7370bc8025f9a29b4c046ec1dd28b128398dab9)
- Implmented cascading donation deletion for runners and donors [`e716fae`](https://git.odit.services/lfk/backend/commit/e716fae1c5eec625e6d050ac8893dfbe2ff1d820)
- Added the basics for distance donation updateing [`72c3fc7`](https://git.odit.services/lfk/backend/commit/72c3fc78b3f7a960496fd7737c5aac8e9880db45)
- Implemented the distance donation response [`55f72c3`](https://git.odit.services/lfk/backend/commit/55f72c35a62ec827866b29e2d2cde371734b2e0e)
- Implemented the donation response [`6c53701`](https://git.odit.services/lfk/backend/commit/6c53701a59a0f9559d3668ead3970b7eacefe2ec)
- Implemented a response donation interface [`02bb634`](https://git.odit.services/lfk/backend/commit/02bb6342575de23074c4117fbc93c3fc26ecd717)
- Added donor donation amount to the donor response [`bba35d1`](https://git.odit.services/lfk/backend/commit/bba35d189eb0a2dc082c3e5553b98e29f7e12075)
- Implemented donation deletion [`57f62a6`](https://git.odit.services/lfk/backend/commit/57f62a608764914c5a213f0c2aebde0d67df70e0)
- Implemented fixed donation creation [`97ecc83`](https://git.odit.services/lfk/backend/commit/97ecc83fe47f35638313d4cb424ccb554d8d47d4)
- Added donation errors [`5f1ab4a`](https://git.odit.services/lfk/backend/commit/5f1ab4a2f32ca2297fcf952171e6c106c2ae3a39)
- Updated some trone pipeline names and messages [`67b3101`](https://git.odit.services/lfk/backend/commit/67b3101fd11537a53ac91fe252f1d66cb2f66921)
- Implemented distance donation creation [`8ee2bdf`](https://git.odit.services/lfk/backend/commit/8ee2bdf488f3aa77bc3c68956ff5ba906b743323)
- Added the basics for fixed donation updateing [`bbaee7c`](https://git.odit.services/lfk/backend/commit/bbaee7cd4d0cb68545a405899e7c2ff93c39bac4)
- Introduces a very basic version getting endpoint [`a2f4fd5`](https://git.odit.services/lfk/backend/commit/a2f4fd5d9b4a683d5eeb5133009e14227f8ee54c)
- Fixed typos [`badff85`](https://git.odit.services/lfk/backend/commit/badff85e287449f8b19d336b245427f83793a191)
- Fixed the version getting process [`295a152`](https://git.odit.services/lfk/backend/commit/295a1524d879c04a17fbb5dab8398ac08424197f)
- Bugfix: resolved missing relation [`7b08784`](https://git.odit.services/lfk/backend/commit/7b087840ec798801ff74ba37cdb62729fb8b53da)
- Added donation permission target [`e1ff8c0`](https://git.odit.services/lfk/backend/commit/e1ff8c03e15c6833e71d1b82ea25b9566ebef48c)
- Fixed typo [`56cedf0`](https://git.odit.services/lfk/backend/commit/56cedf0144e933b34038089e840860dfb6375129)
#### [v0.0.11](https://git.odit.services/lfk/backend/compare/v0.0.10...v0.0.11)
> 10 January 2021
- Merge pull request 'Alpha Release 0.0.11' (#87) from dev into main [`b3ce56c`](https://git.odit.services/lfk/backend/commit/b3ce56c6053efb828d30c640e4ed4ac113392131)
- Version bump [`28cefa7`](https://git.odit.services/lfk/backend/commit/28cefa792cb24d5a07314b58454145a61a64b8d4)
- Merge pull request 'General cleanup and optimisation feature/76-cleanup' (#86) from feature/76-cleanup into dev [`0803abc`](https://git.odit.services/lfk/backend/commit/0803abc1686d15e6c466b4fc9488fc6facdad05f)
- Intruduced a new folder structure for action models [`3bc172e`](https://git.odit.services/lfk/backend/commit/3bc172e7e0633a662811787f66bf30fbcf533868)
- Updated imports [`a00231d`](https://git.odit.services/lfk/backend/commit/a00231dd3ca028c4e36a1825ccb6ee589bddf060)
- added trackscan update tests [`7e95103`](https://git.odit.services/lfk/backend/commit/7e95103a2d68e9f55a6550290d36b6e62add973f)
- added trackscan add tests [`0c86e5d`](https://git.odit.services/lfk/backend/commit/0c86e5dae173c04422cf7254c72da961eca96e35)
- Added card update tests [`35ea315`](https://git.odit.services/lfk/backend/commit/35ea3154d132d095fc29d1d302964d680d082b4e)
- added card add tests [`8463bee`](https://git.odit.services/lfk/backend/commit/8463bee25312b4ddf5badb2af26716c2bcf9d9dc)
- Unified the openapi generation [`1721594`](https://git.odit.services/lfk/backend/commit/172159414b1d4964ee862ad1edc66a7c4c94cccb)
- Implemented trackscan updateing [`638898f`](https://git.odit.services/lfk/backend/commit/638898fa28bbb686c920ff5603e9ef6b68af3d83)
- added trackscan get tests [`f1dee10`](https://git.odit.services/lfk/backend/commit/f1dee1061dc8dc9b76d3100b7c66d7c12434fd8f)
- added trackscan delete tests [`efe1a1f`](https://git.odit.services/lfk/backend/commit/efe1a1f543aa2eebd2b2a3c2be89ce1a08c6bcd4)
- Added card creation [`36ecae7`](https://git.odit.services/lfk/backend/commit/36ecae7e6e1eda637bafbc260d3dfa5815a472ff)
- Added a barebones runnercard controller [`52eb7b1`](https://git.odit.services/lfk/backend/commit/52eb7b1afe87c4e96d6975a983dcc69a2989de23)
- Implemented runner updateing [`32fda46`](https://git.odit.services/lfk/backend/commit/32fda46f0a7e4b63b1119754e9c0ba5327511ceb)
- Added runner card get endpoints [`4faeddc`](https://git.odit.services/lfk/backend/commit/4faeddc3f3086727432bfbf9bebf4f38d73b74aa)
- Added card deletion + errors [`a5bfe4e`](https://git.odit.services/lfk/backend/commit/a5bfe4e3d5072718f29e2d4ca324d63bd7393291)
- Moded group updateing to a updateusergroup action model [`be40507`](https://git.odit.services/lfk/backend/commit/be4050768e45fb7893d9bf1957095baed646ae92)
- Renamed the to&gt;Entity Name&gt;() functiuons to toEntity() [`e6b9d4f`](https://git.odit.services/lfk/backend/commit/e6b9d4f2737a6eeb30e4c14a10675b13f89d62fa)
- Added basic response calss for runner cards [`af3a9e5`](https://git.odit.services/lfk/backend/commit/af3a9e5ce249950ebd9d54c9b5521c9bd0aaab8c)
- Fixed manual trackscan creation [`188f26a`](https://git.odit.services/lfk/backend/commit/188f26ad650a0099fba2b2b683e5dc5c9ea4613e)
- Added card get tests [`df39166`](https://git.odit.services/lfk/backend/commit/df39166279723f13d38288dd09f3120c26a628f1)
- Added card delete tests [`ebf6682`](https://git.odit.services/lfk/backend/commit/ebf66821a2a0956905a2e7d3e7bbdd0cd2296152)
- Implmented the EAN generation [`860680d`](https://git.odit.services/lfk/backend/commit/860680d001191ac8ab4f5190618b4b0937915992)
- Renamed the update&gt;Entity Name&gt;() functiuons to update() [`3f7b0f6`](https://git.odit.services/lfk/backend/commit/3f7b0f6563f2446508257d09ca87e119c6383ea8)
- Fixed some typos in errors [`ee9df21`](https://git.odit.services/lfk/backend/commit/ee9df21ae53cb4c4787f6605ba981bdff909f9f3)
- Dependency bump [`1bb98c1`](https://git.odit.services/lfk/backend/commit/1bb98c13d1eef83204506e67381f448b16f542fa)
- Implemented proper scan invalidation [`61cf0fc`](https://git.odit.services/lfk/backend/commit/61cf0fc08d3af733b30640880f4b3981cd9f827a)
- Implemented cascading scan, track and card deletion [`3d07aac`](https://git.odit.services/lfk/backend/commit/3d07aac9441b529ec38a47146ee2d8dcb9b5ea73)
- Renamed the auth response call to ResponseAuth [`01e0d5b`](https://git.odit.services/lfk/backend/commit/01e0d5b94db8d6fc8d0e5f6aa7f83794812d9367)
- Fixed some typos and extended comments for the middlewares [`f96b256`](https://git.odit.services/lfk/backend/commit/f96b256ad3ed492367eb4087c6537a9ca116e3cc)
- Implmented basic release mgnt [`dc6ec23`](https://git.odit.services/lfk/backend/commit/dc6ec23cb99efecf1b932b91fcec2bb7d7ba208c)
- Added missing parameter fro negative-test [`4fea690`](https://git.odit.services/lfk/backend/commit/4fea6906706872ca6157679d47b22b70d7ff2255)
- Renamed the auth response call to ResponseAuth [`ac00667`](https://git.odit.services/lfk/backend/commit/ac00667465d80745d6e1954df764f8aa977a693f)
- Moved all update() and toEntity action model functions to async [`3deae2b`](https://git.odit.services/lfk/backend/commit/3deae2bfeb9f022d3d324bfdd7f0d6d2e9bd39a1)
- Fixed runner distance resolution [`9013b94`](https://git.odit.services/lfk/backend/commit/9013b9492c89c8128664cf86f4cf0ab9d4122e55)
- Removed total distance from tests [`3ceb5a0`](https://git.odit.services/lfk/backend/commit/3ceb5a0c0fc49e28ac26e1bccaa1b5ee044e616c)
- Revert "Temporary: extended live logging" [`1e37186`](https://git.odit.services/lfk/backend/commit/1e371862471057d49ba10f18f32533d652eba3a7)
- Temporary: extended live logging [`154c763`](https://git.odit.services/lfk/backend/commit/154c7637195f6f13fcb2f2e1b92fa0d6f2d05b34)
- removed distance checks from tests [`e7cd68e`](https://git.odit.services/lfk/backend/commit/e7cd68e1c8bd419772de33e250292e1d7d65a16b)
- Implemented cascading scan, track and card deletion [`1a5493f`](https://git.odit.services/lfk/backend/commit/1a5493facf5635d8a0fb3773df70a2c6f2f4c767)
- Cleaner implementation of the api version getter [`e4fafd7`](https://git.odit.services/lfk/backend/commit/e4fafd764c138708e0393e0b2cc46dd4e6276239)
- App now automagicly displays the current package version as the openapi version [`9355138`](https://git.odit.services/lfk/backend/commit/9355138a8c8322bc98465fcfc7d9691694b3986b)
- Fixed runner total distance not getting resolved [`e1ce052`](https://git.odit.services/lfk/backend/commit/e1ce052d3caa051b88c0e9525977b0610605b078)
- Removed everything comit related from the release-it config [`02ae883`](https://git.odit.services/lfk/backend/commit/02ae883fa4dd34d3d8032bbe81414c4287f078b9)
- Reverted temporary logging [`02e3239`](https://git.odit.services/lfk/backend/commit/02e3239848a045220f75a7ee3ddd603b5e9a552f)
- Temporary: extended live logging [`89926b2`](https://git.odit.services/lfk/backend/commit/89926b2c3121ab54213492ec8d0c1749b0f610cf)
- Unified remove parameters [`bca979b`](https://git.odit.services/lfk/backend/commit/bca979bab5a092d0e266f96b5eca54525d53b0c7)
- Reverted temporary logging [`8a54b02`](https://git.odit.services/lfk/backend/commit/8a54b027d059365c1573c34da26dfa8dd5ee4456)
- Temporary: extended live logging [`7b4e895`](https://git.odit.services/lfk/backend/commit/7b4e89555ea138acc9908b218491c5b913f1a168)
- Merge pull request 'feature/78-trackscan' (#85) from feature/78-trackscan into dev [`80197d5`](https://git.odit.services/lfk/backend/commit/80197d5834e3db32e4c35b35f8216dd4e7446956)
- Merge pull request 'New feature: runner cards (feature/77-runner_cards)' (#84) from feature/77-runner_cards into dev [`70a379e`](https://git.odit.services/lfk/backend/commit/70a379edef1b96229cbfcbedb3e6267310356290)
- Added card permission target [`98f7bf3`](https://git.odit.services/lfk/backend/commit/98f7bf366f916d98cbce0b502923d1054044badf)
#### [v0.0.10](https://git.odit.services/lfk/backend/compare/v0.0.9...v0.0.10)
> 8 January 2021
- Merge pull request 'Alpha Release 0.0.10' (#83) from dev into main [`490fbd2`](https://git.odit.services/lfk/backend/commit/490fbd241d930cbe1aa9bbe452ee39db187f46a8)
- Fixed responsescheme for the user controller [`c1e680a`](https://git.odit.services/lfk/backend/commit/c1e680a0632451a0f94277cbf47f610af80df0b8)
- Version bump [`f132131`](https://git.odit.services/lfk/backend/commit/f132131156e1ce39ab0e7e634761fafbfb790f1e)
#### [v0.0.9](https://git.odit.services/lfk/backend/compare/v0.0.8...v0.0.9)
> 8 January 2021
- Merge pull request 'All users get profile pics feature/79-profile_pics' (#81) from feature/79-profile_pics into dev [`#79`](https://git.odit.services/lfk/backend/issues/79)
- Merge pull request 'Added scan (station) apis feature/67-scan_apis' (#80) from feature/67-scan_apis into dev [`#67`](https://git.odit.services/lfk/backend/issues/67)
- Merge pull request 'Alpha Release 0.0.9' (#82) from dev into main [`c66b06c`](https://git.odit.services/lfk/backend/commit/c66b06c2c92bcb590dba460831839f5e0735d946)
- Added scan update tests [`975ad50`](https://git.odit.services/lfk/backend/commit/975ad50afc87280fedbc4a9228ee9d071cb14c45)
- Added scan add tests [`0c27df7`](https://git.odit.services/lfk/backend/commit/0c27df7754609d5f0c91db339f71738696f93491)
- Added basics for scan creation (to be tested after scanstations got added) [`72b5ca4`](https://git.odit.services/lfk/backend/commit/72b5ca415340d96649ecce943d19f0e0b2b82fda)
- Added scan station add tests [`5510cbb`](https://git.odit.services/lfk/backend/commit/5510cbb8e9e53dec141dd0e31168321e8253e121)
- Added the enabled flag for scanstations [`4f01baa`](https://git.odit.services/lfk/backend/commit/4f01baaa23c658561a0f34046caa4c1d82cb7773)
- Added scan station update tests [`ccf2a3b`](https://git.odit.services/lfk/backend/commit/ccf2a3b6173744bcb48d066e3430cd8305227923)
- Added barebones scans controller [`ee2433a`](https://git.odit.services/lfk/backend/commit/ee2433a5ae2d3797477e46bc63ddfb362a0ece24)
- Implemented "normal" scan updateing [`eec5284`](https://git.odit.services/lfk/backend/commit/eec528430682fdf2209825d511852141a1c6bd2b)
- Added scan add tests with the station based auth [`a005945`](https://git.odit.services/lfk/backend/commit/a005945e9e0b17d754ffc52dc5f5c2c6a010f3eb)
- Defined responses for scans and trackscans [`a4b0dfe`](https://git.odit.services/lfk/backend/commit/a4b0dfe43ed6707cc682ac100941930c80738ea9)
- Added a barebones scanstation controller [`eea656b`](https://git.odit.services/lfk/backend/commit/eea656bd7b09c8a878235b88793a7a2aa4baf41b)
- Implemented the second round of the toResponse normalisationf for all classes [`2cad2ac`](https://git.odit.services/lfk/backend/commit/2cad2ac2e95d0ece9ec7a7f294aa6e7901915b0c)
- Implemented scan auth middleware [`db6fdf6`](https://git.odit.services/lfk/backend/commit/db6fdf6baf074830a457e0e5ab56421bfc0ce4e3)
- Added Creation class for ScanSatations [`857de9f`](https://git.odit.services/lfk/backend/commit/857de9ffcc637ab5e9761e8e5cc00067d4d21745)
- Fixed Creation of normal scans [`30502ec`](https://git.odit.services/lfk/backend/commit/30502ec94991b31a26bdb9aa631a7323d3f2bccf)
- Added scan get tests [`3f23e4f`](https://git.odit.services/lfk/backend/commit/3f23e4f1f14d07a252a49ed17bfb9ef680feb305)
- Added scan delete tests [`102a860`](https://git.odit.services/lfk/backend/commit/102a860ba350783a08dd20fe66aa4c4b96655dfc)
- Added a ScanStation response class [`c447114`](https://git.odit.services/lfk/backend/commit/c447114297f2a5d2f64582a16cf5c6a2b258086c)
- Implemented the first route of the toResponse normalisationf for all classes [`58156e0`](https://git.odit.services/lfk/backend/commit/58156e0d616dab65ad3366a383426945fd207250)
- Added scan station get tests [`a434173`](https://git.odit.services/lfk/backend/commit/a434173b545f3a7d97c62f00ff4daaa5ef46e71f)
- Added scan station delete tests [`09ab638`](https://git.odit.services/lfk/backend/commit/09ab638239d37746f3acf22b7cb8762c66a66b89)
- Added scan station delete tests [`a4f88c7`](https://git.odit.services/lfk/backend/commit/a4f88c78f4d863e734c8c4b91f0165bbf36ae25d)
- Implemented cascading station deletion [`9b9ee70`](https://git.odit.services/lfk/backend/commit/9b9ee702882730bc765d4e684ff85ec9e9b1ceb1)
- Added single scan get w/ errors [`aeec2e1`](https://git.odit.services/lfk/backend/commit/aeec2e1c3255557bab0452ac931d346335269396)
- Implemented single scan station get +e errors [`b9c0a32`](https://git.odit.services/lfk/backend/commit/b9c0a328628cb6a68460d4c3264487ec18004a8b)
- First part of the permission return (buggy!) [`f3cd138`](https://git.odit.services/lfk/backend/commit/f3cd1380be650837dadd47649eb59b82dea6c060)
- First part of the permission return (buggy!) [`a2c3dfb`](https://git.odit.services/lfk/backend/commit/a2c3dfbf85ea1514959dba05455bd1bf66bd2a2f)
- Added profile pics to all user related models [`3c37aaf`](https://git.odit.services/lfk/backend/commit/3c37aafe1f5b044f524132c74c4642068d7cf559)
- Implmented getting all scan stations [`82644a2`](https://git.odit.services/lfk/backend/commit/82644a2ff49d678937ebe7648bc2f0013cad0031)
- Implemented scan deletion [`88a6a76`](https://git.odit.services/lfk/backend/commit/88a6a768c4849731619024c47e75094be70463de)
- Adusted the way scan distances are implemented [`f1c7713`](https://git.odit.services/lfk/backend/commit/f1c7713da2db6d90df8161872887f61348fafd5b)
- Ajusted the way scan distances are implemented [`d6a41d5`](https://git.odit.services/lfk/backend/commit/d6a41d5a82e3c1e3593a494f6292eb25f1f6533d)
- Updated comments [`c591c18`](https://git.odit.services/lfk/backend/commit/c591c182b344cb09e237ae5046f1a662a5ed4c33)
- Implemented scan station creation [`2628f69`](https://git.odit.services/lfk/backend/commit/2628f6965165de7abbc100ed729b8d1f9c8c422d)
- Track deletion now recognizes associated stations [`9776a35`](https://git.odit.services/lfk/backend/commit/9776a35f9f31bcfaedd44a95b76c3b630179213f)
- Updated OPENAPI Descriptions for the new controllers [`ce8fed3`](https://git.odit.services/lfk/backend/commit/ce8fed350ecc84d5abe8ffd6b0789c89334c5ec1)
- Fixed getting all permissions for users [`aa0337e`](https://git.odit.services/lfk/backend/commit/aa0337ea33b0b68d5a8eed9d520cab4ee064c23d)
- Fixed scan runner in response [`e67d1c5`](https://git.odit.services/lfk/backend/commit/e67d1c56976994ffeae47f038d453123908dc08d)
- Added openapi sec scheme for the scan station auth [`7728759`](https://git.odit.services/lfk/backend/commit/7728759bcd9cf311149ce80f356bdb027b402dd4)
- Added alias for posting track scans [`7387f70`](https://git.odit.services/lfk/backend/commit/7387f700fb75681e7e1e4be766db436a816db489)
- Implemented scans get including the response classes [`f9889be`](https://git.odit.services/lfk/backend/commit/f9889bea3d5d049b08d471ad60264f190aaaad54)
- Finned node version for ci [`c3b9e13`](https://git.odit.services/lfk/backend/commit/c3b9e135b056edb108759e0d72c5a8d2d2079588)
- Fixed wrong auth type being used [`cf86520`](https://git.odit.services/lfk/backend/commit/cf86520faeaf5e4ac2e7b3a3606d2ea8317d2eb6)
- Fixed runner scan validation bug [`edac1a2`](https://git.odit.services/lfk/backend/commit/edac1a224c8ce6fa44ff39302431e64f014b7137)
- Finned node version for ci [`e6576f4`](https://git.odit.services/lfk/backend/commit/e6576f4a540d822ed4c57e42ddecc68ac2311bbb)
- Added tmp files to gitignore [`324d570`](https://git.odit.services/lfk/backend/commit/324d5709e3a11ae2f6e9a7532fe13d54be3d4d6f)
- Added (scan) stations as a new permission target [`3d2c93b`](https://git.odit.services/lfk/backend/commit/3d2c93b5acae4c37278e45580f81ded3a5f088ec)
- Added Scan permission target [`2151b85`](https://git.odit.services/lfk/backend/commit/2151b8502d34f1e7693be1d58fdef1c136414684)
- Version bump [`65e605c`](https://git.odit.services/lfk/backend/commit/65e605cdc4b799be58872d63f1296b943f3f5723)
- Fixed wrong relation getting resolved [`d0deb9d`](https://git.odit.services/lfk/backend/commit/d0deb9d647262a05f6239c273868e715d28777fe)
- Pinned sqlite3 to 5.0.0 as a temporary bugfix [`4991d73`](https://git.odit.services/lfk/backend/commit/4991d735bf4a12369043e8dea533ba387b9b48b9)
- Fixed wrong error getting thrown [`c8f941a`](https://git.odit.services/lfk/backend/commit/c8f941a779d90e6661efca5aeeadc44fc612eb50)
- Fixed typo [`09b37f0`](https://git.odit.services/lfk/backend/commit/09b37f0ff23f1cfc05000648d567801ef2aba137)
#### [v0.0.8](https://git.odit.services/lfk/backend/compare/v0.0.7...v0.0.8)
> 3 January 2021
- Merge pull request 'Fixed relative paths not being updated + version bump for bugfix release' (#75) from dev into main [`d948fe2`](https://git.odit.services/lfk/backend/commit/d948fe26311824cb0e3049bc67b4312535f326aa)
- Fixed relative paths not being updated + version bump for bugfix release [`2b55253`](https://git.odit.services/lfk/backend/commit/2b5525323bc57fc9e4fe02a21f34df06f756f67a)
- Merge pull request 'Bugfix for the openapi exporter' (#74) from dev into main [`b57fde9`](https://git.odit.services/lfk/backend/commit/b57fde9b0a06b6a75a1548109c586245ea703fe4)
- Fixed switch up between node/js and ts-node/ts [`0687f26`](https://git.odit.services/lfk/backend/commit/0687f268fce14ad06dd27642f6f37406cfe83537)
#### [v0.0.7](https://git.odit.services/lfk/backend/compare/0.0.6...v0.0.7)
> 3 January 2021
- Merge pull request 'Minimum lap times for tracks feature/71-track_times' (#72) from feature/71-track_times into dev [`#71`](https://git.odit.services/lfk/backend/issues/71)
- Merge pull request 'New Feature: Donor endpoints feature/65-donor_controllers' (#69) from feature/65-donor_controllers into dev [`#65`](https://git.odit.services/lfk/backend/issues/65)
- Merge pull request 'bugfix/68-address_circular_dependencies' (#70) from bugfix/68-address_circular_dependencies into feature/65-donor_controllers [`#68`](https://git.odit.services/lfk/backend/issues/68)
- Merge pull request 'Automatic and manual license collection 📖' (#62) from feature/59-license_collection into dev [`#59`](https://git.odit.services/lfk/backend/issues/59)
- Merge pull request 'Alpha Release 0.0.7' (#73) from dev into main [`bc42683`](https://git.odit.services/lfk/backend/commit/bc426831db5a257652e529607576046477fc1f5a)
- Switched to automatic license attribution generation via oss-attribution-generator [`580a73f`](https://git.odit.services/lfk/backend/commit/580a73f9a5923215a64d2a073eff8ec18d963803)
- Removed legacy license txt file [`eb40de6`](https://git.odit.services/lfk/backend/commit/eb40de6eb46ee24e247a3c4354e2a98fbf9578bc)
- new license file version [CI SKIP] [`6efd09d`](https://git.odit.services/lfk/backend/commit/6efd09db738d1b10f0e06f9c4f64f6ed1a5381ec)
- Removed the old basic test class [`daa899a`](https://git.odit.services/lfk/backend/commit/daa899a1ef4ccc7bff950cca887d8ba85c937df3)
- Added copy of runnerController with some stuff reanames for donors [`4126d31`](https://git.odit.services/lfk/backend/commit/4126d31a5e87aadd33f3c0b7878c71d428721243)
- Added track update tests [`d67be31`](https://git.odit.services/lfk/backend/commit/d67be313e6c683a2494790af43fc4ab5300c5dfa)
- Added track add tests [`1a0573e`](https://git.odit.services/lfk/backend/commit/1a0573e0d055488bbb2c8474c8d60f7ff5f32c02)
- Added donor post (add) tests [`e4c1930`](https://git.odit.services/lfk/backend/commit/e4c1930dd1ac1c95ca0449d81dd2251f570729a5)
- Added donor put (update) tests [`deb1367`](https://git.odit.services/lfk/backend/commit/deb13674b255fde6f367e09bf624ac084a5f44de)
- Implemented track upodates using the "new" method [`59cb72a`](https://git.odit.services/lfk/backend/commit/59cb72a11d6a12a1733a3bd8d8c082252a408bfd)
- Mitigated circular dependency (to be fixed) [`1dc438b`](https://git.odit.services/lfk/backend/commit/1dc438beb25e81671980fa7a5704879169053985)
- Added basic runner updateing [`ab67e5f`](https://git.odit.services/lfk/backend/commit/ab67e5f4aaa6deeb79af1ebbf2aaff0675ce58e9)
- Added donor get tests [`b337ab4`](https://git.odit.services/lfk/backend/commit/b337ab424d2a350d662910445fcbdb1a5e35c070)
- Revert "Added --full option for the license exporter to export the license path and text as well" [`a501625`](https://git.odit.services/lfk/backend/commit/a501625dd65c05fc96155a0c9f315958aa963ad7)
- Added --full option for the license exporter to export the license path and text as well [`62c7f26`](https://git.odit.services/lfk/backend/commit/62c7f26540905b0f73c09b8047da7718a67cfaf8)
- Implemented a possible bugfix [`2c47436`](https://git.odit.services/lfk/backend/commit/2c47436259260a3e1d340ae64e69da1496a685ec)
- Added track delete tests [`15d2d02`](https://git.odit.services/lfk/backend/commit/15d2d029dc251751ec46511d3e770392a96ba622)
- Added track get tests [`9f103d8`](https://git.odit.services/lfk/backend/commit/9f103d8df1242b95fdea4a461975b05e4b0c2c6b)
- Added donor delete tests [`17c82ff`](https://git.odit.services/lfk/backend/commit/17c82ff4098dc42a99fae445fc298471b295cb0a)
- Added everything for basic donor creation [`557608e`](https://git.odit.services/lfk/backend/commit/557608e3181ec3b2c6a6cde3a6405509356e97d0)
- Added first donor-specific errors [`a83fedc`](https://git.odit.services/lfk/backend/commit/a83fedc9b8cefb25105149aa82988c8aa263a0bb)
- Revert "Added license exporter (to json)" [`5cfd2c9`](https://git.odit.services/lfk/backend/commit/5cfd2c9a526b17c3c8cdfa687fa90235426283bc)
- Added license exporter (to json) [`84a0bd2`](https://git.odit.services/lfk/backend/commit/84a0bd2cd90509eb843d3f7db569f0a96685acc2)
- Added the base logic for donor getters [`3df1db4`](https://git.odit.services/lfk/backend/commit/3df1db4ad8fa26deaaf7fe64af94c8893303d9c3)
- Improved error handling for negative lap times [`28c1b6d`](https://git.odit.services/lfk/backend/commit/28c1b6d31dddab082a31aeaedff6dd9339dbfc0c)
- Removed the testing pipeline and updated the dev license pipeline [`8757813`](https://git.odit.services/lfk/backend/commit/875781335c771382aad8d346ee6ec42bb184c6b3)
- Revert "Added test pipeline for automatic license export" [`cc64ce4`](https://git.odit.services/lfk/backend/commit/cc64ce449865e8a460cc9a175141296586da5b09)
- Added test pipeline for automatic license export [`c9378e6`](https://git.odit.services/lfk/backend/commit/c9378e6cae06dcb355bc05cae4370d70477b94be)
- Added donor response class [`e46cfa0`](https://git.odit.services/lfk/backend/commit/e46cfa0d7789466cf9fef153de7eed0fc10c96bf)
- Revert "Removed addresses from tests until the circular dependencies are solved" [`56c6a7e`](https://git.odit.services/lfk/backend/commit/56c6a7efb057da6a43081be803ae2b15402eb2fd)
- Updated track tests for paralellism [`82a0e19`](https://git.odit.services/lfk/backend/commit/82a0e194cbac2b9191e1361909dbcb979865bda3)
- Removed addresses from tests until the circular dependencies are solved [`599296c`](https://git.odit.services/lfk/backend/commit/599296c4e3736bf9aadbc32067cd2ff8c39f0f17)
- Revert "Added automatic license export on dev push/merge" [`2924ac2`](https://git.odit.services/lfk/backend/commit/2924ac290027acb16d08a6b2f79510552abee053)
- Added automatic license export on dev push/merge [`18e3ef9`](https://git.odit.services/lfk/backend/commit/18e3ef9a7954f4102a26f050e5b82ace69e9a17b)
- Added address check for donors that want a receipt [`335d4e2`](https://git.odit.services/lfk/backend/commit/335d4e24daeccf06b559c077e26469c5d6c8a91c)
- Implemented basic donor deletion [`61a17b1`](https://git.odit.services/lfk/backend/commit/61a17b198f13a3c4b57d4811f74a531688e95045)
- Marked property as optional [`02f7ddb`](https://git.odit.services/lfk/backend/commit/02f7ddbb37efe28cc682cda2666d442770f56e8c)
- Added the laptime to the track response [`dcb791c`](https://git.odit.services/lfk/backend/commit/dcb791c9a2418900a9f07730fd9d650593606f72)
- Added the minimum lap time to the track entity [`63b1ca9`](https://git.odit.services/lfk/backend/commit/63b1ca9b56d3c729a441390ca4b4dd1134ae0a37)
- Added donor add test for address needed error [`f9e314b`](https://git.odit.services/lfk/backend/commit/f9e314bf9f2c0a23e585f5a093b1b46a92af54cd)
- Revert "Moved package script related files to their own folder" [`6c7b31d`](https://git.odit.services/lfk/backend/commit/6c7b31d76c2b93078cab53e81242e7d4a5dc7447)
- Moved package script related files to their own folder [`395b010`](https://git.odit.services/lfk/backend/commit/395b0101a8a8684566b4c56e36c1f1f34dc87a4c)
- Reenabled addresses in org responses [`1e2de76`](https://git.odit.services/lfk/backend/commit/1e2de7656e36405b9b15d4e0a7004e8b14e61c85)
- Added helpful comment about the tracktime's unit [`f378b06`](https://git.odit.services/lfk/backend/commit/f378b0651add4142ce02a288c7712ab8d4fdedfa)
- Added address check for donors that want a receipt on update [`2594a60`](https://git.odit.services/lfk/backend/commit/2594a607dc4315a8fdfe42c8b961b6c3a30b4428)
- Fixed copy-paste mistake [`b6ea5e6`](https://git.odit.services/lfk/backend/commit/b6ea5e6549ef5dd347428f8d2fddc564abb7abdc)
- Added the laptime to createtrack [`907259b`](https://git.odit.services/lfk/backend/commit/907259bf737f4ad5bcc5d65f152c3f54ce2f6408)
- Added comments to the bugfix [`9c4e54f`](https://git.odit.services/lfk/backend/commit/9c4e54fc6e738194475c956895a229b18b51a3f4)
- Bumped license lib version [`05868e0`](https://git.odit.services/lfk/backend/commit/05868e0e00aca932634c759f33fc46ff4c9ba5ad)
- Added new donor permission target [`9d9549c`](https://git.odit.services/lfk/backend/commit/9d9549cdd45f53137c8b86b28e2f051b1eba806b)
- Version bump [`276e553`](https://git.odit.services/lfk/backend/commit/276e553e13c8e84a2a884f353bb863aef17e3833)
- Change requested by @philipp [`97e8470`](https://git.odit.services/lfk/backend/commit/97e8470b0d9c2d6e87fb951236769eb4274e2ab9)
- Dependency: Bumped license-exporter version [`6b0e350`](https://git.odit.services/lfk/backend/commit/6b0e3503a75b566640bdbc8a4c4834e318549f2e)
- Fixed not null constraint [`52cdd41`](https://git.odit.services/lfk/backend/commit/52cdd41ec869318d75aead3043b3541487916b5a)
- Fixed not null constraint [`53548ba`](https://git.odit.services/lfk/backend/commit/53548ba7a698bef27560adb18aca07e4a587c155)
- Extended todo w/ issue link [`c9ba697`](https://git.odit.services/lfk/backend/commit/c9ba69792f326b70d68ee1529d513f0fc122d375)
- Adjusted ci dependencies [`82d4b11`](https://git.odit.services/lfk/backend/commit/82d4b11de3a07c6ccbbaa0e4d98c7f4cd8c31440)
- Adjusted ci dependencies [`7547393`](https://git.odit.services/lfk/backend/commit/75473937cfec3abcac7aabb301f115acf1f3a8da)
- Canged drone branch [`a68bbab`](https://git.odit.services/lfk/backend/commit/a68bbab8abaa560fd05ef4ed850854266b6e02c9)
- Removed useless console.log [`a5d70ce`](https://git.odit.services/lfk/backend/commit/a5d70ce4b5ea758a535958752d65d0ab23c727c3)
- Added todo relateing to the bugfix issue [`9b5d16a`](https://git.odit.services/lfk/backend/commit/9b5d16ae92045580a748c820d0af64950cf2fdfd)
- Added secondary dependency for piupeline [`a684f60`](https://git.odit.services/lfk/backend/commit/a684f602524ea0426c68317786ac25c29281a254)
- new license file version [CI SKIP] [`931cae3`](https://git.odit.services/lfk/backend/commit/931cae3c9839c1febf89276486c6a3d989099133)
#### [0.0.6](https://git.odit.services/lfk/backend/compare/0.0.5...0.0.6)
> 30 December 2020
- Merge pull request 'feature/56-stats_endpoint' (#60) from feature/56-stats_endpoint into dev [`#56`](https://git.odit.services/lfk/backend/issues/56)
- Merge pull request 'Merge for alpha 0.0.6' (#61) from dev into main [`9cd181c`](https://git.odit.services/lfk/backend/commit/9cd181c5b8cae2d2bf80e635a5d6cd8f9e466eb6)
- Added stats and stats responses for orgs [`5d31d8d`](https://git.odit.services/lfk/backend/commit/5d31d8d1a23f8bbff31cf89cc1090103362c607e)
- Added stats response [`53a01ad`](https://git.odit.services/lfk/backend/commit/53a01ad97779ff47be4c309f5dc2547ecc61d08e)
- Added a controller for stats clients (todo: put) [`500b94b`](https://git.odit.services/lfk/backend/commit/500b94b44afc27df2bbbaab50390fdf7e7fb7d14)
- Added a response class for team stats [`ec64ec3`](https://git.odit.services/lfk/backend/commit/ec64ec3d6326c0afcdff64f782944554c2760b78)
- Added response class for the runner stats [`d850650`](https://git.odit.services/lfk/backend/commit/d850650aeb632576114a0f7d726533585e0fd3bb)
- Update: keys cant be updated (for security reasons) [`b53b5cf`](https://git.odit.services/lfk/backend/commit/b53b5cf91f073a30736fe941ded9d63a1816423f)
- Added authed stats routes [`555e37e`](https://git.odit.services/lfk/backend/commit/555e37eaf71456d4b46ec8343622ccd1d5ea2f27)
- Created a response for the statsClient [`2b38044`](https://git.odit.services/lfk/backend/commit/2b3804427117ab36aea31986f18928ee49f9fdcb)
- Impelemented stats api auth via token or the usual auth (jwt with get for runners, teams and orgs). [`43e256f`](https://git.odit.services/lfk/backend/commit/43e256f38c216b0136dd9b6fb41a73f98047d110)
- Added basic status api key checking middleware [`7c5a389`](https://git.odit.services/lfk/backend/commit/7c5a3893efd98bcd1b0684e3c0571a5206485bf0)
- Updated the method of api key creation. [`0481317`](https://git.odit.services/lfk/backend/commit/04813173e4c6ff57702950ad5d8126a1ad7b47f3)
- Implemented more stats endpoints [`6e121a3`](https://git.odit.services/lfk/backend/commit/6e121a3ce29ba858eafe3d8c6314c865cd05621c)
- Added the new statsClient class for stats api auth [`a738c19`](https://git.odit.services/lfk/backend/commit/a738c19316355343d4a458903de3209f0fbd8daa)
- Added stats endpoint with some basic stats (more to come) - to be tested [`1b7424f`](https://git.odit.services/lfk/backend/commit/1b7424f7501075ede10cc91e3f4de096065b4533)
- Added Create action for the statsclients [`e2cc0c0`](https://git.odit.services/lfk/backend/commit/e2cc0c0b800a66a8696525dd7a8f7e4b3d456c7c)
- Added some comments [`e0fa58d`](https://git.odit.services/lfk/backend/commit/e0fa58da57013a3482636a04d20095d2f842fa7e)
- Added example endpoint for stats auth [`345851b`](https://git.odit.services/lfk/backend/commit/345851bf1d8dc06c2cdcefe90135dea3470898e6)
- Added basic errors for stats clients [`641466a`](https://git.odit.services/lfk/backend/commit/641466a7315fe6869e9b41cdb855cc52cf5487f9)
- Added enabled flag for the stats clients [`4c3d264`](https://git.odit.services/lfk/backend/commit/4c3d2643c111dece23a38a565cd4cb156e55a917)
- Updated security for the stats endpoints [`6cb978d`](https://git.odit.services/lfk/backend/commit/6cb978df98c548111ea5da6dac4c551d7411748b)
- Moved the authchecker to the middleware folder (b/c it pretty much is a glolified middleware) [`b5f9cf2`](https://git.odit.services/lfk/backend/commit/b5f9cf201d09c32ff10017eb7956cf41d6167540)
- Added openapi scheme for the stats api tokens. [`9675e79`](https://git.odit.services/lfk/backend/commit/9675e79441e623821402902768bd1cbd9c6ef951)
- Switched to hased tokens based on uuid (to be canged) [`bb24ed5`](https://git.odit.services/lfk/backend/commit/bb24ed53a4b4601c2cce9d0d5ecdc23e5db18f6d)
- Added team and org stats [`6a762f5`](https://git.odit.services/lfk/backend/commit/6a762f570d8f58c70413974daa2f4d20729af814)
- Added donation amount to the stats runner response [`35dbfeb`](https://git.odit.services/lfk/backend/commit/35dbfeb5e7302dd1865d41c561dbdfb2f0823603)
- Added ResponseSchemas and fixed donation resolution bug [`dd48ee2`](https://git.odit.services/lfk/backend/commit/dd48ee2f7edd38af803f735567e1aadeeb7c655d)
- Added mission relation resolving [`d779175`](https://git.odit.services/lfk/backend/commit/d7791756dcee47e0e0e516a2a1be8f88d0394c4f)
- Added response schemas [`a9ecfcc`](https://git.odit.services/lfk/backend/commit/a9ecfccfd26bcd47c902c7ddd81b3049384e12bc)
- Adapted the new async behaviour [`c4270b0`](https://git.odit.services/lfk/backend/commit/c4270b0839cb90be2be7ed498605eedb0f6e4d4d)
- Adjusted the validation type [`b7cbe2a`](https://git.odit.services/lfk/backend/commit/b7cbe2a0b485d341c7a556d460d585e0be834056)
- Added STATSCLIENT as a new permission target [`b604374`](https://git.odit.services/lfk/backend/commit/b6043744a9ce1ec9daf04aefd965659f8df26750)
- Version bump [`41828a6`](https://git.odit.services/lfk/backend/commit/41828a6e41164fc8472595d5b6410f481d65909f)
- Added response schemas [`4cb0efa`](https://git.odit.services/lfk/backend/commit/4cb0efa6bd17b30bbc67767e7eb2d7f313d5cf3c)
- Renamed class [`1b74b21`](https://git.odit.services/lfk/backend/commit/1b74b214202217edfcb5ab4202a713cfb14130c1)
- Removed async flag, b/c this doesn't need to perform anything async [`e3ea83b`](https://git.odit.services/lfk/backend/commit/e3ea83bb4782565e773e97019a92aa71f92c2809)
- Removed abstract flag from class [`ce55dce`](https://git.odit.services/lfk/backend/commit/ce55dce011bb44c65b1ed1e3a60123cb5edb7b38)
- Adjusted return type, since async is no longer needed here (thanks to db relations) [`bdd4f70`](https://git.odit.services/lfk/backend/commit/bdd4f705bee079d052c17bc5fb1222c73d8aef47)
#### 0.0.5
> 29 December 2020
- Merge pull request 'feature/52-alternative_openapi_viewers' (#53) from feature/52-alternative_openapi_viewers into dev [`#52`](https://git.odit.services/lfk/backend/issues/52)
- Merge pull request 'feature/49-openapi_cookie_schema' (#51) from feature/49-openapi_cookie_schema into dev [`#49`](https://git.odit.services/lfk/backend/issues/49)
- Merge pull request 'feature/45-auth_tests' (#50) from feature/45-auth_tests into dev [`#45`](https://git.odit.services/lfk/backend/issues/45)
- Merge pull request 'feature/40-pw_reset' (#48) from feature/40-pw_reset into dev [`#40`](https://git.odit.services/lfk/backend/issues/40)
- Merge pull request 'feature/43-postal_from_env' (#46) from feature/43-postal_from_env into dev [`#43`](https://git.odit.services/lfk/backend/issues/43)
- Merge pull request 'Updated the put methods and cleaned up a shitload of comments' (#42) from feature/39-update_puts into dev [`#39`](https://git.odit.services/lfk/backend/issues/39)
- Merge pull request 'Fixed a bug concerning user updates' (#38) from bugfix/37-user_update into dev [`#37`](https://git.odit.services/lfk/backend/issues/37)
- Merge pull request 'feature/34-status_health' (#36) from feature/34-status_health into dev [`#34`](https://git.odit.services/lfk/backend/issues/34)
- Merge pull request 'Auth for everything (and everything auth) #6' (#35) from feature/6-api_auth into dev [`#6`](https://git.odit.services/lfk/backend/issues/6)
- Merge pull request 'Runner import' (#33) from feature/22-runner_import into dev [`#22`](https://git.odit.services/lfk/backend/issues/22)
- Merge pull request 'feature/24-production_dockerfile' (#30) from feature/24-production_dockerfile into dev [`#24`](https://git.odit.services/lfk/backend/issues/24)
- Merge pull request 'feature/25-refresh-token-cookie' (#29) from feature/25-refresh-token-cookie into dev [`#25`](https://git.odit.services/lfk/backend/issues/25)
- Merge pull request 'New Feature: User seeding feature/19-user_seeding' (#26) from feature/19-user_seeding into dev [`#19`](https://git.odit.services/lfk/backend/issues/19)
- Merge pull request 'Added drone pipeline that automaticly runs on prs (or at least it should)' (#27) from feature/23-tests_on_pr into dev [`#23`](https://git.odit.services/lfk/backend/issues/23)
- Merge branch 'feature/18-exported-env-vars' into dev [`#16`](https://git.odit.services/lfk/backend/issues/16) [`#18`](https://git.odit.services/lfk/backend/issues/18)
- final phone validation move to ZZ default [`#16`](https://git.odit.services/lfk/backend/issues/16)
- Merge branch 'feature/12-jwt-creation' into dev [`#12`](https://git.odit.services/lfk/backend/issues/12)
- ✅ - close #14 [`#14`](https://git.odit.services/lfk/backend/issues/14)
- tsdoc generation [`#8`](https://git.odit.services/lfk/backend/issues/8)
- Merge pull request 'Updates for the tag build pipeline' (#58) from dev into main [`bc76afa`](https://git.odit.services/lfk/backend/commit/bc76afafce6faaba67718753e218fc0d7be899fc)
- switched over to using the static deployment of swaggerUI [`39ad43b`](https://git.odit.services/lfk/backend/commit/39ad43bbb20055328f51ff7d96983c8f3318fd61)
- Added very basic api doc chooser [`ebedea9`](https://git.odit.services/lfk/backend/commit/ebedea97ed3eb0c35696e18e5b69e60232b11667)
- Cleanup [`6e316a7`](https://git.odit.services/lfk/backend/commit/6e316a7533daca0c2045b8947ce9c0cb84253876)
- Moded runner get tests to a new file and added more of them [`49ac7be`](https://git.odit.services/lfk/backend/commit/49ac7be3671f5e322bd30b480f943f7464947718)
- Added responseusers [`efecffb`](https://git.odit.services/lfk/backend/commit/efecffb72d85ecedc8fb5656312d4e514d393145)
- Consolidated the json import for a cleaner result [`0d8fbf1`](https://git.odit.services/lfk/backend/commit/0d8fbf1eca512c3a14cd4ca09b0eda820742ed43)
- Implemented new Permission system on the DB side. [`cc5a309`](https://git.odit.services/lfk/backend/commit/cc5a30980a8d07966981f0474f2de83e15c7a5e5)
- Added runner update tests [`c20f01f`](https://git.odit.services/lfk/backend/commit/c20f01f485897ca3f6e5a4936525fc7266ec020c)
- Added org deletion tests (orgs that still have teams) [`32a92b1`](https://git.odit.services/lfk/backend/commit/32a92b1ad712a83d9bdd901b3341815a4edece3d)
- Added runner creation tests [`47862f2`](https://git.odit.services/lfk/backend/commit/47862f2e1dd3ab958b81242def40fda1fc6c8343)
- Added auth reset tests [`c6ecde2`](https://git.odit.services/lfk/backend/commit/c6ecde29b59119152f8c68f6e504a81c9e628208)
- Added team update tests [`105efdd`](https://git.odit.services/lfk/backend/commit/105efdd4543ad14cb43a6bfb5f15f16527c8fe03)
- Runner updateing now works with it's own class [`f3000f1`](https://git.odit.services/lfk/backend/commit/f3000f14cd3197c95e8a26366435a0ca99e06d8c)
- Bugfix for runner team updates [`721af32`](https://git.odit.services/lfk/backend/commit/721af329893f6c18c378491b61bae053722f41e6)
- Implemented basic password reset [`caeb173`](https://git.odit.services/lfk/backend/commit/caeb17311b3acae85850f4dd0fe835421f6d2b63)
- Added auth refresh tests [`13949af`](https://git.odit.services/lfk/backend/commit/13949af938ccc1897e3692c3facb2fefb2ed4a7b)
- Added logut tests [`3c003a6`](https://git.odit.services/lfk/backend/commit/3c003a60b207d744a6763fc8605abeadd07d81fc)
- added the first login tests [`af27448`](https://git.odit.services/lfk/backend/commit/af2744885fd047467b948c5414d308487c49abc4)
- Added a basic pw reset action [`aa146cd`](https://git.odit.services/lfk/backend/commit/aa146cd6c1d2bfd94217778863f55b34c9c3b103)
- refactoring: cleaned up the names [`d295100`](https://git.odit.services/lfk/backend/commit/d295100a48b46aaa1b2f085464ae282e9d626c10)
- Added runner deletion tests [`d2e0384`](https://git.odit.services/lfk/backend/commit/d2e0384f3cf0d159f1d531f4ac89fae8ae697da9)
- Added team update test [`92dee66`](https://git.odit.services/lfk/backend/commit/92dee666ee842eafa010cb19484e850be01daacb)
- Added basic update test [`64725d9`](https://git.odit.services/lfk/backend/commit/64725d9e7a75e3768ba1912989a94ac1ec741fb9)
- Went back to using id's for deletion (for cleaner query params) [`df5b8ac`](https://git.odit.services/lfk/backend/commit/df5b8ac141ebd009018537ca6107f212dc6403c6)
- Now disableing users while they're in the process of resetting their password [`4b9bfe3`](https://git.odit.services/lfk/backend/commit/4b9bfe3b79c2afd4013df5ed30d7e3fa5b635e2e)
- Added openapi cookie security schema [`dae51cf`](https://git.odit.services/lfk/backend/commit/dae51cfd471089fa15b5feceb66af1407304fde5)
- Changed method of triggering lib builds [`ded14b1`](https://git.odit.services/lfk/backend/commit/ded14b1b3bc7282ed09a708d990c88d7ef913b94)
- Implemented a password reset timeout [`17ee682`](https://git.odit.services/lfk/backend/commit/17ee682029cf261a557dc2e20d6375c41b12f721)
- Added first demo seed [`09decd5`](https://git.odit.services/lfk/backend/commit/09decd5600e415491f5a50e078b3487f099542f4)
- Set trigger to ref tags only [`b737fe6`](https://git.odit.services/lfk/backend/commit/b737fe6a0829f85aba3670c7f6de46f2b7da0cf4)
- Little comment cleanup [`02877ec`](https://git.odit.services/lfk/backend/commit/02877ece9c0dde3211931de0a1b71b57f21843cb)
- Implemented the getter for loading the postalcodelocale from env [`b8c93bf`](https://git.odit.services/lfk/backend/commit/b8c93bf476d0c2e7ac37b202d0b8788567304824)
- Added basic runner get tests [`d0d050e`](https://git.odit.services/lfk/backend/commit/d0d050e6c6e8733b677030883ce259f51d1e3eda)
- Updated ci to trigger the builds for the new libs [`ce5f4b4`](https://git.odit.services/lfk/backend/commit/ce5f4b467d66ee3865e9f1662ed8a4f5bce645c4)
- Implemented toe password reset route [`5aad581`](https://git.odit.services/lfk/backend/commit/5aad581c2d01fc674c0f94a7c6a778b798abaa07)
- Renamed the password reset token creation class to better fit the scheme [`aef8485`](https://git.odit.services/lfk/backend/commit/aef8485f597aca09e680a3967bd15b361c1531c4)
- Added drone pipeline that automaticly runs on prs (or at least it should) [`d543dfb`](https://git.odit.services/lfk/backend/commit/d543dfb2010f186f242407284016ffe34669f78c)
- Added login test after logout [`a9dbf1d`](https://git.odit.services/lfk/backend/commit/a9dbf1d0d2cb79b75707b91462d043a66c8f64a0)
- Users now can be disabled from the start [`a16c4c5`](https://git.odit.services/lfk/backend/commit/a16c4c564a5c81fbe46326591ca574c09069fcee)
- Updated the openapi descriptions for all team routes [`16e5b69`](https://git.odit.services/lfk/backend/commit/16e5b6921d35ed69ba9d48ec6ae0789127aa59e4)
- Updated the openapi descriptions for all team routes [`58a12c7`](https://git.odit.services/lfk/backend/commit/58a12c7fa187ad94801313ebd7df01dee8cffe0a)
- Updated the openapi descriptions for all organisation routes [`f256dec`](https://git.odit.services/lfk/backend/commit/f256dec121bb39bbb9f23273d9cb4f9400f94db8)
- Updated the openapi descriptions for all runner routes [`66631f5`](https://git.odit.services/lfk/backend/commit/66631f5e0a943be974dee887758052c61a1f7708)
- Updated the openapi descriptions for all runner routes [`8de35f3`](https://git.odit.services/lfk/backend/commit/8de35f3431b28759f152ad01e60be86519d488b0)
- Updated the openapi descriptions for all permission routes [`05319e6`](https://git.odit.services/lfk/backend/commit/05319e6f6ea10676281f2a05aad95cdca4d156ba)
- Updated the openapi descriptions for all auth routes [`50f2462`](https://git.odit.services/lfk/backend/commit/50f2462eb9f5a49e1cc6cfb6ce8473b9804073f0)
- Added comments [`146787f`](https://git.odit.services/lfk/backend/commit/146787fd660afe1bd8d775b9355e3ad97f6795dc)
- All things auth now check if the user is disabled [`bf4250b`](https://git.odit.services/lfk/backend/commit/bf4250babd3e5c684cfdea9d49a5e268db8867c8)
- Added a password reset token request route [`61aff5e`](https://git.odit.services/lfk/backend/commit/61aff5e629c0e1c9349e4709bcbeb0b3e56ec191)
- User seeding now automaticly runs if no users are detected [`473033a`](https://git.odit.services/lfk/backend/commit/473033aa50191bca7518fc842c6d550c72600304)
- added non-existant deletion test for teams [`71e5be2`](https://git.odit.services/lfk/backend/commit/71e5be2ba47bdfef9f1e1a705ef4014ca7b3244e)
- Updated the openapi descriptions for all import routes [`b7827fe`](https://git.odit.services/lfk/backend/commit/b7827fef5462dbcc5b861716162ca25e892fb455)
- new get test [`5a27689`](https://git.odit.services/lfk/backend/commit/5a27689e80a54c424c3ce260e40d2af2a64e52d9)
- Added wron password auth test [`69796a8`](https://git.odit.services/lfk/backend/commit/69796a888fa9a2f108717d320d5005db388e67b6)
- Added the POSTALCODE_COUNTRYCODE to the sample and ci env files [`f300897`](https://git.odit.services/lfk/backend/commit/f3008979f30b3a4d5de87ad415b06b813f8bd1a2)
- Added seed yarn script [`effa790`](https://git.odit.services/lfk/backend/commit/effa79032bb4dbacaf75a74646130424b21d9767)
- Fixed uniqueness error [`a4ddeee`](https://git.odit.services/lfk/backend/commit/a4ddeee8e4fdabd5ef7abb42a2688508f6a683eb)
- Renamed the return variable to fit the class [`5aa83fe`](https://git.odit.services/lfk/backend/commit/5aa83fe2f0b3c2afbcde2114a60163929c651e12)
- Added a test:ci script (for testing in ci enviornments) [`79e418f`](https://git.odit.services/lfk/backend/commit/79e418f91883f90827453fdf5fe031cf777173da)
- Switched to yarn [`abb1304`](https://git.odit.services/lfk/backend/commit/abb13045e6857057515aab77d8aacb6ef9e23e82)
- Added validator as a explicit dependency, b/c pnpm doesn't fallback to peer dependencies [`a85e914`](https://git.odit.services/lfk/backend/commit/a85e914759e1f511d21c8ddc0a73a40ad08dba65)
- Removed bs enabled check [`2f7b0d5`](https://git.odit.services/lfk/backend/commit/2f7b0d5606de7daa168d6db4f081df4169641e87)
- Changed docker image tag [`fbd3f61`](https://git.odit.services/lfk/backend/commit/fbd3f615ad33e9695f8c77e21a588fb6f14a99ac)
- Merge pull request 'Final fix for the tag pipeline triggers' (#57) from dev into main [`a22a7a1`](https://git.odit.services/lfk/backend/commit/a22a7a19c2bd7bd545a91375447f350432ebaa4a)
- Added very basic api doc chooser [`5c3c3eb`](https://git.odit.services/lfk/backend/commit/5c3c3eb167cbfdfe38467f5ec58b42aa16e9876a)
- 🎨 fixed landing html + styling [`11c7d04`](https://git.odit.services/lfk/backend/commit/11c7d041efaa6d2cca50bc58e263edfd7821147e)
- Removed the firsttests jest tests (they were redundant) [`ce0500e`](https://git.odit.services/lfk/backend/commit/ce0500ef8cf7fd6dca1c74594782f840ecbf92ae)
- Added tests for the api docs [`9ab6eb5`](https://git.odit.services/lfk/backend/commit/9ab6eb5314e102b063cd1131f7f0152af2ca8a6e)
- Tried switching to global when [`607630c`](https://git.odit.services/lfk/backend/commit/607630c4f936ea1097b0300310bb5c4558c65d73)
- Switched from trigger to when [`a7976c0`](https://git.odit.services/lfk/backend/commit/a7976c0ee2d9920595ef9ab595ce3c16fcdb9238)
- Updated the openapi descriptions for all group routes [`1f061c7`](https://git.odit.services/lfk/backend/commit/1f061c7ea6ae59452eae8d1c04f1937608f156df)
- Now using the exact trigger snytax the gitea project uses [`6a8247f`](https://git.odit.services/lfk/backend/commit/6a8247f88a50b7a29e7e0d85b95a31e3436d572b)
- Moved to the official tag recognition [`a79bed2`](https://git.odit.services/lfk/backend/commit/a79bed259b584f586a102da82f92bfdf2db2202f)
- Fixed typo [`c34bde7`](https://git.odit.services/lfk/backend/commit/c34bde7d4fd065f7f43fb62f85de713b546867e1)
- Back to when syntax for triggering tag builds [`b3f7412`](https://git.odit.services/lfk/backend/commit/b3f741234e20f87e856868f01e7014acf1f82726)
- Removed everything concerning the swaggerUI express middleware [`9fc282d`](https://git.odit.services/lfk/backend/commit/9fc282d858d08ccc0a4e546bf149219f13b0fb12)
- Updated the openapi descriptions for all user routes [`578f930`](https://git.odit.services/lfk/backend/commit/578f9301db0a7373a98d74b6c1af0c4a04d367ed)
- Updated the openapi descriptions for all track routes [`9b47f3a`](https://git.odit.services/lfk/backend/commit/9b47f3ab05fbb7f50f24007bac8019ea1f3fdd1b)
- Set package version (+openapi version) [`c93e93b`](https://git.odit.services/lfk/backend/commit/c93e93be319280a6e2284078f2881748b6cb8a0b)
- Removed push from tag build triggers [`e33076c`](https://git.odit.services/lfk/backend/commit/e33076c04d021a3f7c5609e28616f5ad8442ae1b)
- Added branch to when [`f2970f4`](https://git.odit.services/lfk/backend/commit/f2970f4cd8fb95db4cff0c24522890f43448047c)
- Added tag as ref to tag build [`5ed5f18`](https://git.odit.services/lfk/backend/commit/5ed5f181d187cc40c3cde28079a3e6f782b46843)
- Renamed the package to fit the scheme for the project [`d8e38f4`](https://git.odit.services/lfk/backend/commit/d8e38f404dab045e4778a27763a2d0cc1815b6c7)
- Added the static files to the build step [`bb70bf5`](https://git.odit.services/lfk/backend/commit/bb70bf58fb1a09e2c856bd32e679037301f37589)
- Removed the branch requirements from dev [`519d11b`](https://git.odit.services/lfk/backend/commit/519d11beef5dc985314a565313e059f5c5401a19)
- Added pushing to tags as trigger [`b51da15`](https://git.odit.services/lfk/backend/commit/b51da15007f1144d34789effa7ddc52476c0e70c)
- Added push as drone tag build event trigger [`ae35f50`](https://git.odit.services/lfk/backend/commit/ae35f50da268144b948f0ff605c519849ccba5b5)
- Merge pull request 'Bugfix for the release pipeline (no other changes)' (#55) from dev into main [`cc5d90c`](https://git.odit.services/lfk/backend/commit/cc5d90cb4fa811be266f8a49d9669a0a975264f9)
- Merge pull request 'Merge alpha 0.0.5 to master' (#54) from dev into main [`cbed5fc`](https://git.odit.services/lfk/backend/commit/cbed5fc0b24bbb418b02b5808013caaaa3ed050f)
- Added auth to all tests [`b19f18a`](https://git.odit.services/lfk/backend/commit/b19f18ada16d7e7c150e3e4281603b0706435124)
- Added pw reset jwt generation [`6042089`](https://git.odit.services/lfk/backend/commit/6042089074810df8b5af8fc5ff6447ea8c1dc7d0)
- Merge pull request 'Disabled the x-served-by and x-powered-by Headers' (#44) from feature/41-owasp_headers into dev [`b6cf3b2`](https://git.odit.services/lfk/backend/commit/b6cf3b24d42c38952684e8ec95d8cd5950af4940)
- Code + comment cleanup for the entities [`d20d738`](https://git.odit.services/lfk/backend/commit/d20d7382180b798ecf96ba30d7171a870be682f5)
- Implemented permission getting [`d89fcb8`](https://git.odit.services/lfk/backend/commit/d89fcb84a28b535a017dd22494281710d465072f)
- Code + comment cleanup for the response models [`7533298`](https://git.odit.services/lfk/backend/commit/75332983c2b6eec549af8b479c864277102e3f7d)
- First part of the action comment refactoring [`1d0d79f`](https://git.odit.services/lfk/backend/commit/1d0d79f3da52adb9e070812f2a8428bad0303f2e)
- Now with 1000% cleaner jwt generation [`65a8449`](https://git.odit.services/lfk/backend/commit/65a8449ea390503060a9882dc6a102411ad93880)
- Fixed some weired user update behaviour [`ca14237`](https://git.odit.services/lfk/backend/commit/ca142376b3e229dc149a1d66de6756b29eb565ae)
- Implemented permission updateing [`8820654`](https://git.odit.services/lfk/backend/commit/882065470adf15ee38a6a0047d42c9a9d864f12d)
- Second part of the action comment refactoring [`48bef8d`](https://git.odit.services/lfk/backend/commit/48bef8db608032375705b27aecc4c9ae7b75f655)
- Added Permission creation [`dc485c0`](https://git.odit.services/lfk/backend/commit/dc485c02eac36096011fa731bb85cce10c1bc4b3)
- Now with smooth access token refreshing [`6403e38`](https://git.odit.services/lfk/backend/commit/6403e386ab3a2ec5a994ad8f50fecdc73a8791c9)
- Now with cleaner participants in the responses [`145a08b`](https://git.odit.services/lfk/backend/commit/145a08b1b4f0c8c7a389b04d7ef033e23641a5b7)
- Added specific permission getting [`ebb0c5f`](https://git.odit.services/lfk/backend/commit/ebb0c5faca6fee18482a6552f10be18be5398b40)
- Switched runner orgs to the cleaner syntax via a update entity [`532b5a5`](https://git.odit.services/lfk/backend/commit/532b5a56a5226d524f864bb8e965b4f57483101b)
- Implemented permission deletion [`d4293c1`](https://git.odit.services/lfk/backend/commit/d4293c164db3478c5adc799e33b1d721e99b1972)
- Added auth to all endpoints [`744faba`](https://git.odit.services/lfk/backend/commit/744faba7eec3702b8cbd15fe51e7a248cc7cc19a)
- Fixed messages and comments for AuthErrors [`4ca85a1`](https://git.odit.services/lfk/backend/commit/4ca85a1f224ae48fc5c358e8e044b86f054c9d3d)
- Fixed the user-&gt;Group relation [`d670b81`](https://git.odit.services/lfk/backend/commit/d670b814a4d516f1874dc11dc3bccdd9c59c536c)
- Added a admin group with all permissions to seeding [`f25ae9b`](https://git.odit.services/lfk/backend/commit/f25ae9ba4f390c9ec71891ed326d47060dfb7133)
- Cleaned up the auth checker a little bit [`b9e9150`](https://git.odit.services/lfk/backend/commit/b9e91502cdbfa391805435cc2ea07a563894f3c7)
- Fixed some stuff not getting checked against null [`7a4238f`](https://git.odit.services/lfk/backend/commit/7a4238f1f7e54de2c0ec91b3dc67656c2f1f7ec8)
- Moved runners to the new put mechanism [`cc68948`](https://git.odit.services/lfk/backend/commit/cc68948a205b7e983f4c6f8e21b47d9b60c008bc)
- Added coments to the jwt creator [`428e2c3`](https://git.odit.services/lfk/backend/commit/428e2c38cef3ce34714a28ce78d18681d28b8bfc)
- added a simple health route [`cea5993`](https://git.odit.services/lfk/backend/commit/cea5993049b3c7098c33a2191db496656d72589e)
- User deletion now also delete's the users permissons [`ff3a5b4`](https://git.odit.services/lfk/backend/commit/ff3a5b4545d0359cd4af94229bb71c023888a860)
- Added the openapi security header to all routes that need some kind of auth [`cdfd0e0`](https://git.odit.services/lfk/backend/commit/cdfd0e0d64ae469b0ecfde353834b89364708b28)
- Added permission deletion on group deletion [`9dc336f`](https://git.odit.services/lfk/backend/commit/9dc336f0bbe3708201c1745f55f8e00f4a82557f)
- Added comments and formatting to the auth checker [`595a921`](https://git.odit.services/lfk/backend/commit/595a9213c199f5bd0274c8dde382845f308e1567)
- Code + Comment cleanup for the middlewares [`a88c038`](https://git.odit.services/lfk/backend/commit/a88c0389c1dc6862fe1a10b03c1345a1196869c5)
- Added class validation for the enum [`2240a45`](https://git.odit.services/lfk/backend/commit/2240a45a91c7597cae154cad0672784965c1cbe6)
- Reverted simplification that created loops [`7d5f3b0`](https://git.odit.services/lfk/backend/commit/7d5f3b092f72de6cf97ee35735ece35c554ddc6d)
- Updated some nameing to fit with the rest of the models [`4a21c1f`](https://git.odit.services/lfk/backend/commit/4a21c1fb5cecaba4138dd2ae5df938b257683475)
- Fixed messages and comments for TrackErrors + spelling for some other errors [`75b6489`](https://git.odit.services/lfk/backend/commit/75b6489f8dc91c0c268bf46158ccf5375cfa674d)
- Fixed messages and comments for RunnerOrganisationErrors [`37afc10`](https://git.odit.services/lfk/backend/commit/37afc10e44b4beed4563bd67bbba0fbbe42c1c75)
- Moved permissions to the new put mechanism [`b2bd617`](https://git.odit.services/lfk/backend/commit/b2bd6173a5b2c2fab5a259e0136486aeb92fd833)
- Moved runner teams to the new put mechanism [`24de82f`](https://git.odit.services/lfk/backend/commit/24de82f6dff1ff07cab5b5a851519a290b642266)
- Reimplmented the old permission checking system [`6237e62`](https://git.odit.services/lfk/backend/commit/6237e62a03a6d35beed78c4283b82c26d0753ce9)
- Updated loader comments and descriptions [`43a4f11`](https://git.odit.services/lfk/backend/commit/43a4f1118da324016f9038451484f3b8e6764729)
- Fixed messages and comments for RunnerTeamErrors [`389f634`](https://git.odit.services/lfk/backend/commit/389f6347c367c04e8e6b45cf42f2d54f1bc28084)
- Added toString for permissions [`445e96d`](https://git.odit.services/lfk/backend/commit/445e96dcdf273cb67724ebce86b2eb9bd4155085)
- Jwt's now feature group permissions and permission deduplication [`d742ccd`](https://git.odit.services/lfk/backend/commit/d742ccd581fc803663d90916365d60b0c7caccd5)
- Added missing username property to the responseuser [`cf583a2`](https://git.odit.services/lfk/backend/commit/cf583a22fad8de5967bd0a1be93a693a935ef1c1)
- Shoothed out variable nameing scheme [`1d54fb0`](https://git.odit.services/lfk/backend/commit/1d54fb085b43aaa9584a9998a2381fd49bec0040)
- Fixed messages and comments for UserErrors [`ee76f1c`](https://git.odit.services/lfk/backend/commit/ee76f1c0e8d9f93a9a98871fbfeedbc55fc0cbc1)
- Formatting implemented for @philipp [`a0a08f7`](https://git.odit.services/lfk/backend/commit/a0a08f7724e64c05e3a6bec74071d2a0f74b8f7e)
- Added additional targets and actions for permissions [`e25fc79`](https://git.odit.services/lfk/backend/commit/e25fc795fe006b27b64199868fb928b94851f4cf)
- Now with duplication avoidance [`6a7e8cc`](https://git.odit.services/lfk/backend/commit/6a7e8ccc37a05a2745ff85d785e6ceb9a180c71b)
- Code + comment cleanup for the enums [`a03f1a4`](https://git.odit.services/lfk/backend/commit/a03f1a438d1e15cb68015a0a90c7e9ebbc2def95)
- Code + comment cleanup for the seeds [`a85d524`](https://git.odit.services/lfk/backend/commit/a85d52437b7e448c8e35741eb71ed28ab3147f3b)
- Fixed messages and comments for UserGroupErrors [`2199cb0`](https://git.odit.services/lfk/backend/commit/2199cb0aef340034644d7b9204a215e539fd6005)
- Fixed messages and comments for PermissionErrors [`c1d784e`](https://git.odit.services/lfk/backend/commit/c1d784e29c80b71a499d5bdd08b897561e235979)
- Formatting #6 [`1a9c860`](https://git.odit.services/lfk/backend/commit/1a9c860188dda598582d01ba5c39b36cc33f4d55)
- Added tracks/get as test-route for auth [`b21dd6f`](https://git.odit.services/lfk/backend/commit/b21dd6f0c0dff656c7b1d2acc4142a5cf44c66dc)
- Fixed messages and comments for RunnerErrors [`5de81ad`](https://git.odit.services/lfk/backend/commit/5de81ad0939cd870ff960c303930147f81144781)
- Fixed wrong error type [`b55d210`](https://git.odit.services/lfk/backend/commit/b55d210affbe19a07d1859064a8d58f9562d3319)
- Renamed function to better reflect it's function [`3850bd9`](https://git.odit.services/lfk/backend/commit/3850bd968173fb2a701ff02327c38a662ee0c40b)
- Bugfix for bs file names [`23758e7`](https://git.odit.services/lfk/backend/commit/23758e7a91ddccef2b37b6b0c20b257de7681764)
- removed useless deletes [`adec2bc`](https://git.odit.services/lfk/backend/commit/adec2bcc5b56fe7139eaada4f66398f20ae9212f)
- Fixed import for linux [`631310f`](https://git.odit.services/lfk/backend/commit/631310f1589511803bd2044fc0f021e7f53226a7)
- Updated the openapi json path for the ci testing script [`0b4d30b`](https://git.odit.services/lfk/backend/commit/0b4d30b3f3760d0e926c3ce4d58def6ff22f5674)
- fixed typo [`5d75f70`](https://git.odit.services/lfk/backend/commit/5d75f70296670b08f425e29b9159aaa7344a5fc8)
- Updated the openapi descriptions for all status routes [`84b97be`](https://git.odit.services/lfk/backend/commit/84b97bee8d19ab87b6485488ed8c2b4781b88f0c)
- Removed the user disableing [`9458b77`](https://git.odit.services/lfk/backend/commit/9458b774ea1abd7d2c10676264e715ee5e44b49f)
- Fixed weired query behaviour [`8d860cb`](https://git.odit.services/lfk/backend/commit/8d860cb2e109bcee81d0de60cdbbcbe9076a8fde)
- Set reset token expiry to 15 mins [`4868545`](https://git.odit.services/lfk/backend/commit/48685451bead5972a95dec9abd03f9b5285454ed)
- Disabled the x-served-by and x-powered-by Headers [`19422ed`](https://git.odit.services/lfk/backend/commit/19422edbaee15751c37d926e3b31b15acba29984)
- Small bugfix [`0ef6d9c`](https://git.odit.services/lfk/backend/commit/0ef6d9cc4865a5eebd9458cdd51f8aff9f3590d2)
- Added a missing poiunt/exclamation mark [`de91d49`](https://git.odit.services/lfk/backend/commit/de91d491e561881ba5a54d920dba28fe486fce61)
- Moved tracks to the new put mechanism [`fbe2b35`](https://git.odit.services/lfk/backend/commit/fbe2b358bd349456f2f4ac3413ab8b82d6f4bbe3)
- Moved usergroups to the new put mechanism [`18ede29`](https://git.odit.services/lfk/backend/commit/18ede29ea544000abd9bffdfa35d82a62b6733a4)
- Fixed some weired toString beviour [`ec4d751`](https://git.odit.services/lfk/backend/commit/ec4d75128b284fb5530dc76b7ae99df3efcaba75)
- Bugfix for bs file names [`c7fd059`](https://git.odit.services/lfk/backend/commit/c7fd0593fb5cce2b2ae39789073436d674a56825)
- Fixed messages and comments for RunnerGroupErrors [`82ced34`](https://git.odit.services/lfk/backend/commit/82ced34750222f733e30ab42fa6cabe00c6dbba0)
- Manual overwrite [`c3e3c6b`](https://git.odit.services/lfk/backend/commit/c3e3c6bed170f2c3002895fc06a4e0244f976b71)
- Merge pull request 'feature/17-automated_tests' (#21) from feature/17-automated_tests into dev [`57f6775`](https://git.odit.services/lfk/backend/commit/57f67751400510731811c2a2ecd62539172bd9f3)
- Fix for the 404 in the swagger doc [`bd07763`](https://git.odit.services/lfk/backend/commit/bd0776345501cab1634f29dcca36b821d675f789)
- Fixed runner get test [`e223c06`](https://git.odit.services/lfk/backend/commit/e223c060d4665556cf28d91a3e4fe85831e93602)
- Removed console logs [`7fe9480`](https://git.odit.services/lfk/backend/commit/7fe9480c9408d1f3b51fe22c4fbf530e9cde0bf2)
- Runner update tests now run clean [`6eee80d`](https://git.odit.services/lfk/backend/commit/6eee80d3577d5da218ace78710904dc8523ebfe3)
- future proved the group update failture [`6e12b01`](https://git.odit.services/lfk/backend/commit/6e12b014e706b96e3e3b1f2d39276f417a537157)
- Replaced a console log with a consola.error [`aaeef4a`](https://git.odit.services/lfk/backend/commit/aaeef4a27e3980204c4cc300d1f748b19162af62)
- Fixed optional property [`bc80be9`](https://git.odit.services/lfk/backend/commit/bc80be947d073296010d13c9ec1b225e45f8869b)
- Adjustes responsecode [`80ef7e8`](https://git.odit.services/lfk/backend/commit/80ef7e8c3ab8fc3f2db4d0463b1e5f09d5ba17d0)
- Added squlite jurnal tmp file to the gitignore [`3e961e3`](https://git.odit.services/lfk/backend/commit/3e961e34a1a28f1a02bd547eec180ad51cb1ff38)
- Removed sqlite jurnal (however it managed to end up here) [`ff6a4ea`](https://git.odit.services/lfk/backend/commit/ff6a4eaca1d37f1d14a582d4ee4b1a0c99abd3ff)
- Merge pull request 'latest work' (#20) from dev into main [`e3a5b41`](https://git.odit.services/lfk/backend/commit/e3a5b41b5eca8fc7025f31033d0ab96685ef739d)
- Added more basic tests for the runner orgs [`db5feb0`](https://git.odit.services/lfk/backend/commit/db5feb00cc48e475c8575f08535ceaba93883733)
- Added import-action classes [`a8ec014`](https://git.odit.services/lfk/backend/commit/a8ec0142b06eb367e496d395a74105cd7df77d06)
- Pulled out some linguini-esc code [`5dc9edf`](https://git.odit.services/lfk/backend/commit/5dc9edfe40fe0898946861430bda15769e67fdb8)
- Added status codes [`3aae8f8`](https://git.odit.services/lfk/backend/commit/3aae8f85c430115b0a9122881821415261c10b5d)
- Working csv import [`03b7e34`](https://git.odit.services/lfk/backend/commit/03b7e346ab52a2f70b39f8784d8525a7f4da9123)
- Removed the bs code [`ff178f9`](https://git.odit.services/lfk/backend/commit/ff178f9d777f0da0a60d5bad5328222155aae214)
- test drone pipeline [`8d00487`](https://git.odit.services/lfk/backend/commit/8d004873596d07ee03295437bbd27be8647bcf5d)
- Added downstream trigger [`0c6f3d1`](https://git.odit.services/lfk/backend/commit/0c6f3d1f12397666562ea8e630abcecc059d6ffe)
- Now organisations and teams can import runners [`71228fb`](https://git.odit.services/lfk/backend/commit/71228fbf33a59e9d1d77ee8415c43a69a66ac010)
- Added rawbody if needed [`b9fd237`](https://git.odit.services/lfk/backend/commit/b9fd2379f4bc83265441c08814d85f359c3cd11b)
- Added responseschemas and content types [`15ed9f5`](https://git.odit.services/lfk/backend/commit/15ed9f58d5aa22ba7d53f1e54e6f45f72ec01948)
- Fixed the dynamic class creation [`cad30c7`](https://git.odit.services/lfk/backend/commit/cad30c7f6326d288173223e77df59f90696576da)
- Added endpoints for runner import by json and csv [`2e4a4f1`](https://git.odit.services/lfk/backend/commit/2e4a4f1661093ad8816aca44684ea4a97a8816d7)
- Added a basic import controller [`1b1f8f2`](https://git.odit.services/lfk/backend/commit/1b1f8f2b09bc72b90c0c12bbd1cc5a68a1290cc3)
- Removed the test pipeline [`fcb3e35`](https://git.odit.services/lfk/backend/commit/fcb3e35b29d23421f06bb052c5609aa858533eb9)
- Runners can now be imported into a org [`97494ae`](https://git.odit.services/lfk/backend/commit/97494aeaf71d258980256592ae4406f2a2be0bb9)
- Cleaned up relation types [`eb9473e`](https://git.odit.services/lfk/backend/commit/eb9473e230e8737b624b5084b31c73aa99bc4e66)
- Expanded API Decriptions [`9db4344`](https://git.odit.services/lfk/backend/commit/9db4344153ebd8965e2639b4bb008e5e86893055)
- removed the lib generation part [`ec69f6c`](https://git.odit.services/lfk/backend/commit/ec69f6caf3a9ba9e72720b1046e2ce4a30291a96)
- Abstracted a little bit more for potential company runner import [`1b59d58`](https://git.odit.services/lfk/backend/commit/1b59d58c6023803a5b729b0a274c6d17013219d7)
- Updated nameing to fit the usual scheme [`476afc6`](https://git.odit.services/lfk/backend/commit/476afc6a997b68221708c0c2afbd735a5603efe7)
- Marked csv import as not implemented [`30952aa`](https://git.odit.services/lfk/backend/commit/30952aa14f12f7af59780c9c5d2358764db7ac0e)
- Fixed typo [`388fc6b`](https://git.odit.services/lfk/backend/commit/388fc6ba6a62088d773d5e1afd299ee78b47d573)
- Fixed path [`c90f9f1`](https://git.odit.services/lfk/backend/commit/c90f9f1dd44d78b828b2d084c66f1d5cfcf7a8cf)
- Cleanup [`3e6c7b6`](https://git.odit.services/lfk/backend/commit/3e6c7b630258181c8805c8d7f289d4771ea2a017)
- Push [`d0c5323`](https://git.odit.services/lfk/backend/commit/d0c5323cb6e2e62a09ae3e713fd96cb98618bd5a)
- I just need to trigger sth [`4705b5a`](https://git.odit.services/lfk/backend/commit/4705b5a0b4d3e925829cae56cf095c21cb6db0b4)
- fixed command order [`20ec6e0`](https://git.odit.services/lfk/backend/commit/20ec6e0cd6da23579943106b4d5b4ca1ca7dbe92)
- fixed duplicate name [`e10a394`](https://git.odit.services/lfk/backend/commit/e10a3947ba8afc5bf19ec01c8e5329f4551f904b)
- Removed useless console.log [`4801e01`](https://git.odit.services/lfk/backend/commit/4801e010b4e7327507f7465f4b86d1c57cb3c369)
- Merge pull request 'feature/31-lib_generation' (#32) from feature/31-lib_generation into dev [`39b932a`](https://git.odit.services/lfk/backend/commit/39b932a81c22fd54fbf9ae059b340eb16c9a70e4)
- Moved to a "cleaner" directory structure [`e8727ca`](https://git.odit.services/lfk/backend/commit/e8727ca922475f2a7f32ee0785625a3612c21c0e)
- More dynamic creation of objects [`4352910`](https://git.odit.services/lfk/backend/commit/4352910d54a74773499704070f35adb95e542ff6)
- Create models now feature the createparticipant abstract [`56202ec`](https://git.odit.services/lfk/backend/commit/56202ec3094444ec60170953aee5829e2a4ffba1)
- Added basics for the runner team controller [`ca917b0`](https://git.odit.services/lfk/backend/commit/ca917b057767c341f7d0e2f2d62603df9d291a3b)
- Moved Create Runner to it's own file [`9e3ee43`](https://git.odit.services/lfk/backend/commit/9e3ee433d2571110004d797381a872348075a317)
- 🚧 UserGroups [`3275b5f`](https://git.odit.services/lfk/backend/commit/3275b5fd8008b0c10601c33844b6d35ab39d4972)
- User + UserGroup [`48e28e7`](https://git.odit.services/lfk/backend/commit/48e28e7b7a19e1ad66ba12461826676bd9074a58)
- Cleaned up a load of relations and optional stuff [`a1105f0`](https://git.odit.services/lfk/backend/commit/a1105f06abf28d72b691c9431fd54083a82d8318)
- Added basics for runnerorg controller [`a35e6d0`](https://git.odit.services/lfk/backend/commit/a35e6d0a9f19dc7dbde3c867b840276416eac9f6)
- Now with even more inheritance and fancy stuff: RunnerResponses now get their information from participant responses [`b480912`](https://git.odit.services/lfk/backend/commit/b480912bd8c643391865da4c7f4bfeb796315d7a)
- Runnerteams now with resolving relations and response types :O [`a437ada`](https://git.odit.services/lfk/backend/commit/a437ada3b3cee64c69548cf0cd1e93d4fa2495b3)
- Reverted to id based relation setter [`65b2399`](https://git.odit.services/lfk/backend/commit/65b2399eaa83ae97a8ade0f4eef5a17f15773fcb)
- Fixed the cirvular import BS [`ac0ce79`](https://git.odit.services/lfk/backend/commit/ac0ce799f950dac194192177329d07c802feb457)
- New response model for runners [`8beb658`](https://git.odit.services/lfk/backend/commit/8beb658bccb754b73ff7cb39d9d1e18e33cde0dd)
- Now with working runner orga controller including responses [`7b08489`](https://git.odit.services/lfk/backend/commit/7b084895334431445ae2c038bd086c8833a8e530)
- All things deletion for runner* now are clean af and cascadeing [`45675b0`](https://git.odit.services/lfk/backend/commit/45675b06994d6754fa0106f46353b48041aaba13)
- Error cleanup [`33b3bcb`](https://git.odit.services/lfk/backend/commit/33b3bcb8c2eaec3dd9d92a2f92d1e561920b97a9)
- Error cleanup [`1ae466a`](https://git.odit.services/lfk/backend/commit/1ae466a6f4618ca41beaffb64a673a5a66ca4901)
- Created basic runner controller [`701207e`](https://git.odit.services/lfk/backend/commit/701207e100c7b7b71a4791a7594bd346a4618066)
- 🚧 UserController [`d556e9b`](https://git.odit.services/lfk/backend/commit/d556e9ba190222c615b2b7567bd30fece0c08c5c)
- Working(tm) implementation of group and team deletion [`795599f`](https://git.odit.services/lfk/backend/commit/795599fd388150a07c959cb3fbed6f676d3db790)
- Added basic creation class [`7bbf769`](https://git.odit.services/lfk/backend/commit/7bbf769bddaa92ec263d06adb5ccd3199feb8bc4)
- A step towards inheritance for the create* objects relating to runner groups [`5d7d80d`](https://git.odit.services/lfk/backend/commit/5d7d80d2e75e0cdf68eea458b97610e6e2322087)
- Switched to using a response model for tracks [`9130333`](https://git.odit.services/lfk/backend/commit/913033373be3ece9bed301f787e7d7036042ca26)
- 🚧 better/ more errors [`a0e6424`](https://git.odit.services/lfk/backend/commit/a0e6424d482c54d77a887d8b91c81a6f39b51f59)
- 🚧 starting work on LogoutHandler [`675717f`](https://git.odit.services/lfk/backend/commit/675717f8ca495898e87fb73dca12249065301fb0)
- 🚧 basic AuthErrors 🔒 [`b9bbdee`](https://git.odit.services/lfk/backend/commit/b9bbdee82654b5cea26fdd97b38df2c0829ec1e6)
- 🚧 Permissions [`1cf35f0`](https://git.odit.services/lfk/backend/commit/1cf35f016b0aeb0f1224648b301044b2ea76dc60)
- Added comments and decorators for existing create models [`330cbd5`](https://git.odit.services/lfk/backend/commit/330cbd5f57a9f16cbf277ea57fadefcb6d24e0fa)
- Updated relationships to be nullable [`4c80ab1`](https://git.odit.services/lfk/backend/commit/4c80ab1516d11ec069fd79e06cdf050712647090)
- Impementing more methods for the runner orgs [`0c6528b`](https://git.odit.services/lfk/backend/commit/0c6528bdc5eb314399bc722087e3b907f0f59ff8)
- Emergency fix: Switched to table inheritances [`a895622`](https://git.odit.services/lfk/backend/commit/a8956223c2c70b810b4ec9dea09900b30b963a24)
- Cleaned up the createUser a little bit [`a42595b`](https://git.odit.services/lfk/backend/commit/a42595bd15ec7646b5b18758aee4c178857e1427)
- 🚧 CreateUser model [`d2c826c`](https://git.odit.services/lfk/backend/commit/d2c826c7c9a8b79ff5ab6268865a26791b36c2c2)
- Moded track controller related models to a new file [`da4597f`](https://git.odit.services/lfk/backend/commit/da4597fa62dd85b0496aaa6d9407a263b5291912)
- implement proper jwt checking in authchecker [`76e19ca`](https://git.odit.services/lfk/backend/commit/76e19ca28dc183f698049080b62e88f9feddf036)
- first part of the user class cleanuo [`dadaacf`](https://git.odit.services/lfk/backend/commit/dadaacfaaeed6f4cc1a1c01abc6428601708fbcb)
- 🚧 UserAction [`82ca8f4`](https://git.odit.services/lfk/backend/commit/82ca8f48dc8cd5438ba1eeab7b222b1df60355df)
- 🚧 User + Permissions [`a78bbb1`](https://git.odit.services/lfk/backend/commit/a78bbb1de5765f6339440663bb884367b6d3bfdf)
- Smoothed out the participant creation process regarting addresses [`975d30e`](https://git.odit.services/lfk/backend/commit/975d30e411c580d8c6a7e6c87f7d0187b97070f1)
- Updated a bunch of optional collumns to be nullable [`aa565c6`](https://git.odit.services/lfk/backend/commit/aa565c6b344f62521b9b53575ffce36e8b77af74)
- 🚧 basic JWTAuth Middleware [`1f3b312`](https://git.odit.services/lfk/backend/commit/1f3b31267598e1b9e97cf8bed542def68bfd99f6)
- Cleanup: Renamed the creation folder to the more fitting "actions" [`0e92444`](https://git.odit.services/lfk/backend/commit/0e924449d60c994c29b95abba675309e31c04383)
- temp commit: added first part of create runner [`3ade01d`](https://git.odit.services/lfk/backend/commit/3ade01def931fbb7feb1a1fe8b8b8e29a22b0a58)
- Fixed bugs concerning posts [`aca13f7`](https://git.odit.services/lfk/backend/commit/aca13f730865e3660bdc14574af71d1ccfd7e5ad)
- 🚧 Permissions [`1d57264`](https://git.odit.services/lfk/backend/commit/1d5726492286f21adcc6064c62159de8d134538d)
- 🚧 starting work on RefreshAuth [`2f90275`](https://git.odit.services/lfk/backend/commit/2f902755c47af829ae3eb6447a5cabe3c0017cf4)
- CreateAuth model [`a7afcf4`](https://git.odit.services/lfk/backend/commit/a7afcf4cd1ab60f856c299eaeace7fe5f3ec3b14)
- working on AuthController + CreateAuth [`6cb0109`](https://git.odit.services/lfk/backend/commit/6cb01090d0f640d25728495f0a80c756ee43e985)
- Still broken distance, we'll fix this together [`c30922e`](https://git.odit.services/lfk/backend/commit/c30922e3250ad2a0510ab8fd296e364943994eba)
- 🚧 better uuid + starting hashing implementation [`f162944`](https://git.odit.services/lfk/backend/commit/f1629440feae3a49ab17ec7d29b709ff392d6988)
- basic jest + typescript support [`8ae5cea`](https://git.odit.services/lfk/backend/commit/8ae5cea631a9c3097c7fbf7da6ce0cb1f347c4b4)
- Part 1 of the relation fix [`c53e94d`](https://git.odit.services/lfk/backend/commit/c53e94d20517837b871f1649ac3fe850e9658c9c)
- 🚧 UserAction relation [`f50e7f0`](https://git.odit.services/lfk/backend/commit/f50e7f0b3ac49b6f728099e9ed1f1ccb0d9e78ff)
- Added basic runner related errors [`980ac64`](https://git.odit.services/lfk/backend/commit/980ac646889690ae773de75b984dc9eec4e67bb1)
- 🚧 CreateAuth - credential validation [`bd0c7ce`](https://git.odit.services/lfk/backend/commit/bd0c7ce04213a297cf13f85ac63de34785796306)
- 🐞 fixed UserGroupNotFoundError throwing ✅ [`d4753a0`](https://git.odit.services/lfk/backend/commit/d4753a02d4fa04beaf0794f1b15debb38c7827b9)
- CreateUser [`b101682`](https://git.odit.services/lfk/backend/commit/b101682e3cd23ea501ca8c6036084c0d4aef2644)
- Added more runner errors [`cb5d5e5`](https://git.odit.services/lfk/backend/commit/cb5d5e546d0232e771495a3c5d140ac9531b7743)
- Deletes now work based on EntityFromParam [`8870b26`](https://git.odit.services/lfk/backend/commit/8870b26ce63d6294567863c76d9dcfccd18e681d)
- Cleaned up the createUserGroup a little bit [`109e145`](https://git.odit.services/lfk/backend/commit/109e145a1970952a2375df9f1f6cf57f056982ff)
- Fixed amount calculations [`afef95e`](https://git.odit.services/lfk/backend/commit/afef95e14ea1e77144a9cd0ccbf9b02e4d63b4f4)
- 🚧 CreateUserErrors model [`983fa41`](https://git.odit.services/lfk/backend/commit/983fa41cba3a4d537ab742a149b86d6c6a87f5bf)
- Cleaned up the loaders [`f58a715`](https://git.odit.services/lfk/backend/commit/f58a715c45ae5e8ea95041816d78991498461b94)
- implemented refreshcount increase [`13d568b`](https://git.odit.services/lfk/backend/commit/13d568ba3f9a3c1035a2dd48509bee2567bd06f3)
- 🚧 RefreshAuth - refresh tokens now working ✅ [`51addd4`](https://git.odit.services/lfk/backend/commit/51addd4a31e63bdaab64b422f35432571af7da23)
- better errors [`c0c9505`](https://git.odit.services/lfk/backend/commit/c0c95056bf0401de0c77032928547c13982c932c)
- basic Auth model [`b0a24c6`](https://git.odit.services/lfk/backend/commit/b0a24c6a74d9a20a4ec5c562ece6baa3811cd00a)
- first accesstoken generation [`c33097f`](https://git.odit.services/lfk/backend/commit/c33097f7738da74cbd50f3cedd15e1ae173a7e3e)
- 🚧 AuthController with multiple endpoints [`28c2b86`](https://git.odit.services/lfk/backend/commit/28c2b862f0a070323ea7eb1d2c0a53c71979e46f)
- Now all runner endpoints return a response runner [`0564135`](https://git.odit.services/lfk/backend/commit/056413560ec29cb8d8a1f7a94528d84025e994c1)
- 🚧 CreateUser group search + adding [`5b7f3ae`](https://git.odit.services/lfk/backend/commit/5b7f3ae12f3f8749aa637d18763cf5f5df8001eb)
- 🚧 reference new Errors from CreateUser [`1efca47`](https://git.odit.services/lfk/backend/commit/1efca4733617806363e51d013590c885b9b13405)
- 🚧 Permission [`e4d5afb`](https://git.odit.services/lfk/backend/commit/e4d5afbebe7179c926a0625fd11d17f5285e55a8)
- 🧹 cleanups [`e5b605c`](https://git.odit.services/lfk/backend/commit/e5b605cc55715e92885ddb1fefe930b79449c430)
- trying to fix UserGroupNotFoundError (false/not triggering) [`451d0c9`](https://git.odit.services/lfk/backend/commit/451d0c92dddd4e56626eca8c8b9e6728b6427a23)
- 🚧 Scan.ts - secondsSinceLastScan [`9395813`](https://git.odit.services/lfk/backend/commit/9395813f5aafb282a50b8e2313a3022737e7decc)
- 🚧 UserNotFoundOrRefreshTokenCountInvalidError [`093f6f5`](https://git.odit.services/lfk/backend/commit/093f6f5f789d58d54f325fcf02fbd1ab3cf09a95)
- Turned the abstracts into entities [`5bf978d`](https://git.odit.services/lfk/backend/commit/5bf978d32dc8e9d49d9fcff0adeb75c8ee50ad03)
- basic RefreshAuth checking [`126799d`](https://git.odit.services/lfk/backend/commit/126799dab98a8866be2e3f3812b7a76a50d0812d)
- first jwt generation [`6ae0c1b`](https://git.odit.services/lfk/backend/commit/6ae0c1b95526530968198ebf78b10ab1e71a8caa)
- UserNotFoundError [`d803704`](https://git.odit.services/lfk/backend/commit/d803704eeebc5d5a188cb9fd5c9afd6882579fd3)
- Added Comments. [`6d81fc1`](https://git.odit.services/lfk/backend/commit/6d81fc13095b2d96b6cd864f952242749567bbab)
- Added defaults back in [`932e782`](https://git.odit.services/lfk/backend/commit/932e782a14454a05aa59f9b76c7c9638aa440385)
- Cleaned up relations [`dd5f448`](https://git.odit.services/lfk/backend/commit/dd5f4488be9cf5df6fae740f60fb5597382ca984)
- TrackController now also deletes based on a entityfromparam [`0e3cf07`](https://git.odit.services/lfk/backend/commit/0e3cf07b9147f32cf3da40e764fea19fb1f52c58)
- Little bugfix [`9c63a34`](https://git.odit.services/lfk/backend/commit/9c63a34fe13ffed8e35371c42617a43814f7d16c)
- integrate UserNotFoundError [`6244c96`](https://git.odit.services/lfk/backend/commit/6244c969afac300183339aaf0dac77d213947d2b)
- Added basic openapi security scheme for the bearer auth header [`5a4a6cd`](https://git.odit.services/lfk/backend/commit/5a4a6cdcefd96ddc413232841af8b596580d941f)
- 🚧 JwtNotProvidedError [`d23ed00`](https://git.odit.services/lfk/backend/commit/d23ed002b24ee29b1bfca98b7f5b3eb3ce47c2db)
- Now throwing errors even faster [`179add8`](https://git.odit.services/lfk/backend/commit/179add80f480cd10f2951d8f7077164da840d4d0)
- Cleaned up some relations for users [`74ee77f`](https://git.odit.services/lfk/backend/commit/74ee77f814c269718cb99847e4a43600fc52b41f)
- Cleanup: Renamed Responses to represent their response nature [`61e7ae4`](https://git.odit.services/lfk/backend/commit/61e7ae4f86e0453c0efa15f151271d674ea0a44d)
- remove routes/v1/test [`740d7f1`](https://git.odit.services/lfk/backend/commit/740d7f10f5ede09846d5a4d3a482bf750cb13698)
- 🚧 CreateAuth - basic jwt creation with user details [`a0fe8c0`](https://git.odit.services/lfk/backend/commit/a0fe8c0017d4f594d57e0d3c00305077874f5aa0)
- 🚧 User entity - add @Column [`7f3358d`](https://git.odit.services/lfk/backend/commit/7f3358d284889687aef92a4dbd562ec2ccb4c499)
- authchecker - use new custom Errors [`f251b7a`](https://git.odit.services/lfk/backend/commit/f251b7acdbc8e277971cf97cfe619f441ac0362a)
- Attention: Broken [`32c4270`](https://git.odit.services/lfk/backend/commit/32c4270dff0c3e1a9703e72b8b180a7289d413d4)
- 🚧 User.ts - optional phone number [`8d1dd78`](https://git.odit.services/lfk/backend/commit/8d1dd78194be42c837934f0804287624ff7079b9)
- Fixed user&lt;-&gt; Group relationship [`4a9fd57`](https://git.odit.services/lfk/backend/commit/4a9fd57356132b2fce539724c2faecdc6f160e7f)
- sample json validation [`431fd60`](https://git.odit.services/lfk/backend/commit/431fd608a6945b0fbed932f122af5e6e5c8e8cd8)
- remove sampletoken generation [`5c25948`](https://git.odit.services/lfk/backend/commit/5c259484ee5a4063bcf71bd847413014ec848a00)
- 🚧 CreateAuth now returns a sample jwt [`d46ad59`](https://git.odit.services/lfk/backend/commit/d46ad5954676e73ab3c77f2d84c87b22088f4e71)
- 🚧 User - mark columns as unique [`b8bc39d`](https://git.odit.services/lfk/backend/commit/b8bc39d691d10c13e60dc7bd3709d413dcf8b8b6)
- Formatting [`af75d6c`](https://git.odit.services/lfk/backend/commit/af75d6cfec13131f2980cc83866eb3d6b024b9e0)
- Added missing getter [`84dd1fe`](https://git.odit.services/lfk/backend/commit/84dd1fe4a5871e1bf3d5510bb92d826d519dd6ad)
- 🧹 clean up CreateAuth [`1850dd5`](https://git.odit.services/lfk/backend/commit/1850dd542d564e91cf55ac9fcdf7902091969163)
- ⚙ tsconfig - includes + excludes [`8ef6f93`](https://git.odit.services/lfk/backend/commit/8ef6f933a745214ba02a12cf778eb36bc04a0891)
- Fixxed dockerfile [`ee35da7`](https://git.odit.services/lfk/backend/commit/ee35da7342de601650052eae13bc773831ea9ad7)
- 🚧 AuthController - add proper response schemas [`0d21497`](https://git.odit.services/lfk/backend/commit/0d21497c2fd42602d253067d6f6d42fe7cfee5b5)
- note on refreshtokencount checking [`e5f65d0`](https://git.odit.services/lfk/backend/commit/e5f65d0b801934c0ac3a5d898aa7d8fdee4a35c4)
- class-validator on Auth model [`c4b7ece`](https://git.odit.services/lfk/backend/commit/c4b7ece974fe548e68415b49fc8cce913ef6cd92)
- 🚧 move to uuidV4 [`091b455`](https://git.odit.services/lfk/backend/commit/091b455460dfe79276305c533170f5d153d78b73)
- Shortened db call [`c4f0202`](https://git.odit.services/lfk/backend/commit/c4f02023b949312a8e09d2fbd1c4d036816f30e0)
- ⚙ vscode setting - import organize + fix [`92bafb0`](https://git.odit.services/lfk/backend/commit/92bafb0cf457b50a19f0f965c3a7e241974e750d)
- ⚙ settings - standard imports + quote formatting [`684e7c4`](https://git.odit.services/lfk/backend/commit/684e7c4ddbb10e88ead1d33e93f97fc7dcb0db25)
- add response schemas to AuthController [`8c229db`](https://git.odit.services/lfk/backend/commit/8c229dba82ebad03a22231ac821d985a49b45611)
- 🚧AuthController - add all Error response schemas to post [`2a1b65f`](https://git.odit.services/lfk/backend/commit/2a1b65f4249defb535f8464cf5ec3a63e4dd44bb)
- ⚙tsconfig - no sourcemaps [`ffc3150`](https://git.odit.services/lfk/backend/commit/ffc31506e36b9c0b22cc7cc66e6ab5f06c4a64cf)
- 🚧 RunnerCard EAN [`33d159d`](https://git.odit.services/lfk/backend/commit/33d159dbcf49b6dd0e87e85d0a98042e7d5f34a8)
- CreateUser - remove uuid from params [`a7854fb`](https://git.odit.services/lfk/backend/commit/a7854fbe81b1b8ed1c0df7927e3b8da74ad0fab0)
- clean up jwtauth [`c5c3058`](https://git.odit.services/lfk/backend/commit/c5c3058f3d20aa898bd67c02baa3d995321e0ab5)
- 🔒argon2 password hashing w/ salt [`ce2c38e`](https://git.odit.services/lfk/backend/commit/ce2c38e1882882da13e631fdde62a79b879d13b6)
- 📏 fit to new structure [`ae24c33`](https://git.odit.services/lfk/backend/commit/ae24c3394b4243065119535d24252a66cce2cdeb)
- Fixed missing child declaration [`5bbf522`](https://git.odit.services/lfk/backend/commit/5bbf522362a8985e93b16884369f5859ab72d32a)
- Now creating runner orgs again [`ec2ff98`](https://git.odit.services/lfk/backend/commit/ec2ff981b217e460e4547b57a1ad069059d13b7d)
- Removed console logs [`21ad622`](https://git.odit.services/lfk/backend/commit/21ad622c10712ae36fb0c5e1519fc3ecba6341ae)
- Now returning the saved runner [`084691c`](https://git.odit.services/lfk/backend/commit/084691c294ff3bf4d09ef634ce2d0d81ef93c50d)
- added await (async stuff und so) [`7e4ce00`](https://git.odit.services/lfk/backend/commit/7e4ce00c30acd4eaa188fdee524cee1c19948faf)
- 🚧 CreateAuth - use proper refreshTokenCount [`82f3118`](https://git.odit.services/lfk/backend/commit/82f31185a1aaba1cb3d4e3812ff65ef62d042e4c)
- 🚧 CreateUser - add group as object instead of nested array [`a7cf86e`](https://git.odit.services/lfk/backend/commit/a7cf86eae41991956db6b48f8c70ed0d6cec374a)
- Fix [`a3b79ef`](https://git.odit.services/lfk/backend/commit/a3b79ef21df1ce96f0b301097cc0122eef06bfbd)
- ⚙🐞 VSCode formatting broke code by removing all unused [`5e0fcf1`](https://git.odit.services/lfk/backend/commit/5e0fcf1f4ab8ac7929b69cbbf117bbd49edc1407)
- Added missing import [`e3133e0`](https://git.odit.services/lfk/backend/commit/e3133e0d5eb70daf858a6b807970838db8fd0ef9)
- ⚙target: es2017 ▶ ES2020 [`9051b75`](https://git.odit.services/lfk/backend/commit/9051b7565cf3506ddecfdc0abc05e7266be450dd)
- 🐞 CreateRunner - optional orgId & teamId [`098699e`](https://git.odit.services/lfk/backend/commit/098699e09a4b2c1399c471149a3379645710274a)
- Merge pull request 'feature/11-new_classes' (#15) from feature/11-new_classes into dev [`7d9e003`](https://git.odit.services/lfk/backend/commit/7d9e003a6dc32a21214a32d21ced13bd33156b25)
- Initial commit [`80cb16c`](https://git.odit.services/lfk/backend/commit/80cb16cccde94664a16945e05063acfbdad0cad7)
- Added errors and fixed the create model [`b382f06`](https://git.odit.services/lfk/backend/commit/b382f0689bba58f9b731a7d63b44f9ba09b5d732)
- Added participant abstract class [`f350007`](https://git.odit.services/lfk/backend/commit/f350007ae5696a16ecb1994bf3b4be843781b91d)
- fixed auth parsing [`5f4aed2`](https://git.odit.services/lfk/backend/commit/5f4aed2f02b22799d3e043394641bc3ac549caf2)
- Added Runnergroup abstract class [`f999c41`](https://git.odit.services/lfk/backend/commit/f999c416c4367ddbb99fe19e443c1ce4867f5053)
- fixed component definition [`51ff9de`](https://git.odit.services/lfk/backend/commit/51ff9defc5c796ad895bf8ecfdaad2ec8bb35de0)
- Added differenciation between local and docker based testing/dev setup [`860b6c8`](https://git.odit.services/lfk/backend/commit/860b6c850daf5756ad1f97c111f77e5f21c80df0)
- Adjusted the comments for tsdoc [`f0a7cbb`](https://git.odit.services/lfk/backend/commit/f0a7cbbcae140fba469634ef79a63f677cb994c7)
- Added custom errors [`01542ae`](https://git.odit.services/lfk/backend/commit/01542ae6a8779703842fbd0114c8f3b049cd77b7)
- Added openapi style response schemas [`0e3ec4e`](https://git.odit.services/lfk/backend/commit/0e3ec4ebf9a70866b8b54e066f41a4460a361b2b)
- implementation details [`d85c126`](https://git.odit.services/lfk/backend/commit/d85c126c276a91996178ccf8b8e7a566d33dac69)
- Added Basic Scan interface [`abb7f7f`](https://git.odit.services/lfk/backend/commit/abb7f7f89452cdd44bbc5f34d377a9306684fc9b)
- Switched from implementing the "interfaces" as interface to abstract classes [`a2cf8d1`](https://git.odit.services/lfk/backend/commit/a2cf8d1f2c4a2087e2dd6c297bea1a46db4220f9)
- Changed nameing scheme for the abstract classes since we're not useing interfaces [`f8e1bf7`](https://git.odit.services/lfk/backend/commit/f8e1bf715b57788c16c8f8565bc20696c26b1499)
- Merge pull request 'Added our branch structure to the readme' (#10) from bugfix/readmeupdate into main [`96a99c4`](https://git.odit.services/lfk/backend/commit/96a99c4e3ba6910a5922f04fc543419f653384d6)
- Now using typeorm-routing-controllers-extensions for cleaner controllers [`2c29fe2`](https://git.odit.services/lfk/backend/commit/2c29fe29e8153f264ceb91b04ff95ac4883b3ca3)
- Added basic ignores [`186e172`](https://git.odit.services/lfk/backend/commit/186e172be79892e4f5b84eb76331b56621b1af85)
- Added basic ignores [`ba5a4cb`](https://git.odit.services/lfk/backend/commit/ba5a4cb2f22c79e30e1035b0d80caaf58564c73a)
- precommit hooks & file formatting [`595aacb`](https://git.odit.services/lfk/backend/commit/595aacb311c22e63a476579f0d4d95550c314940)
- move to module [`e29d59a`](https://git.odit.services/lfk/backend/commit/e29d59ac02f6d73aba5452cba6801898fe1900b9)
- Switched to using controllers via routing-controllers [`8cbcfe7`](https://git.odit.services/lfk/backend/commit/8cbcfe7fbb66b9de7b6193962ed11b32150aaa7c)
- Added the track scan class [`8b2d684`](https://git.odit.services/lfk/backend/commit/8b2d6840a861d44132740fa65128d45400ebd449)
- Added tracks route [`4ba0219`](https://git.odit.services/lfk/backend/commit/4ba021935c201e9d155656e82a7295c53debd8f8)
- Added the address class [`2bd0cba`](https://git.odit.services/lfk/backend/commit/2bd0cbadbed6b04136d7fc3c6f0f5e8ef35d982d)
- Added rlly basic lib generation [`421ddc5`](https://git.odit.services/lfk/backend/commit/421ddc50edc97dd98f95b19097d26f0b0388b165)
- Implemented more loaders [`6ce88a1`](https://git.odit.services/lfk/backend/commit/6ce88a1e3db4639e05473d7227ed55a785a9e967)
- Cleaned up the pipelines [`40fb081`](https://git.odit.services/lfk/backend/commit/40fb081332d4e24f222eee986d78ac3d85acd5c9)
- 🐳 working Dockerfile [`b8aebc1`](https://git.odit.services/lfk/backend/commit/b8aebc14e837868516a4fbac7bab1cef3b33c754)
- gets now use the db [`7b948f0`](https://git.odit.services/lfk/backend/commit/7b948f0380e6cc8e3d4a8b2ef54ffa34931d7f07)
- 🚀 CI/CD [`359e955`](https://git.odit.services/lfk/backend/commit/359e9559269ff34d91a42905280faa658afb5de9)
- sample implementation of authorizationChecker [`d5c6c92`](https://git.odit.services/lfk/backend/commit/d5c6c9238fb4339153fd2702dda106d36c1893e0)
- Added scanstation class [`f7beebc`](https://git.odit.services/lfk/backend/commit/f7beebce3f5dc39f6b5e8ae34a1010ebf25058e1)
- Added first team creation tests [`862834c`](https://git.odit.services/lfk/backend/commit/862834c877c3cf38f55dccf30c08e6d937cac947)
- Added runnerCard class [`fbbb5df`](https://git.odit.services/lfk/backend/commit/fbbb5df64f6033c528c7e20141fd3208b103500f)
- Added team delete test [`c3258b9`](https://git.odit.services/lfk/backend/commit/c3258b9304be150ae9e36153b72d86fd6f639ac1)
- 🧪tracks.spec.ts - adding + getting + updating tracks [`29acabf`](https://git.odit.services/lfk/backend/commit/29acabfca362ea7e13f7435b171ab3ac2d12daad)
- Deletes now return 204 instead of 404 (better rest compatability) [`a068c4d`](https://git.odit.services/lfk/backend/commit/a068c4d318dadc1860b796b231dafd3e2cf53714)
- Added distance Donation [`6c32a9e`](https://git.odit.services/lfk/backend/commit/6c32a9ebe954cd272ee140d06ef2553c9091239e)
- Added put tests for runner orgs [`0a00503`](https://git.odit.services/lfk/backend/commit/0a0050368fa0e921e20efe43f653c672c7f477ae)
- Added delete test [`13f96e3`](https://git.odit.services/lfk/backend/commit/13f96e319060bea8d47fd7d98ae5e7fc21ff59dd)
- 🚚 basic move to config.ts [`99d8a03`](https://git.odit.services/lfk/backend/commit/99d8a0360f3cdb18444a07ba4f3b5f8cd4bb98d0)
- move to dotenv + custom env validations [`622bdf7`](https://git.odit.services/lfk/backend/commit/622bdf7a3fb31e69ee28b43a02b3958c2568c31e)
- Added the donation abstract/interface [`57ba0c3`](https://git.odit.services/lfk/backend/commit/57ba0c3051ac539eca96a9d32faa00a910332db3)
- basic track testing [`07e03ff`](https://git.odit.services/lfk/backend/commit/07e03ff04e6e51113f9dcdd9e0c2f6bde2c1b906)
- sample implementation of db connection [`0d870be`](https://git.odit.services/lfk/backend/commit/0d870be23c7129645a7f4b16a812d008671d1a0d)
- initial package setup + tsconfig [`a4656e4`](https://git.odit.services/lfk/backend/commit/a4656e40373515f8ef25c2b5137d173f4fab644f)
- basic build works [`47e4f6c`](https://git.odit.services/lfk/backend/commit/47e4f6cd7eaf170f444f618b62c2bf1256ca890f)
- Added TrackScan relationships [`c1242b2`](https://git.odit.services/lfk/backend/commit/c1242b2a2aa0cc2bb07caf845a204052ac3934a7)
- Added basic openapi support [`3ce9a0b`](https://git.odit.services/lfk/backend/commit/3ce9a0b21a050095d93643bab453375c4b889ca6)
- clean up app.ts [`9925047`](https://git.odit.services/lfk/backend/commit/992504705b89e6dd915c97bbb79ccc3c6e6c7dbb)
- Added bad test to the put [`4e3b038`](https://git.odit.services/lfk/backend/commit/4e3b038dec481bdfef53c4cd136120b19d1b462e)
- First tests for orgs [`34fa94e`](https://git.odit.services/lfk/backend/commit/34fa94ea4f896ad17b6a8759f61ecb7fba095d53)
- basic jwt auth test [`3a84cc8`](https://git.odit.services/lfk/backend/commit/3a84cc8ef56c20fce74707f0aa9df7f120ee693e)
- Basic track route [`619485b`](https://git.odit.services/lfk/backend/commit/619485b356427cf3f57fa680628323917a229de0)
- Now using class validator annotations [`a6bd723`](https://git.odit.services/lfk/backend/commit/a6bd7235114e63298f2534636fa1c6fa0f08ddf5)
- Untested dockerfile and compose [`36192ea`](https://git.odit.services/lfk/backend/commit/36192ea5eb253cbdc1303e58fb34cbfa23397dae)
- sample route actions for jwt + consola demo [`8140d76`](https://git.odit.services/lfk/backend/commit/8140d76240a9c8a70ff9199e57a5759d5e7cfb74)
- Removed garbage file [`ad6c9e7`](https://git.odit.services/lfk/backend/commit/ad6c9e72111f91f432b66bc67001ef8ceea499dc)
- Moved attribute to super [`c82cc9a`](https://git.odit.services/lfk/backend/commit/c82cc9a67060268518b33b4e6ee383292c529998)
- move orm config to src folder [`3c38993`](https://git.odit.services/lfk/backend/commit/3c389937b7a1526d1da968d171330d5462fb34af)
- 🧪tracks.spec.ts - move to baseurl [`def7ca3`](https://git.odit.services/lfk/backend/commit/def7ca3eb218caf6cf4ed15799ee8ddf921cdc9f)
- 🐳 optimize Dockerfile in speed and size (pnpm + layers) [`c391201`](https://git.odit.services/lfk/backend/commit/c391201570aae13dd494a6d8fa1d28bd69dea06b)
- Updated author, contributors and license [`2000909`](https://git.odit.services/lfk/backend/commit/200090935f1ec61aa4f2c5b2956c15c48cf5b63b)
- basic prettier config [`8e107fd`](https://git.odit.services/lfk/backend/commit/8e107fd206d3c7520fc566cc5f8570f1ea559f22)
- 🚀 CI build on feature branch tags [`a1c3751`](https://git.odit.services/lfk/backend/commit/a1c37511646bee7b626bc934f28bc655e1005dca)
- Added the runnerteam class [`ac40527`](https://git.odit.services/lfk/backend/commit/ac40527fa2997450f2e0685485bc7d91ca3e9bde)
- Added the runner org class [`66f7a79`](https://git.odit.services/lfk/backend/commit/66f7a7928c60ff6def7da2c7238de297d03d67e1)
- Now throwing errors [`77b7694`](https://git.odit.services/lfk/backend/commit/77b769446ff443cf0538fcdb9bbeb1b56932e881)
- Added finxed donations [`deae0bb`](https://git.odit.services/lfk/backend/commit/deae0bb84b02b2ddf18104b7e3181c05cf20ec35)
- Added the runner class [`5a04e61`](https://git.odit.services/lfk/backend/commit/5a04e61d1cb1583e2e496fbfcb5ba78c5be6dea1)
- Set env to node_env for the server [`f2efc4e`](https://git.odit.services/lfk/backend/commit/f2efc4e37b44f9eb68cd03713a17df7d93e2c550)
- Added createtrack model that omits the id from the track model [`e5562ef`](https://git.odit.services/lfk/backend/commit/e5562efe3545012cfcddff7707891fff3f05ff1d)
- Now w/ working logout [`ac2da0a`](https://git.odit.services/lfk/backend/commit/ac2da0af63d2d6fcd4436b03f61b4eac495c1959)
- 🚧tracks.spec.ts - check if track was added [`15e3d04`](https://git.odit.services/lfk/backend/commit/15e3d04215fdab899c0fc0b8aeeb77419c518f9b)
- Added donor [`b632c09`](https://git.odit.services/lfk/backend/commit/b632c09924bd3f1f42bfc0d3ed820d349576b13a)
- basic loaders logic [`ab0e925`](https://git.odit.services/lfk/backend/commit/ab0e925ab32e8e3700a551334a07d6cc2e8cf56f)
- Now w/ working cookie based refresh [`aca3eaa`](https://git.odit.services/lfk/backend/commit/aca3eaaeea482f3fbeeb8fc69e5e9a7c5297bbc5)
- Added more negative tests for the teams [`b4b5271`](https://git.odit.services/lfk/backend/commit/b4b52717fcbb40f0aaebb5c8372715e365342b8c)
- Fix for getting one [`204e235`](https://git.odit.services/lfk/backend/commit/204e2352a9a580a5579fad98ffcfb8cdb4683eab)
- Cleaned up up the middlewares [`1fb09e5`](https://git.odit.services/lfk/backend/commit/1fb09e577c539d8261afe4cc4a2cfae88b8f866b)
- Added relations for runners [`a6222a8`](https://git.odit.services/lfk/backend/commit/a6222a80251168153dd82b69a9eb65be87aaf3a8)
- Now creating (json)schemas from class validator annotated classes [`796b894`](https://git.odit.services/lfk/backend/commit/796b8942d89ccd57fd8b5a9cd85fdc0b13f59c80)
- first sample router - ref #4 [`0d1d3c5`](https://git.odit.services/lfk/backend/commit/0d1d3c593c3621082eaa17a951aff28fbd8b1aa0)
- Basic typreorm config [`abb5b44`](https://git.odit.services/lfk/backend/commit/abb5b443eaeaa5beeb078e9e7c03aadee8335500)
- Added relations to RunnerGroup [`f28b08e`](https://git.odit.services/lfk/backend/commit/f28b08ed654309305960f8f5a882b2f6d492bf1d)
- Now also serving the openapi [`9b2ea8c`](https://git.odit.services/lfk/backend/commit/9b2ea8c23c09621e5a84dbc013137ea150a4a2dc)
- Added pirst part of track model db connection [`203d95e`](https://git.odit.services/lfk/backend/commit/203d95ee1c6c5b54646c7950b7555c8675040448)
- Added simple tracks model [`d7b5563`](https://git.odit.services/lfk/backend/commit/d7b5563d0f04183ca5e88520eacfc5a18f3e18e1)
- 🚧 tracks.spec.ts - sample track adding + getting [`a671bf8`](https://git.odit.services/lfk/backend/commit/a671bf8bcbfee3af07d5f4b667d5484e69eb9afe)
- Added scan station relationship [`f32291d`](https://git.odit.services/lfk/backend/commit/f32291d7142ed262680e627832594984b901c7e4)
- Added relations for participants [`4075276`](https://git.odit.services/lfk/backend/commit/40752761302a043e8c974fe98bc57a865eedcb55)
- Added relationships for donation [`2b69391`](https://git.odit.services/lfk/backend/commit/2b693917b0d003165bed24d97d9218f5dc613d18)
- Added endpoint descriptions [`b267d87`](https://git.odit.services/lfk/backend/commit/b267d87ba66e19e61fc04a64dee5056e3cad91e5)
- removed husky [`6363595`](https://git.odit.services/lfk/backend/commit/63635956cee97bf00375e64deebc575364e46470)
- clean up initial route sample [`529ebb2`](https://git.odit.services/lfk/backend/commit/529ebb2a8f73c9a4941a639b913d05b2eeed8de1)
- move to node:14.15.1-alpine3.12 [`bcb266e`](https://git.odit.services/lfk/backend/commit/bcb266e29bee1a7fd0f978c5b9e3c5c7795d79fe)
- switched to custom clone logic [`553a35b`](https://git.odit.services/lfk/backend/commit/553a35bb8ec61f0bc6335b2eacd26df508db6f8d)
- testing branch parameter [`ef3fcee`](https://git.odit.services/lfk/backend/commit/ef3fcee2a9cb4dc29e26040f9a9039a1b135edb4)
- Added test for non-existant deletion [`6396fff`](https://git.odit.services/lfk/backend/commit/6396fffc045da75d15b84de66d1029b01f736d79)
- ✅ phone countrycode validation in env vars [`fcfc10f`](https://git.odit.services/lfk/backend/commit/fcfc10f7d123130a5abfb877035c0e073c885021)
- ⚙ use new config loader [`39cefbc`](https://git.odit.services/lfk/backend/commit/39cefbc593a057393c59de96d2b7153adb5ea7a5)
- Relations for distanceDonation [`1c43442`](https://git.odit.services/lfk/backend/commit/1c43442300b9287ed7148a0847bf1db7805e7f0b)
- vscode workspace settings.json [`b6ddda6`](https://git.odit.services/lfk/backend/commit/b6ddda6cd8ab5dc1ee37ba9bea6fcefd23648fdf)
- Added relations for Scans [`8e2eac9`](https://git.odit.services/lfk/backend/commit/8e2eac9dc07d99da7c150e393164e96fafcdc632)
- Added relations for RunnerTeams [`0d9d72c`](https://git.odit.services/lfk/backend/commit/0d9d72c223782310a86a20ef483d695b8845dbdd)
- Added relations to RunnerOrganisation [`7ac46a7`](https://git.odit.services/lfk/backend/commit/7ac46a7cc75618f5c01c46d3baee83c30d124124)
- Added relations for runner cards [`029e4be`](https://git.odit.services/lfk/backend/commit/029e4beaf545b2dacaeb272da7f0776cfc28b82d)
- Removed relation that was already implemented in the super [`4d593eb`](https://git.odit.services/lfk/backend/commit/4d593eb840f51d33746479a26787c30f5a3983f5)
- Cleaned up imports and descriptions [`748fff5`](https://git.odit.services/lfk/backend/commit/748fff5c323c63cdfe0c8e9260ca175d99194a6b)
- Added "/api" route prefix [`4e5e084`](https://git.odit.services/lfk/backend/commit/4e5e08483d1b63ae03dc6dbb16d3277cc12bbf8d)
- Switched to declaring the track route for the whole controller [`c85fdda`](https://git.odit.services/lfk/backend/commit/c85fddaa8e9dc60226db4ba45c33a2dc54465fca)
- Make the linter happier [`90136af`](https://git.odit.services/lfk/backend/commit/90136af516abc80703b5d7f063aa87c1c1082563)
- README - basic editor informations [`0dbac89`](https://git.odit.services/lfk/backend/commit/0dbac894a1e875b352ca93ffa80667f81d1338f0)
- Added ci env [`6cfaec8`](https://git.odit.services/lfk/backend/commit/6cfaec8397f184dd357779eddac2aca568634c25)
- ⚙ nodemon config - ignore tests [`4ff6f8c`](https://git.odit.services/lfk/backend/commit/4ff6f8c54007aa01b94f428eef0c6abdaa0c29ee)
- Added our branch structure to the readme [`5b4224b`](https://git.odit.services/lfk/backend/commit/5b4224b8f55b1125f0d13893606397fb6bfc7852)
- Added reflect-metadata - typeorm requires it [`27629fb`](https://git.odit.services/lfk/backend/commit/27629fbe3bbe039ef083d073795e9089a0e07d7b)
- Added test for getting an non-existant team [`f4abbfc`](https://git.odit.services/lfk/backend/commit/f4abbfcee4cc57ec826af594ef3bcd30868c81ab)
- Added group contact class [`96d70d5`](https://git.odit.services/lfk/backend/commit/96d70d5048b89324266f33468ab3a3ea4c771604)
- default to only jwt checking (empty @Authorized() ) [`37baa4e`](https://git.odit.services/lfk/backend/commit/37baa4ea45e64fce0cc5e14bbb29b7aabed22145)
- debugging [`cb5f5b9`](https://git.odit.services/lfk/backend/commit/cb5f5b9ecb9425566a4621a87499ab13b3eaad02)
- Moved cors to the routing-controller function [`24d890f`](https://git.odit.services/lfk/backend/commit/24d890f638b2298ac2588786897490797a405ee5)
- formatting [`f7d7f5e`](https://git.odit.services/lfk/backend/commit/f7d7f5e75f9693f68ed0cf387eb402c185bc1e1c)
- Added first db connection for a tack endpoint [`b5518d0`](https://git.odit.services/lfk/backend/commit/b5518d005ffb9ab5ce5d0244a66ab28ff3a61b0e)
- basic recommended editor extensions [`9ce6209`](https://git.odit.services/lfk/backend/commit/9ce6209cac397b22698e8a92ce6c9fe506d97f49)
- 🚧 implementation in AuthController@login [`36fbccb`](https://git.odit.services/lfk/backend/commit/36fbccb286331bb4226b336e14825e593413c50c)
- Now throwing errors to the next instance [`af1ad48`](https://git.odit.services/lfk/backend/commit/af1ad482d4dd9cf65cc2895896c19f0ecf9d879d)
- Updated file structure in readme [`60c1b5d`](https://git.odit.services/lfk/backend/commit/60c1b5d748e087c89e5ede66d352eb407394e8f0)
- Added basic file structure for routes, models and controllers [`8340cce`](https://git.odit.services/lfk/backend/commit/8340cce9977c291f945eee084d40239a06fc22c1)
- Updated tsconfig to work with await and node imports [`79f883f`](https://git.odit.services/lfk/backend/commit/79f883fc31862d1b1b90ba5ad055ee712a7ed4bf)
- sample ExpressJS code [`fb00f50`](https://git.odit.services/lfk/backend/commit/fb00f50adb81eaaaf90ca9c36fab12f930b712bb)
- Renamed some drone steps [skip-ci} [`c3aa88c`](https://git.odit.services/lfk/backend/commit/c3aa88c212a65789732708157f8c4c56c8d60c29)
- Added cookie-parser to app.use [`c07d40a`](https://git.odit.services/lfk/backend/commit/c07d40ae93581b48a4e5bd0e87e0d8a41c365ec6)
- integrate pm2 process manager to keep the app up and running [`8bcaf71`](https://git.odit.services/lfk/backend/commit/8bcaf710ad580d78a254dc89060f30c0395bbdf2)
- Updated folders in the readme [`5103e8a`](https://git.odit.services/lfk/backend/commit/5103e8a6e5db8a3484eae5710f8f4f7712cb8b14)
- Other classed are now using the new Address class rather than the old location placeholder [`dca9aef`](https://git.odit.services/lfk/backend/commit/dca9aef25842b6127e258475039d6c2e1bad99f7)
- Put now isn't allowed to change ids [`aef2f95`](https://git.odit.services/lfk/backend/commit/aef2f9562a0c585cd567175118996a1725edf28b)
- Added jsdoc style class documentation [`d2278fd`](https://git.odit.services/lfk/backend/commit/d2278fd248658504cba856542328851f4fc6d96b)
- Added update and delete function functionallity [`1d57f4a`](https://git.odit.services/lfk/backend/commit/1d57f4a8d9ba01059df407758bdc9606702bbaa2)
- dependency: body-parser, cors, helmet, sqlite3 (dev) [`5034cbf`](https://git.odit.services/lfk/backend/commit/5034cbfd936b84d52279113a3d8da7be2b34716b)
- Added dev setup description [`84fee8b`](https://git.odit.services/lfk/backend/commit/84fee8b19ae3c10ddfd06883816b59c4d7ccf620)
- drop unused packages [`a7e27c6`](https://git.odit.services/lfk/backend/commit/a7e27c6f6cf20c268a81d41cedfd8e81421fff21)
- Added dedicated clone step [`31e7d07`](https://git.odit.services/lfk/backend/commit/31e7d074dc1850e91d01c3f96a9b29c09f36a59d)
- Added sqlite testing db to ignores [`cfbf1ff`](https://git.odit.services/lfk/backend/commit/cfbf1ff8211f7c8e1f5bfc9231c2187b3b9d8c31)
- Added some fixxes for typeorm entities [`8791bed`](https://git.odit.services/lfk/backend/commit/8791bed4f9239979c526b09e917b779abbeeb978)
- Cleaned up some errors [`6aa1e0d`](https://git.odit.services/lfk/backend/commit/6aa1e0d573e01926de83c410da300e02d2d902ec)
- Removed secure flag and added expiry basd on ht refresh token [`615b54e`](https://git.odit.services/lfk/backend/commit/615b54ec4f12c79d4ced3c13eb159411087ed510)
- Set cookies to secure [`0e003d2`](https://git.odit.services/lfk/backend/commit/0e003d2dc4140f9200cb0d8906a7dcd77db53d50)
- Added source [`1fbddf5`](https://git.odit.services/lfk/backend/commit/1fbddf5ef83a7d40e249ce1bbabfb6913e90a875)
- Fixed typos [`5845a91`](https://git.odit.services/lfk/backend/commit/5845a91f15b6c660fd8707aaffef212ad380d94c)
- resolve groups + permissions [`2d603a1`](https://git.odit.services/lfk/backend/commit/2d603a1467eca50263a0ad2eea427e59da88d263)
- Renamed property, so it fits with the rest of the nameing [`084e2d9`](https://git.odit.services/lfk/backend/commit/084e2d99303ebf02f69782e647ce964649156d07)
- fixxed missing imports and commented out a non-implemented function call [`79eecbb`](https://git.odit.services/lfk/backend/commit/79eecbb329c1f7181558d8a2fc39b91179ec91cf)
- sample in TrackController [`c15b650`](https://git.odit.services/lfk/backend/commit/c15b6501819ec22870c67f16e3d306bd01364ac6)
- tsconfig not strict [`447f4d8`](https://git.odit.services/lfk/backend/commit/447f4d882f23d65598fd7847cc659fa82ae91ac2)
- remove prettier config [`f96f5a6`](https://git.odit.services/lfk/backend/commit/f96f5a63a42dd84181b014ee0e638d519329380f)
- Now creating db schemas [`b5cf040`](https://git.odit.services/lfk/backend/commit/b5cf040cf0975f3a1e5ba60e8c34bbd23bc97c91)
- Switched to export default exports [`e58da2a`](https://git.odit.services/lfk/backend/commit/e58da2a22b98dc63d0982a5dad4fb94653038f2e)
- license update - move to CC BY-NC-SA 4.0 [`5e059cb`](https://git.odit.services/lfk/backend/commit/5e059cbc2a93e19a1d560915ce23312baecb19f0)
- 🩺❤🐳 Docker healthcheck [`95f40a9`](https://git.odit.services/lfk/backend/commit/95f40a9c287745dc7ccffc792f8880ff17cbc515)
- package.json - drop nodemon delay [`5ccdfe1`](https://git.odit.services/lfk/backend/commit/5ccdfe154025fde523fe30986df9ab38a4c87893)
- 🐞 fixed app.ts for production use [`a1e3289`](https://git.odit.services/lfk/backend/commit/a1e3289a88a61ee0bf574f5c674ee4ea6c06a9f8)
- Test for branch restrictions [`7a79f35`](https://git.odit.services/lfk/backend/commit/7a79f35b58eb4c1e9cf7a6bca559bdb396212fef)
- ⚡test:watch script [`34567f2`](https://git.odit.services/lfk/backend/commit/34567f24c3311ed6a0d5f1e0ea52eb8cbaff8904)
- Fixed import [`abf7aae`](https://git.odit.services/lfk/backend/commit/abf7aaeda3a39aecac98756c19b275405d869cb5)
- Changed the distance to be an abstract [`df3715d`](https://git.odit.services/lfk/backend/commit/df3715d8d67ea2506d541fe2418cd1a5bff77e8f)
- Marked amount as abstract [`a8d1ec6`](https://git.odit.services/lfk/backend/commit/a8d1ec6f9b3a3a4673945de9143b299cac1933f8)
- Amount no longer is a column by default [`daea056`](https://git.odit.services/lfk/backend/commit/daea0568a8da9dd661779510ab328175d6f790f2)
- Added todo's for relationships [`72f8085`](https://git.odit.services/lfk/backend/commit/72f80859a974086ba354b48058844d12def937dd)
- Now importing entities from src/models [`40d7d44`](https://git.odit.services/lfk/backend/commit/40d7d447308d0c135ee92171c8d2d445796137d9)
- gitignore /build folder - ref #1 [`f854f13`](https://git.odit.services/lfk/backend/commit/f854f137e579c4498d2a144b7f8f8c833d485d2d)
- tsc building script [`0b92d82`](https://git.odit.services/lfk/backend/commit/0b92d82a5ba64358a4eda4dc88475a9b2f156654)
- Switched to installing all dependencies [`16769b1`](https://git.odit.services/lfk/backend/commit/16769b19782960a8ad835a10c8c2c3095df73c9c)
- Added dotenv-save types [`a5fc6dd`](https://git.odit.services/lfk/backend/commit/a5fc6dd2340cd9fb09061e83cfc54982f50cdd59)
- Fixed broken substitution [`ad908a3`](https://git.odit.services/lfk/backend/commit/ad908a3555e430073d3a43ab6d9d7cd429840116)
- More switching [`e59630b`](https://git.odit.services/lfk/backend/commit/e59630b17e663723bb52b3153d3fd46cc464e693)
- Added lib to gitignore [`f304b86`](https://git.odit.services/lfk/backend/commit/f304b86cb61b88e4c51a5f2ae19e874d36a00068)
- Switched env to dev for tests(ci) [`c321da6`](https://git.odit.services/lfk/backend/commit/c321da613a4cdb87fd2df14c1f4c245e4228870a)
- Switched to prefering body provided tokens over cookie tokens [`3092818`](https://git.odit.services/lfk/backend/commit/30928180e63ad0dbfcf1a94440fc0a6ebd6394f1)
- 🚧 move sqlite to to production [`e398009`](https://git.odit.services/lfk/backend/commit/e3980096e279fa3d884a3688663d7e934f290b32)
- switched to using the ci testing script [`0f41962`](https://git.odit.services/lfk/backend/commit/0f419625d26c7727b20124f7d413c7d42262e500)
- fixed typo [`a83a23a`](https://git.odit.services/lfk/backend/commit/a83a23a64751db583b693892d83852e0f356a984)
- renamed step [`61b2baa`](https://git.odit.services/lfk/backend/commit/61b2baaee71bee52c3c5209f4828a2efb4bb66eb)
- send empty array for user permissions if null [`02236ca`](https://git.odit.services/lfk/backend/commit/02236caa413c3a374c62a30d9cfe0e77e1cb4c91)
- Removed relations resolution that broke the update [`e4cb8eb`](https://git.odit.services/lfk/backend/commit/e4cb8eba1d7a4e7623ebf38d84227752c84d1ead)
- Renamed to better fit the content [`6da7c23`](https://git.odit.services/lfk/backend/commit/6da7c23c04df1148ac79646c362acfaaba3ffd77)
- Fixxed missing plural [`4df63a8`](https://git.odit.services/lfk/backend/commit/4df63a8cc0c1346dda6758bf5aa20f939dc64ade)
- Renamed getter [`d0a1ea3`](https://git.odit.services/lfk/backend/commit/d0a1ea3292cf7c033d24a39ba6fdccde3c0f4022)
- Fixed copy-paste slip up [`7ce8c37`](https://git.odit.services/lfk/backend/commit/7ce8c375a2cf6aceab827d69aaa9b2835a71a5f6)
- Extended error message [`2649965`](https://git.odit.services/lfk/backend/commit/26499658a48cdb475058d1102c5be531f66beb5d)
- Fixed wrong type [`27462b0`](https://git.odit.services/lfk/backend/commit/27462b061538210acc494b151d5d6c88b8d99474)
- Loading db first [`4151f05`](https://git.odit.services/lfk/backend/commit/4151f05c2484a77d61972442b5409e60a59db526)
- Changed type to const [`29979a3`](https://git.odit.services/lfk/backend/commit/29979a37ab2bbd2559050a2dc6096142568c5a7f)
- imported bodyparser [`e3883fe`](https://git.odit.services/lfk/backend/commit/e3883fecbd93f241effbd9462080cd618376a37e)
- added jsonwebtoken dependency [`03a4898`](https://git.odit.services/lfk/backend/commit/03a4898553557e5f02c785429108c438a9e62674)
- Added libs for databases: postgres and mysql [`6c5c61b`](https://git.odit.services/lfk/backend/commit/6c5c61b1e8eed3b76ae5e6ffbaf5aacf3bb2e87b)
- dotenv-safe usage [`e764fcb`](https://git.odit.services/lfk/backend/commit/e764fcbfe916b36e2fbc4677c84130997fe59ea8)
- Switched to dotenv-save [`36d2573`](https://git.odit.services/lfk/backend/commit/36d25732eaa18a83c6d65f36422a1921cf7933af)
- Removed useless return [`db5da3d`](https://git.odit.services/lfk/backend/commit/db5da3d3c25a687d301da5b6aa28daff8cb0c5f4)
- Removed console logging only used for dev [`65f995c`](https://git.odit.services/lfk/backend/commit/65f995cb9fe27b142437d3b83b0fcc7e03c2d6b9)
- 🚧 User class WIP [`d47983a`](https://git.odit.services/lfk/backend/commit/d47983a032c5bb4d4b2958cc013df0b92ece2844)
- remove @types/helmet [`f527cad`](https://git.odit.services/lfk/backend/commit/f527cad186b199f7e5e80f38f0bc142dacf16457)
- added consola dependency [`6b46a0a`](https://git.odit.services/lfk/backend/commit/6b46a0a69e85f7cac7fdd848bbae7dd9353c7c2f)
- add @types/dotenv-safe [`a5cae04`](https://git.odit.services/lfk/backend/commit/a5cae044ed6fd018447531bf11ae19b6137b4938)
- Renamed b/c runner teams also need dedicated tests [`7606553`](https://git.odit.services/lfk/backend/commit/76065538c9cf55008879bf9bbe49ede5bbd51749)

View File

@@ -1,6 +1,16 @@
FROM node:alpine
# Typescript Build
FROM node:14.15.1-alpine3.12
WORKDIR /app
COPY ./package.json ./
RUN npm i
COPY ./ ./
ENTRYPOINT [ "yarn","dev" ]
COPY package.json ./
RUN npm i -g pnpm
RUN pnpm i
COPY tsconfig.json ormconfig.js ./
COPY src ./src
RUN pnpm run build
# final image
FROM node:14.15.1-alpine3.12
COPY package.json ormconfig.js ./
RUN npm i -g pnpm
RUN pnpm i --prod
COPY --from=0 /app/dist dist
ENTRYPOINT ["node", "dist/app.js"]

View File

@@ -25,6 +25,11 @@ Backend Server
yarn dev
```
### Generate Docs
```
yarn docs
```
### Docker w/ postgres 🐳
```bash
@@ -39,9 +44,20 @@ docker-compose up --build
- will be automatically recommended via ./vscode/extensions.json
## Branches
- main: Protected "release" branch
- dev: Current dev branch for merging the different features - only push for merges or minor changes!
- feature/xyz: Feature branches - `feature/issueid-title`
- bugfix/xyz: Branches for bugfixes - `bugfix/issueid-title` (no id for readme changes needed)
## File Structure
- src/models/\* - database models (typeorm entities)
- src/models/entities\* - database models (typeorm entities)
- src/models/actions\* - actions models
- src/models/responses\* - response models
- src/controllers/\* - routing-controllers
- src/loaders/\* - loaders for the different init steps of the api server
- src/routes/\* - express routes for everything we don't do via routing-controllers (shouldn't be much)
- src/middlewares/\* - express middlewares (mainly auth r/n)
- src/errors/* - our custom (http) errors
- src/routes/\* - express routes for everything we don't do via routing-controllers (depreciated)

View File

@@ -6,15 +6,26 @@ services:
- 4010:4010
environment:
APP_PORT: 4010
DB_TYPE: postgres
DB_HOST: backend_db
DB_PORT: 5432
DB_USER: lfk
DB_PASSWORD: changeme
DB_NAME: lfk
backend_db:
image: postgres:11-alpine
environment:
POSTGRES_DB: lfk
POSTGRES_PASSWORD: changeme
POSTGRES_USER: lfk
DB_TYPE: sqlite
DB_HOST: bla
DB_PORT: bla
DB_USER: bla
DB_PASSWORD: bla
DB_NAME: dev.sqlite
NODE_ENV: production
# APP_PORT: 4010
# DB_TYPE: postgres
# DB_HOST: backend_db
# DB_PORT: 5432
# DB_USER: lfk
# DB_PASSWORD: changeme
# DB_NAME: lfk
# NODE_ENV: production
# backend_db:
# image: postgres:11-alpine
# environment:
# POSTGRES_DB: lfk
# POSTGRES_PASSWORD: changeme
# POSTGRES_USER: lfk
# ports:
# - 5432:5432

4
jest.config.js Normal file
View File

@@ -0,0 +1,4 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};

1296
licenses.md Normal file

File diff suppressed because it is too large Load Diff

16
ormconfig.js Normal file
View File

@@ -0,0 +1,16 @@
const dotenv = require('dotenv');
dotenv.config();
//
const SOURCE_PATH = process.env.NODE_ENV === 'production' ? 'dist' : 'src';
module.exports = {
type: process.env.DB_TYPE,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
// entities: ["src/**/entities/*.ts"],
entities: [ `${SOURCE_PATH}/**/entities/*{.ts,.js}` ],
seeds: [ `${SOURCE_PATH}/**/seeds/*{.ts,.js}` ]
// seeds: ['src/seeds/*.ts'],
};

View File

@@ -1,12 +0,0 @@
import { config } from 'dotenv-safe';
config();
export default {
type: process.env.DB_TYPE,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: ["src/models/*.ts"]
};

View File

@@ -1,62 +1,102 @@
{
"name": "@lfk/backend",
"version": "1.0.0",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"author": {
"name": "ODIT.Services",
"email": "info@odit.services",
"url": "https://odit.services"
},
"contributors": [
{
"name": "Philipp Dormann",
"email": "philipp@philippdormann.de",
"url": "https://philippdormann.de"
},
{
"name": "Nicolai Ort",
"email": "info@nicolai-ort.com",
"url": "https://nicolai-ort.com"
}
],
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"body-parser": "^1.19.0",
"class-transformer": "^0.3.1",
"class-validator": "^0.12.2",
"class-validator-jsonschema": "^2.0.3",
"consola": "^2.15.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"helmet": "^4.2.0",
"jsonwebtoken": "^8.5.1",
"multer": "^1.4.2",
"mysql": "^2.18.1",
"pg": "^8.5.1",
"reflect-metadata": "^0.1.13",
"routing-controllers": "^0.9.0-alpha.6",
"routing-controllers-openapi": "^2.1.0",
"swagger-ui-express": "^4.1.5",
"typeorm": "^0.2.29",
"typeorm-routing-controllers-extensions": "^0.2.0"
},
"devDependencies": {
"@types/cors": "^2.8.8",
"@types/dotenv-safe": "^8.1.1",
"@types/express": "^4.17.9",
"@types/jsonwebtoken": "^8.5.0",
"@types/multer": "^1.4.4",
"@types/node": "^14.14.9",
"@types/swagger-ui-express": "^4.1.2",
"dotenv-safe": "^8.2.0",
"nodemon": "^2.0.6",
"sqlite3": "^5.0.0",
"ts-node": "^9.0.0",
"typescript": "^4.1.2"
},
"scripts": {
"dev": "nodemon src/app.ts",
"build": "tsc"
}
}
{
"name": "@odit/lfk-backend",
"version": "0.0.12",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"author": {
"name": "ODIT.Services",
"email": "info@odit.services",
"url": "https://odit.services"
},
"contributors": [
{
"name": "Philipp Dormann",
"email": "philipp@philippdormann.de",
"url": "https://philippdormann.de"
},
{
"name": "Nicolai Ort",
"email": "info@nicolai-ort.com",
"url": "https://nicolai-ort.com"
}
],
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"argon2": "^0.27.1",
"body-parser": "^1.19.0",
"class-transformer": "^0.3.1",
"class-validator": "^0.12.2",
"class-validator-jsonschema": "^2.1.0",
"consola": "^2.15.0",
"cookie": "^0.4.1",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"csvtojson": "^2.0.10",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mysql": "^2.18.1",
"pg": "^8.5.1",
"reflect-metadata": "^0.1.13",
"routing-controllers": "^0.9.0-alpha.6",
"routing-controllers-openapi": "^2.2.0",
"sqlite3": "5.0.0",
"typeorm": "^0.2.29",
"typeorm-routing-controllers-extensions": "^0.2.0",
"typeorm-seeding": "^1.6.1",
"uuid": "^8.3.2",
"validator": "^13.5.2"
},
"devDependencies": {
"@odit/license-exporter": "^0.0.9",
"@types/cors": "^2.8.9",
"@types/csvtojson": "^1.1.5",
"@types/express": "^4.17.9",
"@types/jest": "^26.0.16",
"@types/jsonwebtoken": "^8.5.0",
"@types/node": "^14.14.20",
"@types/uuid": "^8.3.0",
"axios": "^0.21.1",
"cp-cli": "^2.0.0",
"jest": "^26.6.3",
"nodemon": "^2.0.7",
"release-it": "^14.2.2",
"rimraf": "^3.0.2",
"start-server-and-test": "^1.11.7",
"ts-jest": "^26.4.4",
"ts-node": "^9.1.1",
"typedoc": "^0.20.14",
"typescript": "^4.1.3"
},
"scripts": {
"dev": "nodemon src/app.ts",
"build": "rimraf ./dist && tsc && cp-cli ./src/static ./dist/static",
"docs": "typedoc --out docs src",
"test": "jest",
"test:watch": "jest --watchAll",
"test:ci": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test",
"seed": "ts-node ./node_modules/typeorm/cli.js schema:sync && ts-node ./node_modules/typeorm-seeding/dist/cli.js seed",
"openapi:export": "ts-node scripts/openapi_export.ts",
"licenses:export": "license-exporter --md",
"release": "release-it --only-version"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀Bumped version to v${version}",
"requireBranch": "dev",
"push": false,
"tag": false
},
"npm": {
"publish": false
}
},
"nodemonConfig": {
"ignore": [
"src/tests/*",
"docs/*"
]
}
}

34
scripts/openapi_export.ts Normal file
View File

@@ -0,0 +1,34 @@
import { validationMetadatasToSchemas } from 'class-validator-jsonschema';
import consola from "consola";
import fs from "fs";
import "reflect-metadata";
import { createExpressServer, getMetadataArgsStorage } from "routing-controllers";
import { generateSpec } from '../src/apispec';
import { config } from '../src/config';
import authchecker from "../src/middlewares/authchecker";
import { ErrorHandler } from '../src/middlewares/ErrorHandler';
const CONTROLLERS_FILE_EXTENSION = process.env.NODE_ENV === 'production' ? 'js' : 'ts';
createExpressServer({
authorizationChecker: authchecker,
middlewares: [ErrorHandler],
development: config.development,
cors: true,
routePrefix: "/api",
controllers: [`${__dirname}/../src/controllers/*.${CONTROLLERS_FILE_EXTENSION}`],
});
const storage = getMetadataArgsStorage();
const schemas = validationMetadatasToSchemas({
refPointerPrefix: "#/components/schemas/",
});
//Spec creation based on the previously created schemas
const spec = generateSpec(storage, schemas);
try {
fs.writeFileSync("./openapi.json", JSON.stringify(spec), { encoding: "utf-8" });
consola.success("Exported openapi spec to openapi.json");
} catch (error) {
consola.error("Couldn't export the openapi spec");
}

51
src/apispec.ts Normal file
View File

@@ -0,0 +1,51 @@
import { MetadataArgsStorage } from 'routing-controllers';
import { routingControllersToSpec } from 'routing-controllers-openapi';
import { config } from './config';
/**
* This function generates a the openapi spec from route metadata and type schemas.
* @param storage MetadataArgsStorage object generated by routing-controllers.
* @param schemas MetadataArgsStorage object generated by class-validator-jsonschema.
*/
export function generateSpec(storage: MetadataArgsStorage, schemas) {
return routingControllersToSpec(
storage,
{
routePrefix: "/api"
},
{
components: {
schemas,
"securitySchemes": {
"AuthToken": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
description: "A JWT based access token. Use /api/auth/login or /api/auth/refresh to get one."
},
"RefreshTokenCookie": {
"type": "apiKey",
"in": "cookie",
"name": "lfk_backend__refresh_token",
description: "A cookie containing a JWT based refreh token. Attention: Doesn't work in swagger-ui. Use /api/auth/login or /api/auth/refresh to get one."
},
"StatsApiToken": {
"type": "http",
"scheme": "bearer",
description: "Api token that can be obtained by creating a new stats client (post to /api/statsclients). Only valid for obtaining stats."
},
"StationApiToken": {
"type": "http",
"scheme": "bearer",
description: "Api token that can be obtained by creating a new scan station (post to /api/stations). Only valid for creating scans."
}
}
},
info: {
description: "The the backend API for the LfK! runner system.",
title: "LfK! Backend API",
version: config.version
},
}
);
}

View File

@@ -1,25 +1,32 @@
import "reflect-metadata";
import * as dotenvSafe from "dotenv-safe";
import { createExpressServer } from "routing-controllers";
import consola from "consola";
import "reflect-metadata";
import { createExpressServer } from "routing-controllers";
import { config, e as errors } from './config';
import loaders from "./loaders/index";
import authchecker from "./middlewares/authchecker";
import { ErrorHandler } from './middlewares/ErrorHandler';
dotenvSafe.config();
const PORT = process.env.APP_PORT || 4010;
const CONTROLLERS_FILE_EXTENSION = process.env.NODE_ENV === 'production' ? 'js' : 'ts';
const app = createExpressServer({
development: process.env.NODE_ENV === "production",
authorizationChecker: authchecker,
middlewares: [ErrorHandler],
development: config.development,
cors: true,
routePrefix: "/api",
controllers: [__dirname + "/controllers/*.ts"],
controllers: [`${__dirname}/controllers/*.${CONTROLLERS_FILE_EXTENSION}`],
});
async function main() {
await loaders(app);
app.listen(PORT, () => {
app.listen(config.internal_port, () => {
consola.success(
`⚡️[server]: Server is running at http://localhost:${PORT}`
`⚡️[server]: Server is running at http://localhost:${config.internal_port}`
);
});
}
main();
if (errors === 0) {
main();
} else {
consola.error("error");
// something's wrong
}

35
src/config.ts Normal file
View File

@@ -0,0 +1,35 @@
import { config as configDotenv } from 'dotenv';
import ValidatorJS from 'validator';
configDotenv();
export const config = {
internal_port: parseInt(process.env.APP_PORT) || 4010,
development: process.env.NODE_ENV === "production",
jwt_secret: process.env.JWT_SECRET || "secretjwtsecret",
phone_validation_countrycode: process.env.PHONE_COUNTRYCODE || "ZZ",
postalcode_validation_countrycode: getPostalCodeLocale(),
version: process.env.VERSION || require('../package.json').version
}
let errors = 0
if (typeof config.internal_port !== "number") {
errors++
}
if (typeof config.phone_validation_countrycode !== "string") {
errors++
}
if (config.phone_validation_countrycode.length !== 2) {
errors++
}
if (typeof config.development !== "boolean") {
errors++
}
function getPostalCodeLocale(): any {
try {
const stringArray: String[] = ValidatorJS.isPostalCodeLocales;
let index = stringArray.indexOf(process.env.POSTALCODE_COUNTRYCODE);
return ValidatorJS.isPostalCodeLocales[index];
} catch (error) {
return null;
}
}
export let e = errors

View File

@@ -0,0 +1,103 @@
import { Body, CookieParam, JsonController, Param, Post, Req, Res } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError';
import { UserNotFoundError } from '../errors/UserErrors';
import { CreateAuth } from '../models/actions/create/CreateAuth';
import { CreateResetToken } from '../models/actions/create/CreateResetToken';
import { HandleLogout } from '../models/actions/HandleLogout';
import { RefreshAuth } from '../models/actions/RefreshAuth';
import { ResetPassword } from '../models/actions/ResetPassword';
import { ResponseAuth } from '../models/responses/ResponseAuth';
import { Logout } from '../models/responses/ResponseLogout';
@JsonController('/auth')
export class AuthController {
constructor() {
}
@Post("/login")
@ResponseSchema(ResponseAuth)
@ResponseSchema(InvalidCredentialsError)
@ResponseSchema(UserNotFoundError)
@ResponseSchema(UsernameOrEmailNeededError)
@ResponseSchema(PasswordNeededError)
@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)' })
async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) {
let auth;
try {
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_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true });
return response.send(auth)
} catch (error) {
throw error;
}
}
@Post("/logout")
@ResponseSchema(Logout)
@ResponseSchema(InvalidCredentialsError)
@ResponseSchema(UserNotFoundError)
@ResponseSchema(UsernameOrEmailNeededError)
@ResponseSchema(PasswordNeededError)
@ResponseSchema(InvalidCredentialsError)
@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) {
if (refresh_token && refresh_token.length != 0 && handleLogout.token == undefined) {
handleLogout.token = refresh_token;
}
let logout;
try {
logout = await handleLogout.logout()
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 });
} catch (error) {
throw error;
}
return response.send(logout)
}
@Post("/refresh")
@ResponseSchema(ResponseAuth)
@ResponseSchema(JwtNotProvidedError)
@ResponseSchema(IllegalJWTError)
@ResponseSchema(UserNotFoundError)
@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": [] }] })
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) {
refreshAuth.token = refresh_token;
}
let auth;
try {
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_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true });
} catch (error) {
throw error;
}
return response.send(auth)
}
@Post("/reset")
@ResponseSchema(ResponseAuth)
@ResponseSchema(UserNotFoundError)
@ResponseSchema(UsernameOrEmailNeededError)
@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) {
//This really shouldn't just get returned, but sent via mail or sth like that. But for dev only this is fine.
return { "resetToken": await passwordReset.toResetToken() };
}
@Post("/reset/:token")
@ResponseSchema(ResponseAuth)
@ResponseSchema(UserNotFoundError)
@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." })
async resetPassword(@Param("token") token: string, @Body({ validate: true }) passwordReset: ResetPassword) {
passwordReset.resetToken = token;
return await passwordReset.resetPassword();
}
}

View File

@@ -0,0 +1,145 @@
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 { DonationIdsNotMatchingError, DonationNotFoundError } from '../errors/DonationErrors';
import { DonorNotFoundError } from '../errors/DonorErrors';
import { RunnerNotFoundError } from '../errors/RunnerErrors';
import { CreateDistanceDonation } from '../models/actions/create/CreateDistanceDonation';
import { CreateFixedDonation } from '../models/actions/create/CreateFixedDonation';
import { UpdateDistanceDonation } from '../models/actions/update/UpdateDistanceDonation';
import { UpdateFixedDonation } from '../models/actions/update/UpdateFixedDonation';
import { DistanceDonation } from '../models/entities/DistanceDonation';
import { Donation } from '../models/entities/Donation';
import { FixedDonation } from '../models/entities/FixedDonation';
import { ResponseDistanceDonation } from '../models/responses/ResponseDistanceDonation';
import { ResponseDonation } from '../models/responses/ResponseDonation';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
@JsonController('/donations')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class DonationController {
private donationRepository: Repository<Donation>;
private distanceDonationRepository: Repository<DistanceDonation>;
private fixedDonationRepository: Repository<FixedDonation>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.donationRepository = getConnectionManager().get().getRepository(Donation);
this.distanceDonationRepository = getConnectionManager().get().getRepository(DistanceDonation);
this.fixedDonationRepository = getConnectionManager().get().getRepository(FixedDonation);
}
@Get()
@Authorized("DONATION:GET")
@ResponseSchema(ResponseDonation, { isArray: true })
@ResponseSchema(ResponseDistanceDonation, { isArray: true })
@OpenAPI({ description: 'Lists all donations (fixed or distance based) from all donors. <br> This includes the donations\'s runner\'s distance ran(if distance donation).' })
async getAll() {
let responseDonations: ResponseDonation[] = new Array<ResponseDonation>();
const donations = await this.donationRepository.find({ relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] });
donations.forEach(donation => {
responseDonations.push(donation.toResponse());
});
return responseDonations;
}
@Get('/:id')
@Authorized("DONATION:GET")
@ResponseSchema(ResponseDonation)
@ResponseSchema(ResponseDistanceDonation)
@ResponseSchema(DonationNotFoundError, { statusCode: 404 })
@OnUndefined(DonationNotFoundError)
@OpenAPI({ description: 'Lists all information about the donation whose id got provided. This includes the donation\'s runner\'s distance ran (if distance donation).' })
async getOne(@Param('id') id: number) {
let donation = await this.donationRepository.findOne({ id: id }, { relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] })
if (!donation) { throw new DonationNotFoundError(); }
return donation.toResponse();
}
@Post('/fixed')
@Authorized("DONATION:CREATE")
@ResponseSchema(ResponseDonation)
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a fixed donation (not distance donation - use /donations/distance instead). <br> Please rmemember to provide the donation\'s donors\'s id and amount.' })
async postFixed(@Body({ validate: true }) createDonation: CreateFixedDonation) {
let donation = await createDonation.toEntity();
donation = await this.fixedDonationRepository.save(donation);
return (await this.donationRepository.findOne({ id: donation.id }, { relations: ['donor'] })).toResponse();
}
@Post('/distance')
@Authorized("DONATION:CREATE")
@ResponseSchema(ResponseDistanceDonation)
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a distance donation (not fixed donation - use /donations/fixed instead). <br> Please rmemember to provide the donation\'s donors\'s and runner\s ids and amount per distance (kilometer).' })
async postDistance(@Body({ validate: true }) createDonation: CreateDistanceDonation) {
let donation = await createDonation.toEntity();
donation = await this.distanceDonationRepository.save(donation);
return (await this.donationRepository.findOne({ id: donation.id }, { relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] })).toResponse();
}
@Put('/fixed/:id')
@Authorized("DONATION:UPDATE")
@ResponseSchema(ResponseDonation)
@ResponseSchema(DonationNotFoundError, { statusCode: 404 })
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@ResponseSchema(DonationIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the fixed donation (not distance donation - use /donations/distance instead) whose id you provided. <br> Please remember that ids can't be changed and amounts must be positive." })
async putFixed(@Param('id') id: number, @Body({ validate: true }) donation: UpdateFixedDonation) {
let oldDonation = await this.fixedDonationRepository.findOne({ id: id });
if (!oldDonation) {
throw new DonationNotFoundError();
}
if (oldDonation.id != donation.id) {
throw new DonationIdsNotMatchingError();
}
await this.fixedDonationRepository.save(await donation.update(oldDonation));
return (await this.donationRepository.findOne({ id: donation.id }, { relations: ['donor'] })).toResponse();
}
@Put('/distance/:id')
@Authorized("DONATION:UPDATE")
@ResponseSchema(ResponseDonation)
@ResponseSchema(DonationNotFoundError, { statusCode: 404 })
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@ResponseSchema(DonationIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the distance donation (not fixed donation - use /donations/fixed instead) whose id you provided. <br> Please remember that ids can't be changed and amountPerDistance must be positive." })
async putDistance(@Param('id') id: number, @Body({ validate: true }) donation: UpdateDistanceDonation) {
let oldDonation = await this.distanceDonationRepository.findOne({ id: id });
if (!oldDonation) {
throw new DonationNotFoundError();
}
if (oldDonation.id != donation.id) {
throw new DonationIdsNotMatchingError();
}
await this.distanceDonationRepository.save(await donation.update(oldDonation));
return (await this.donationRepository.findOne({ id: donation.id }, { relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] })).toResponse();
}
@Delete('/:id')
@Authorized("DONATION:DELETE")
@ResponseSchema(ResponseDonation)
@ResponseSchema(ResponseDistanceDonation)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the donation whose id you provided. <br> If no donation with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let donation = await this.donationRepository.findOne({ id: id });
if (!donation) { return null; }
const responseScan = await this.donationRepository.findOne({ id: donation.id }, { relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] });
await this.donationRepository.delete(donation);
return responseScan.toResponse();
}
}

View File

@@ -0,0 +1,113 @@
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 { DonorHasDonationsError, DonorIdsNotMatchingError, DonorNotFoundError } from '../errors/DonorErrors';
import { CreateDonor } from '../models/actions/create/CreateDonor';
import { UpdateDonor } from '../models/actions/update/UpdateDonor';
import { Donor } from '../models/entities/Donor';
import { ResponseDonor } from '../models/responses/ResponseDonor';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { DonationController } from './DonationController';
@JsonController('/donors')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class DonorController {
private donorRepository: Repository<Donor>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.donorRepository = getConnectionManager().get().getRepository(Donor);
}
@Get()
@Authorized("DONOR:GET")
@ResponseSchema(ResponseDonor, { isArray: true })
@OpenAPI({ description: 'Lists all donor. <br> This includes the donor\'s current donation amount.' })
async getAll() {
let responseDonors: ResponseDonor[] = new Array<ResponseDonor>();
const donors = await this.donorRepository.find({ relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] });
donors.forEach(donor => {
responseDonors.push(new ResponseDonor(donor));
});
return responseDonors;
}
@Get('/:id')
@Authorized("DONOR:GET")
@ResponseSchema(ResponseDonor)
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@OnUndefined(DonorNotFoundError)
@OpenAPI({ description: 'Lists all information about the donor whose id got provided. <br> This includes the donor\'s current donation amount.' })
async getOne(@Param('id') id: number) {
let donor = await this.donorRepository.findOne({ id: id }, { relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] })
if (!donor) { throw new DonorNotFoundError(); }
return new ResponseDonor(donor);
}
@Post()
@Authorized("DONOR:CREATE")
@ResponseSchema(ResponseDonor)
@OpenAPI({ description: 'Create a new donor.' })
async post(@Body({ validate: true }) createRunner: CreateDonor) {
let donor;
try {
donor = await createRunner.toEntity();
} catch (error) {
throw error;
}
donor = await this.donorRepository.save(donor)
return new ResponseDonor(await this.donorRepository.findOne(donor, { relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] }));
}
@Put('/:id')
@Authorized("DONOR:UPDATE")
@ResponseSchema(ResponseDonor)
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@ResponseSchema(DonorIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the donor whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) donor: UpdateDonor) {
let oldDonor = await this.donorRepository.findOne({ id: id });
if (!oldDonor) {
throw new DonorNotFoundError();
}
if (oldDonor.id != donor.id) {
throw new DonorIdsNotMatchingError();
}
await this.donorRepository.save(await donor.update(oldDonor));
return new ResponseDonor(await this.donorRepository.findOne({ id: id }, { relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] }));
}
@Delete('/:id')
@Authorized("DONOR:DELETE")
@ResponseSchema(ResponseDonor)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the donor whose id you provided. <br> If no donor with this id exists it will just return 204(no content). <br> If the donor still has donations associated this will fail, please provide the query param ?force=true to delete the donor with all associated donations.' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let donor = await this.donorRepository.findOne({ id: id });
if (!donor) { return null; }
const responseDonor = await this.donorRepository.findOne(donor, { relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] });
if (!donor) {
throw new DonorNotFoundError();
}
const donorDonations = (await this.donorRepository.findOne({ id: donor.id }, { relations: ["donations"] })).donations;
if (donorDonations.length > 0 && !force) {
throw new DonorHasDonationsError();
}
const donationController = new DonationController();
for (let donation of donorDonations) {
await donationController.remove(donation.id, force);
}
await this.donorRepository.delete(donor);
return new ResponseDonor(responseDonor);
}
}

View File

@@ -0,0 +1,102 @@
import csv from 'csvtojson';
import { Authorized, Body, ContentType, Controller, Param, Post, QueryParam, Req, UseBefore } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { RunnerGroupNeededError } from '../errors/RunnerErrors';
import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors';
import RawBodyMiddleware from '../middlewares/RawBody';
import { ImportRunner } from '../models/actions/ImportRunner';
import { ResponseRunner } from '../models/responses/ResponseRunner';
import { RunnerController } from './RunnerController';
@Controller()
@Authorized(["RUNNER:IMPORT", "TEAM:IMPORT"])
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class ImportController {
private runnerController: RunnerController;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.runnerController = new RunnerController();
}
@Post('/runners/import')
@ContentType("application/json")
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerGroupNeededError, { statusCode: 406 })
@OpenAPI({ description: "Create new runners from json and insert them into the provided group. <br> If teams/classes are provided alongside the runner's name they'll automaticly be created under the provided org and the runners will be inserted into the teams instead." })
async postJSON(@Body({ validate: true, type: ImportRunner }) importRunners: ImportRunner[], @QueryParam("group") groupID: number) {
if (!groupID) { throw new RunnerGroupNeededError(); }
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
for await (let runner of importRunners) {
responseRunners.push(await this.runnerController.post(await runner.toCreateRunner(groupID)));
}
return responseRunners;
}
@Post('/organisations/:id/import')
@ContentType("application/json")
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerGroupNeededError, { statusCode: 406 })
@OpenAPI({ description: "Create new runners from json and insert them into the provided org. <br> If teams/classes are provided alongside the runner's name they'll automaticly be created under the provided org and the runners will be inserted into the teams instead." })
async postOrgsJSON(@Body({ validate: true, type: ImportRunner }) importRunners: ImportRunner[], @Param('id') id: number) {
return await this.postJSON(importRunners, id)
}
@Post('/teams/:id/import')
@ContentType("application/json")
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerGroupNeededError, { statusCode: 406 })
@OpenAPI({ description: "Create new runners from json and insert them into the provided team" })
async postTeamsJSON(@Body({ validate: true, type: ImportRunner }) importRunners: ImportRunner[], @Param('id') id: number) {
return await this.postJSON(importRunners, id)
}
@Post('/runners/import/csv')
@ContentType("application/json")
@UseBefore(RawBodyMiddleware)
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerGroupNeededError, { statusCode: 406 })
@OpenAPI({ description: "Create new runners from csv and insert them into the provided group. <br> If teams/classes are provided alongside the runner's name they'll automaticly be created under the provided org and the runners will be inserted into the teams instead." })
async postCSV(@Req() request: any, @QueryParam("group") groupID: number) {
let csvParse = await csv({ delimiter: [",", ";"], trim: true }).fromString(request.rawBody.toString());
let importRunners: ImportRunner[] = new Array<ImportRunner>();
for await (let runner of csvParse) {
let newImportRunner = new ImportRunner();
newImportRunner.firstname = runner.firstname;
newImportRunner.middlename = runner.middlename;
newImportRunner.lastname = runner.lastname;
if (runner.class === undefined) { newImportRunner.team = runner.team; }
else { newImportRunner.class = runner.class; }
importRunners.push(newImportRunner);
}
return await this.postJSON(importRunners, groupID);
}
@Post('/organisations/:id/import/csv')
@ContentType("application/json")
@UseBefore(RawBodyMiddleware)
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerGroupNeededError, { statusCode: 406 })
@OpenAPI({ description: "Create new runners from csv and insert them into the provided org. <br> If teams/classes are provided alongside the runner's name they'll automaticly be created under the provided org and the runners will be inserted into the teams instead." })
async postOrgsCSV(@Req() request: any, @Param("id") id: number) {
return await this.postCSV(request, id);
}
@Post('/teams/:id/import/csv')
@ContentType("application/json")
@UseBefore(RawBodyMiddleware)
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerGroupNeededError, { statusCode: 406 })
@OpenAPI({ description: "Create new runners from csv and insert them into the provided team" })
async postTeamsCSV(@Req() request: any, @Param("id") id: number) {
return await this.postCSV(request, id);
}
}

View File

@@ -0,0 +1,118 @@
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 { PermissionIdsNotMatchingError, PermissionNeedsPrincipalError, PermissionNotFoundError } from '../errors/PermissionErrors';
import { PrincipalNotFoundError } from '../errors/PrincipalErrors';
import { CreatePermission } from '../models/actions/create/CreatePermission';
import { UpdatePermission } from '../models/actions/update/UpdatePermission';
import { Permission } from '../models/entities/Permission';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponsePermission } from '../models/responses/ResponsePermission';
import { ResponsePrincipal } from '../models/responses/ResponsePrincipal';
@JsonController('/permissions')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class PermissionController {
private permissionRepository: Repository<Permission>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.permissionRepository = getConnectionManager().get().getRepository(Permission);
}
@Get()
@Authorized("PERMISSION:GET")
@ResponseSchema(ResponsePermission, { isArray: true })
@OpenAPI({ description: 'Lists all permissions for all users and groups.' })
async getAll() {
let responsePermissions: ResponsePermission[] = new Array<ResponsePermission>();
const permissions = await this.permissionRepository.find({ relations: ['principal'] });
permissions.forEach(permission => {
responsePermissions.push(new ResponsePermission(permission));
});
return responsePermissions;
}
@Get('/:id')
@Authorized("PERMISSION:GET")
@ResponseSchema(ResponsePermission)
@ResponseSchema(PermissionNotFoundError, { statusCode: 404 })
@OnUndefined(PermissionNotFoundError)
@OpenAPI({ description: 'Lists all information about the permission whose id got provided.' })
async getOne(@Param('id') id: number) {
let permission = await this.permissionRepository.findOne({ id: id }, { relations: ['principal'] });
if (!permission) { throw new PermissionNotFoundError(); }
return new ResponsePermission(permission);
}
@Post()
@Authorized("PERMISSION:CREATE")
@ResponseSchema(ResponsePermission)
@ResponseSchema(PrincipalNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a new permission for a existing principal(user/group). <br> If a permission with this target, action and prinicpal already exists that permission will be returned instead of creating a new one.' })
async post(@Body({ validate: true }) createPermission: CreatePermission) {
let permission;
try {
permission = await createPermission.toEntity();
} catch (error) {
throw error;
}
let existingPermission = await this.permissionRepository.findOne({ target: permission.target, action: permission.action, principal: permission.principal }, { relations: ['principal'] });
if (existingPermission) { return new ResponsePermission(existingPermission); }
permission = await this.permissionRepository.save(permission);
permission = await this.permissionRepository.findOne(permission, { relations: ['principal'] });
return new ResponsePermission(permission);
}
@Put('/:id')
@Authorized("PERMISSION:UPDATE")
@ResponseSchema(ResponsePrincipal)
@ResponseSchema(PermissionNotFoundError, { statusCode: 404 })
@ResponseSchema(PrincipalNotFoundError, { statusCode: 404 })
@ResponseSchema(PermissionIdsNotMatchingError, { statusCode: 406 })
@ResponseSchema(PermissionNeedsPrincipalError, { statusCode: 406 })
@OpenAPI({ description: "Update a permission object. <br> If updateing the permission object would result in duplicate permission (same target, action and principal) this permission will get deleted and the existing permission will be returned. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) permission: UpdatePermission) {
let oldPermission = await this.permissionRepository.findOne({ id: id }, { relations: ['principal'] });
if (!oldPermission) {
throw new PermissionNotFoundError();
}
if (oldPermission.id != permission.id) {
throw new PermissionIdsNotMatchingError();
}
let existingPermission = await this.permissionRepository.findOne({ target: permission.target, action: permission.action, principal: permission.principal }, { relations: ['principal'] });
if (existingPermission) {
await this.remove(permission.id, true);
return new ResponsePermission(existingPermission);
}
await this.permissionRepository.save(await permission.update(oldPermission));
return new ResponsePermission(await this.permissionRepository.findOne({ id: permission.id }, { relations: ['principal'] }));
}
@Delete('/:id')
@Authorized("PERMISSION:DELETE")
@ResponseSchema(ResponsePermission)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: 'Deletes the permission whose id you provide. <br> If no permission with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let permission = await this.permissionRepository.findOne({ id: id }, { relations: ['principal'] });
if (!permission) { return null; }
const responsePermission = new ResponsePermission(permission);
await this.permissionRepository.delete(permission);
return responsePermission;
}
}

View File

@@ -0,0 +1,106 @@
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 { RunnerCardHasScansError, RunnerCardIdsNotMatchingError, RunnerCardNotFoundError } from '../errors/RunnerCardErrors';
import { RunnerNotFoundError } from '../errors/RunnerErrors';
import { CreateRunnerCard } from '../models/actions/create/CreateRunnerCard';
import { UpdateRunnerCard } from '../models/actions/update/UpdateRunnerCard';
import { RunnerCard } from '../models/entities/RunnerCard';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseRunnerCard } from '../models/responses/ResponseRunnerCard';
import { ScanController } from './ScanController';
@JsonController('/cards')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class RunnerCardController {
private cardRepository: Repository<RunnerCard>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.cardRepository = getConnectionManager().get().getRepository(RunnerCard);
}
@Get()
@Authorized("CARD:GET")
@ResponseSchema(ResponseRunnerCard, { isArray: true })
@OpenAPI({ description: 'Lists all card.' })
async getAll() {
let responseCards: ResponseRunnerCard[] = new Array<ResponseRunnerCard>();
const cards = await this.cardRepository.find({ relations: ['runner'] });
cards.forEach(card => {
responseCards.push(new ResponseRunnerCard(card));
});
return responseCards;
}
@Get('/:id')
@Authorized("CARD:GET")
@ResponseSchema(ResponseRunnerCard)
@ResponseSchema(RunnerCardNotFoundError, { statusCode: 404 })
@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'] });
if (!card) { throw new RunnerCardNotFoundError(); }
return card.toResponse();
}
@Post()
@Authorized("CARD:CREATE")
@ResponseSchema(ResponseRunnerCard)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OpenAPI({ description: "Create a new card. <br> You can provide a associated runner by id but you don't have to." })
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();
}
@Put('/:id')
@Authorized("CARD:UPDATE")
@ResponseSchema(ResponseRunnerCard)
@ResponseSchema(RunnerCardNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerCardIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the card whose id you provided. <br> Scans created via this card will still be associated with the old runner. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) card: UpdateRunnerCard) {
let oldCard = await this.cardRepository.findOne({ id: id });
if (!oldCard) {
throw new RunnerCardNotFoundError();
}
if (oldCard.id != card.id) {
throw new RunnerCardIdsNotMatchingError();
}
await this.cardRepository.save(await card.update(oldCard));
return (await this.cardRepository.findOne({ id: id }, { relations: ['runner'] })).toResponse();
}
@Delete('/:id')
@Authorized("CARD:DELETE")
@ResponseSchema(ResponseRunnerCard)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@ResponseSchema(RunnerCardHasScansError, { statusCode: 406 })
@OnUndefined(204)
@OpenAPI({ description: "Delete the card whose id you provided. <br> If no card with this id exists it will just return 204(no content). <br> If the card still has scans associated you have to provide the force=true query param (warning: this deletes all scans associated with by this card - please disable it instead or just remove the runner association)." })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let card = await this.cardRepository.findOne({ id: id });
if (!card) { return null; }
const cardScans = (await this.cardRepository.findOne({ id: id }, { relations: ["scans"] })).scans;
if (cardScans.length != 0 && !force) {
throw new RunnerCardHasScansError();
}
const scanController = new ScanController;
for (let scan of cardScans) {
await scanController.remove(scan.id, force);
}
await this.cardRepository.delete(card);
return card.toResponse();
}
}

View File

@@ -0,0 +1,131 @@
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 { RunnerGroupNeededError, RunnerHasDistanceDonationsError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors';
import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors';
import { CreateRunner } from '../models/actions/create/CreateRunner';
import { UpdateRunner } from '../models/actions/update/UpdateRunner';
import { Runner } from '../models/entities/Runner';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseRunner } from '../models/responses/ResponseRunner';
import { DonationController } from './DonationController';
import { RunnerCardController } from './RunnerCardController';
import { ScanController } from './ScanController';
@JsonController('/runners')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class RunnerController {
private runnerRepository: Repository<Runner>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.runnerRepository = getConnectionManager().get().getRepository(Runner);
}
@Get()
@Authorized("RUNNER:GET")
@ResponseSchema(ResponseRunner, { isArray: true })
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
async getAll() {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
const runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'scans.track', 'cards'] });
runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner));
});
return responseRunners;
}
@Get('/:id')
@Authorized("RUNNER:GET")
@ResponseSchema(ResponseRunner)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerNotFoundError)
@OpenAPI({ description: 'Lists all information about the runner whose id got provided.' })
async getOne(@Param('id') id: number) {
let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'scans.track', 'cards'] })
if (!runner) { throw new RunnerNotFoundError(); }
return new ResponseRunner(runner);
}
@Post()
@Authorized("RUNNER:CREATE")
@ResponseSchema(ResponseRunner)
@ResponseSchema(RunnerGroupNeededError)
@ResponseSchema(RunnerGroupNotFoundError)
@OpenAPI({ description: 'Create a new runner. <br> Please remeber to provide the runner\'s group\'s id.' })
async post(@Body({ validate: true }) createRunner: CreateRunner) {
let runner;
try {
runner = await createRunner.toEntity();
} catch (error) {
throw error;
}
runner = await this.runnerRepository.save(runner)
return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'scans.track', 'cards'] }));
}
@Put('/:id')
@Authorized("RUNNER:UPDATE")
@ResponseSchema(ResponseRunner)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the runner whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) runner: UpdateRunner) {
let oldRunner = await this.runnerRepository.findOne({ id: id }, { relations: ['group'] });
if (!oldRunner) {
throw new RunnerNotFoundError();
}
if (oldRunner.id != runner.id) {
throw new RunnerIdsNotMatchingError();
}
await this.runnerRepository.save(await runner.update(oldRunner));
return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'scans.track', 'cards'] }));
}
@Delete('/:id')
@Authorized("RUNNER:DELETE")
@ResponseSchema(ResponseRunner)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@ResponseSchema(RunnerHasDistanceDonationsError, { statusCode: 406 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the runner whose id you provided. <br> This will also delete all scans and cards associated with the runner. <br> If no runner with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let runner = await this.runnerRepository.findOne({ id: id });
if (!runner) { return null; }
const responseRunner = await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'scans.track', 'cards'] });
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 ResponseRunner(responseRunner);
}
}

View File

@@ -0,0 +1,127 @@
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 { RunnerOrganisationHasRunnersError, RunnerOrganisationHasTeamsError, RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors';
import { CreateRunnerOrganisation } from '../models/actions/create/CreateRunnerOrganisation';
import { UpdateRunnerOrganisation } from '../models/actions/update/UpdateRunnerOrganisation';
import { RunnerOrganisation } from '../models/entities/RunnerOrganisation';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseRunnerOrganisation } from '../models/responses/ResponseRunnerOrganisation';
import { RunnerController } from './RunnerController';
import { RunnerTeamController } from './RunnerTeamController';
@JsonController('/organisations')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class RunnerOrganisationController {
private runnerOrganisationRepository: Repository<RunnerOrganisation>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerOrganisation);
}
@Get()
@Authorized("ORGANISATION:GET")
@ResponseSchema(ResponseRunnerOrganisation, { isArray: true })
@OpenAPI({ description: 'Lists all organisations. <br> This includes their address, contact and teams (if existing/associated).' })
async getAll() {
let responseTeams: ResponseRunnerOrganisation[] = new Array<ResponseRunnerOrganisation>();
const runners = await this.runnerOrganisationRepository.find({ relations: ['address', 'contact', 'teams'] });
runners.forEach(runner => {
responseTeams.push(new ResponseRunnerOrganisation(runner));
});
return responseTeams;
}
@Get('/:id')
@Authorized("ORGANISATION:GET")
@ResponseSchema(ResponseRunnerOrganisation)
@ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerOrganisationNotFoundError)
@OpenAPI({ description: 'Lists all information about the organisation whose id got provided.' })
async getOne(@Param('id') id: number) {
let runnerOrg = await this.runnerOrganisationRepository.findOne({ id: id }, { relations: ['address', 'contact', 'teams'] });
if (!runnerOrg) { throw new RunnerOrganisationNotFoundError(); }
return new ResponseRunnerOrganisation(runnerOrg);
}
@Post()
@Authorized("ORGANISATION:CREATE")
@ResponseSchema(ResponseRunnerOrganisation)
@OpenAPI({ description: 'Create a new organsisation.' })
async post(@Body({ validate: true }) createRunnerOrganisation: CreateRunnerOrganisation) {
let runnerOrganisation;
try {
runnerOrganisation = await createRunnerOrganisation.toEntity();
} catch (error) {
throw error;
}
runnerOrganisation = await this.runnerOrganisationRepository.save(runnerOrganisation);
return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['address', 'contact', 'teams'] }));
}
@Put('/:id')
@Authorized("ORGANISATION:UPDATE")
@ResponseSchema(ResponseRunnerOrganisation)
@ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the organisation whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) updateOrganisation: UpdateRunnerOrganisation) {
let oldRunnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id });
if (!oldRunnerOrganisation) {
throw new RunnerOrganisationNotFoundError();
}
if (oldRunnerOrganisation.id != updateOrganisation.id) {
throw new RunnerOrganisationIdsNotMatchingError();
}
await this.runnerOrganisationRepository.save(await updateOrganisation.update(oldRunnerOrganisation));
return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(id, { relations: ['address', 'contact', 'teams'] }));
}
@Delete('/:id')
@Authorized("ORGANISATION:DELETE")
@ResponseSchema(ResponseRunnerOrganisation)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@ResponseSchema(RunnerOrganisationHasTeamsError, { statusCode: 406 })
@ResponseSchema(RunnerOrganisationHasRunnersError, { statusCode: 406 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the organsisation whose id you provided. <br> If the organisation still has runners and/or teams associated this will fail. <br> To delete the organisation with all associated runners and teams set the force QueryParam to true (cascading deletion might take a while). <br> If no organisation with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let organisation = await this.runnerOrganisationRepository.findOne({ id: id });
if (!organisation) { return null; }
let runnerOrganisation = await this.runnerOrganisationRepository.findOne(organisation, { relations: ['address', 'contact', 'runners', 'teams'] });
if (!force) {
if (runnerOrganisation.teams.length != 0) {
throw new RunnerOrganisationHasTeamsError();
}
}
const teamController = new RunnerTeamController()
for (let team of runnerOrganisation.teams) {
await teamController.remove(team.id, true);
}
if (!force) {
if (runnerOrganisation.runners.length != 0) {
throw new RunnerOrganisationHasRunnersError();
}
}
const runnerController = new RunnerController()
for (let runner of runnerOrganisation.runners) {
await runnerController.remove(runner.id, true);
}
const responseOrganisation = new ResponseRunnerOrganisation(runnerOrganisation);
await this.runnerOrganisationRepository.delete(organisation);
return responseOrganisation;
}
}

View File

@@ -0,0 +1,116 @@
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 { RunnerTeamHasRunnersError, RunnerTeamIdsNotMatchingError, RunnerTeamNotFoundError } from '../errors/RunnerTeamErrors';
import { CreateRunnerTeam } from '../models/actions/create/CreateRunnerTeam';
import { UpdateRunnerTeam } from '../models/actions/update/UpdateRunnerTeam';
import { RunnerTeam } from '../models/entities/RunnerTeam';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseRunnerTeam } from '../models/responses/ResponseRunnerTeam';
import { RunnerController } from './RunnerController';
@JsonController('/teams')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class RunnerTeamController {
private runnerTeamRepository: Repository<RunnerTeam>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.runnerTeamRepository = getConnectionManager().get().getRepository(RunnerTeam);
}
@Get()
@Authorized("TEAM:GET")
@ResponseSchema(ResponseRunnerTeam, { isArray: true })
@OpenAPI({ description: 'Lists all teams. <br> This includes their parent organisation and contact (if existing/associated).' })
async getAll() {
let responseTeams: ResponseRunnerTeam[] = new Array<ResponseRunnerTeam>();
const runners = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] });
runners.forEach(runner => {
responseTeams.push(new ResponseRunnerTeam(runner));
});
return responseTeams;
}
@Get('/:id')
@Authorized("TEAM:GET")
@ResponseSchema(ResponseRunnerTeam)
@ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerTeamNotFoundError)
@OpenAPI({ description: 'Lists all information about the team whose id got provided.' })
async getOne(@Param('id') id: number) {
let runnerTeam = await this.runnerTeamRepository.findOne({ id: id }, { relations: ['parentGroup', 'contact'] });
if (!runnerTeam) { throw new RunnerTeamNotFoundError(); }
return new ResponseRunnerTeam(runnerTeam);
}
@Post()
@Authorized("TEAM:CREATE")
@ResponseSchema(ResponseRunnerTeam)
@OpenAPI({ description: 'Create a new organsisation. <br> Please remember to provide it\'s parent group\'s id.' })
async post(@Body({ validate: true }) createRunnerTeam: CreateRunnerTeam) {
let runnerTeam;
try {
runnerTeam = await createRunnerTeam.toEntity();
} catch (error) {
throw error;
}
runnerTeam = await this.runnerTeamRepository.save(runnerTeam);
runnerTeam = await this.runnerTeamRepository.findOne(runnerTeam, { relations: ['parentGroup', 'contact'] });
return new ResponseRunnerTeam(runnerTeam);
}
@Put('/:id')
@Authorized("TEAM:UPDATE")
@ResponseSchema(ResponseRunnerTeam)
@ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerTeamIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the team whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) runnerTeam: UpdateRunnerTeam) {
let oldRunnerTeam = await this.runnerTeamRepository.findOne({ id: id }, { relations: ['parentGroup', 'contact'] });
if (!oldRunnerTeam) {
throw new RunnerTeamNotFoundError();
}
if (oldRunnerTeam.id != runnerTeam.id) {
throw new RunnerTeamIdsNotMatchingError();
}
await this.runnerTeamRepository.save(await runnerTeam.update(oldRunnerTeam));
return new ResponseRunnerTeam(await this.runnerTeamRepository.findOne({ id: runnerTeam.id }, { relations: ['parentGroup', 'contact'] }));
}
@Delete('/:id')
@Authorized("TEAM:DELETE")
@ResponseSchema(ResponseRunnerTeam)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@ResponseSchema(RunnerTeamHasRunnersError, { statusCode: 406 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the team whose id you provided. <br> If the team still has runners associated this will fail. <br> To delete the team with all associated runners set the force QueryParam to true (cascading deletion might take a while). <br> If no team with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let team = await this.runnerTeamRepository.findOne({ id: id });
if (!team) { return null; }
let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['parentGroup', 'contact', 'runners'] });
if (!force) {
if (runnerTeam.runners.length != 0) {
throw new RunnerTeamHasRunnersError();
}
}
const runnerController = new RunnerController()
for (let runner of runnerTeam.runners) {
await runnerController.remove(runner.id, true);
}
const responseTeam = new ResponseRunnerTeam(runnerTeam);
await this.runnerTeamRepository.delete(team);
return responseTeam;
}
}

View File

@@ -0,0 +1,140 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam, UseBefore } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { RunnerNotFoundError } from '../errors/RunnerErrors';
import { ScanIdsNotMatchingError, ScanNotFoundError } from '../errors/ScanErrors';
import { ScanStationNotFoundError } from '../errors/ScanStationErrors';
import ScanAuth from '../middlewares/ScanAuth';
import { CreateScan } from '../models/actions/create/CreateScan';
import { CreateTrackScan } from '../models/actions/create/CreateTrackScan';
import { UpdateScan } from '../models/actions/update/UpdateScan';
import { UpdateTrackScan } from '../models/actions/update/UpdateTrackScan';
import { Scan } from '../models/entities/Scan';
import { TrackScan } from '../models/entities/TrackScan';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseScan } from '../models/responses/ResponseScan';
import { ResponseTrackScan } from '../models/responses/ResponseTrackScan';
@JsonController('/scans')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class ScanController {
private scanRepository: Repository<Scan>;
private trackScanRepository: Repository<TrackScan>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.scanRepository = getConnectionManager().get().getRepository(Scan);
this.trackScanRepository = getConnectionManager().get().getRepository(TrackScan);
}
@Get()
@Authorized("SCAN:GET")
@ResponseSchema(ResponseScan, { isArray: true })
@ResponseSchema(ResponseTrackScan, { isArray: true })
@OpenAPI({ description: 'Lists all scans (normal or track) from all runners. <br> This includes the scan\'s runner\'s distance ran.' })
async getAll() {
let responseScans: ResponseScan[] = new Array<ResponseScan>();
const scans = await this.scanRepository.find({ relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] });
scans.forEach(scan => {
responseScans.push(scan.toResponse());
});
return responseScans;
}
@Get('/:id')
@Authorized("SCAN:GET")
@ResponseSchema(ResponseScan)
@ResponseSchema(ResponseTrackScan)
@ResponseSchema(ScanNotFoundError, { statusCode: 404 })
@OnUndefined(ScanNotFoundError)
@OpenAPI({ description: 'Lists all information about the scan whose id got provided. This includes the scan\'s runner\'s distance ran.' })
async getOne(@Param('id') id: number) {
let scan = await this.scanRepository.findOne({ id: id }, { relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] })
if (!scan) { throw new ScanNotFoundError(); }
return scan.toResponse();
}
@Post()
@UseBefore(ScanAuth)
@ResponseSchema(ResponseScan)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a new scan (not track scan - use /scans/trackscans instead). <br> Please rmemember to provide the scan\'s runner\'s id and distance.', security: [{ "ScanApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async post(@Body({ validate: true }) createScan: CreateScan) {
let scan = await createScan.toEntity();
scan = await this.scanRepository.save(scan);
return (await this.scanRepository.findOne({ id: scan.id }, { relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] })).toResponse();
}
@Post("/trackscans")
@UseBefore(ScanAuth)
@ResponseSchema(ResponseTrackScan)
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a new track scan (for "normal" scans use /scans instead). <br> Please remember that to provide the scan\'s card\'s station\'s id.', security: [{ "ScanApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async postTrackScans(@Body({ validate: true }) createScan: CreateTrackScan) {
let scan = await createScan.toEntity();
scan = await this.trackScanRepository.save(scan);
return (await this.scanRepository.findOne({ id: scan.id }, { relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] })).toResponse();
}
@Put('/:id')
@Authorized("SCAN:UPDATE")
@ResponseSchema(ResponseScan)
@ResponseSchema(ScanNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@ResponseSchema(ScanIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the scan (not track scan use /scans/trackscans/:id instead) whose id you provided. <br> Please remember that ids can't be changed and distances must be positive." })
async put(@Param('id') id: number, @Body({ validate: true }) scan: UpdateScan) {
let oldScan = await this.scanRepository.findOne({ id: id });
if (!oldScan) {
throw new ScanNotFoundError();
}
if (oldScan.id != scan.id) {
throw new ScanIdsNotMatchingError();
}
await this.scanRepository.save(await scan.update(oldScan));
return (await this.scanRepository.findOne({ id: id }, { relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] })).toResponse();
}
@Put('/trackscans/:id')
@Authorized("SCAN:UPDATE")
@ResponseSchema(ResponseTrackScan)
@ResponseSchema(ScanNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@ResponseSchema(ScanStationNotFoundError, { statusCode: 404 })
@ResponseSchema(ScanIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: 'Update the track scan (not "normal" scan use /scans/trackscans/:id instead) whose id you provided. <br> Please remember that only the validity, runner and track can be changed.' })
async putTrackScan(@Param('id') id: number, @Body({ validate: true }) scan: UpdateTrackScan) {
let oldScan = await this.trackScanRepository.findOne({ id: id });
if (!oldScan) {
throw new ScanNotFoundError();
}
if (oldScan.id != scan.id) {
throw new ScanIdsNotMatchingError();
}
await this.trackScanRepository.save(await scan.update(oldScan));
return (await this.scanRepository.findOne({ id: id }, { relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] })).toResponse();
}
@Delete('/:id')
@Authorized("SCAN:DELETE")
@ResponseSchema(ResponseScan)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the scan whose id you provided. <br> If no scan with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let scan = await this.scanRepository.findOne({ id: id });
if (!scan) { return null; }
const responseScan = await this.scanRepository.findOne({ id: scan.id }, { relations: ['runner', 'track', 'runner.scans', 'runner.scans.track', 'card', 'station'] });
await this.scanRepository.delete(scan);
return responseScan.toResponse();
}
}

View File

@@ -0,0 +1,108 @@
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 { ScanStationHasScansError, ScanStationIdsNotMatchingError, ScanStationNotFoundError } from '../errors/ScanStationErrors';
import { TrackNotFoundError } from '../errors/TrackErrors';
import { CreateScanStation } from '../models/actions/create/CreateScanStation';
import { UpdateScanStation } from '../models/actions/update/UpdateScanStation';
import { ScanStation } from '../models/entities/ScanStation';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseScanStation } from '../models/responses/ResponseScanStation';
import { ScanController } from './ScanController';
@JsonController('/stations')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class ScanStationController {
private stationRepository: Repository<ScanStation>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.stationRepository = getConnectionManager().get().getRepository(ScanStation);
}
@Get()
@Authorized("STATION:GET")
@ResponseSchema(ResponseScanStation, { isArray: true })
@OpenAPI({ description: 'Lists all stations. <br> This includes their associated tracks.' })
async getAll() {
let responseStations: ResponseScanStation[] = new Array<ResponseScanStation>();
const stations = await this.stationRepository.find({ relations: ['track'] });
stations.forEach(station => {
responseStations.push(station.toResponse());
});
return responseStations;
}
@Get('/:id')
@Authorized("STATION:GET")
@ResponseSchema(ResponseScanStation)
@ResponseSchema(ScanStationNotFoundError, { statusCode: 404 })
@OnUndefined(ScanStationNotFoundError)
@OpenAPI({ description: 'Lists all information about the station whose id got provided. <br> This includes it\'s associated track.' })
async getOne(@Param('id') id: number) {
let scan = await this.stationRepository.findOne({ id: id }, { relations: ['track'] })
if (!scan) { throw new ScanStationNotFoundError(); }
return scan.toResponse();
}
@Post()
@Authorized("STATION:CREATE")
@ResponseSchema(ResponseScanStation)
@ResponseSchema(TrackNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a new station. <br> Please remeber to provide the station\'s track\'s id. <br> Please also remember that the station key is only visibe on creation.' })
async post(@Body({ validate: true }) createStation: CreateScanStation) {
let newStation = await createStation.toEntity();
const station = await this.stationRepository.save(newStation);
let responseStation = (await this.stationRepository.findOne({ id: station.id }, { relations: ['track'] })).toResponse();
responseStation.key = newStation.cleartextkey;
return responseStation;
}
@Put('/:id')
@Authorized("STATION:UPDATE")
@ResponseSchema(ResponseScanStation)
@ResponseSchema(ScanStationNotFoundError, { statusCode: 404 })
@ResponseSchema(ScanStationIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the station whose id you provided. <br> Please remember that only the description and enabled state can be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) station: UpdateScanStation) {
let oldStation = await this.stationRepository.findOne({ id: id });
if (!oldStation) {
throw new ScanStationNotFoundError();
}
if (oldStation.id != station.id) {
throw new ScanStationIdsNotMatchingError();
}
await this.stationRepository.save(await station.update(oldStation));
return (await this.stationRepository.findOne({ id: id }, { relations: ['track'] })).toResponse();
}
@Delete('/:id')
@Authorized("STATION:DELETE")
@ResponseSchema(ResponseScanStation)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@ResponseSchema(ScanStationHasScansError, { statusCode: 406 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the station whose id you provided. <br> If no station with this id exists it will just return 204(no content). <br> If the station still has scans associated you have to provide the force=true query param (warning: this deletes all scans associated with/created by this station - please disable it instead).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let station = await this.stationRepository.findOne({ id: id });
if (!station) { return null; }
const stationScans = (await this.stationRepository.findOne({ id: station.id }, { relations: ["scans"] })).scans;
if (stationScans.length != 0 && !force) {
throw new ScanStationHasScansError();
}
const scanController = new ScanController;
for (let scan of stationScans) {
await scanController.remove(scan.id, force);
}
const responseStation = await this.stationRepository.findOne({ id: station.id }, { relations: ["track"] });
await this.stationRepository.delete(station);
return responseStation.toResponse();
}
}

View File

@@ -0,0 +1,75 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { StatsClientNotFoundError } from '../errors/StatsClientErrors';
import { TrackNotFoundError } from "../errors/TrackErrors";
import { CreateStatsClient } from '../models/actions/create/CreateStatsClient';
import { StatsClient } from '../models/entities/StatsClient';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseStatsClient } from '../models/responses/ResponseStatsClient';
@JsonController('/statsclients')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class StatsClientController {
private clientRepository: Repository<StatsClient>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.clientRepository = getConnectionManager().get().getRepository(StatsClient);
}
@Get()
@Authorized("STATSCLIENT:GET")
@ResponseSchema(ResponseStatsClient, { isArray: true })
@OpenAPI({ description: 'Lists all stats clients. Please remember that the key can only be viewed on creation.' })
async getAll() {
let responseClients: ResponseStatsClient[] = new Array<ResponseStatsClient>();
const clients = await this.clientRepository.find();
clients.forEach(clients => {
responseClients.push(new ResponseStatsClient(clients));
});
return responseClients;
}
@Get('/:id')
@Authorized("STATSCLIENT:GET")
@ResponseSchema(ResponseStatsClient)
@ResponseSchema(StatsClientNotFoundError, { statusCode: 404 })
@OnUndefined(StatsClientNotFoundError)
@OpenAPI({ description: "Lists all information about the stats client whose id got provided. Please remember that the key can only be viewed on creation." })
async getOne(@Param('id') id: number) {
let client = await this.clientRepository.findOne({ id: id });
if (!client) { throw new TrackNotFoundError(); }
return new ResponseStatsClient(client);
}
@Post()
@Authorized("STATSCLIENT:CREATE")
@ResponseSchema(ResponseStatsClient)
@OpenAPI({ description: "Create a new stats client. <br> Please remember that the client\'s key will be generated automaticly and that it can only be viewed on creation." })
async post(
@Body({ validate: true })
client: CreateStatsClient
) {
let newClient = await this.clientRepository.save(await client.toEntity());
let responseClient = new ResponseStatsClient(newClient);
responseClient.key = newClient.cleartextkey;
return responseClient;
}
@Delete('/:id')
@Authorized("STATSCLIENT:DELETE")
@ResponseSchema(ResponseStatsClient)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: "Delete the stats client whose id you provided. <br> If no client with this id exists it will just return 204(no content)." })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let client = await this.clientRepository.findOne({ id: id });
if (!client) { return null; }
await this.clientRepository.delete(client);
return new ResponseStatsClient(client);
}
}

View File

@@ -0,0 +1,124 @@
import { Get, JsonController, UseBefore } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnection } from 'typeorm';
import StatsAuth from '../middlewares/StatsAuth';
import { Donation } from '../models/entities/Donation';
import { Runner } from '../models/entities/Runner';
import { RunnerOrganisation } from '../models/entities/RunnerOrganisation';
import { RunnerTeam } from '../models/entities/RunnerTeam';
import { Scan } from '../models/entities/Scan';
import { User } from '../models/entities/User';
import { ResponseStats } from '../models/responses/ResponseStats';
import { ResponseStatsOrgnisation } from '../models/responses/ResponseStatsOrganisation';
import { ResponseStatsRunner } from '../models/responses/ResponseStatsRunner';
import { ResponseStatsTeam } from '../models/responses/ResponseStatsTeam';
@JsonController('/stats')
export class StatsController {
@Get()
@ResponseSchema(ResponseStats)
@OpenAPI({ description: "A very basic stats endpoint providing basic counters for a dashboard or simmilar" })
async get() {
let connection = getConnection();
let runners = await connection.getRepository(Runner).find({ relations: ['scans', 'scans.track'] });
let teams = await connection.getRepository(RunnerTeam).find();
let orgs = await connection.getRepository(RunnerOrganisation).find();
let users = await connection.getRepository(User).find();
let scans = await connection.getRepository(Scan).find();
let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] });
return new ResponseStats(runners, teams, orgs, users, scans, donations)
}
@Get("/runners/distance")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsRunner, { isArray: true })
@OpenAPI({ description: "Returns the top ten runners by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopRunnersByDistance() {
let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations', 'scans.track'] });
let topRunners = runners.sort((runner1, runner2) => runner1.distance - runner2.distance).slice(0, 9);
let responseRunners: ResponseStatsRunner[] = new Array<ResponseStatsRunner>();
topRunners.forEach(runner => {
responseRunners.push(new ResponseStatsRunner(runner));
});
return responseRunners;
}
@Get("/runners/donations")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsRunner, { isArray: true })
@OpenAPI({ description: "Returns the top ten runners by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopRunnersByDonations() {
let runners = await getConnection().getRepository(Runner).find({ relations: ['scans', 'group', 'distanceDonations', 'scans.track'] });
let topRunners = runners.sort((runner1, runner2) => runner1.distanceDonationAmount - runner2.distanceDonationAmount).slice(0, 9);
let responseRunners: ResponseStatsRunner[] = new Array<ResponseStatsRunner>();
topRunners.forEach(runner => {
responseRunners.push(new ResponseStatsRunner(runner));
});
return responseRunners;
}
@Get("/scans")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsRunner, { isArray: true })
@OpenAPI({ description: "Returns the top ten fastest track times (with their runner and the runner's group).", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopRunnersByTrackTime() {
throw new Error("Not implemented yet.")
}
@Get("/teams/distance")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsTeam, { isArray: true })
@OpenAPI({ description: "Returns the top ten teams by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopTeamsByDistance() {
let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track'] });
let topTeams = teams.sort((team1, team2) => team1.distance - team2.distance).slice(0, 9);
let responseTeams: ResponseStatsTeam[] = new Array<ResponseStatsTeam>();
topTeams.forEach(team => {
responseTeams.push(new ResponseStatsTeam(team));
});
return responseTeams;
}
@Get("/teams/donations")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsTeam, { isArray: true })
@OpenAPI({ description: "Returns the top ten teams by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopTeamsByDonations() {
let teams = await getConnection().getRepository(RunnerTeam).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track'] });
let topTeams = teams.sort((team1, team2) => team1.distanceDonationAmount - team2.distanceDonationAmount).slice(0, 9);
let responseTeams: ResponseStatsTeam[] = new Array<ResponseStatsTeam>();
topTeams.forEach(team => {
responseTeams.push(new ResponseStatsTeam(team));
});
return responseTeams;
}
@Get("/organisations/distance")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsOrgnisation, { isArray: true })
@OpenAPI({ description: "Returns the top ten organisations by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopOrgsByDistance() {
let orgs = await getConnection().getRepository(RunnerOrganisation).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] });
let topOrgs = orgs.sort((org1, org2) => org1.distance - org2.distance).slice(0, 9);
let responseOrgs: ResponseStatsOrgnisation[] = new Array<ResponseStatsOrgnisation>();
topOrgs.forEach(org => {
responseOrgs.push(new ResponseStatsOrgnisation(org));
});
return responseOrgs;
}
@Get("/organisations/donations")
@UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsOrgnisation, { isArray: true })
@OpenAPI({ description: "Returns the top ten organisations by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopOrgsByDonations() {
let orgs = await getConnection().getRepository(RunnerOrganisation).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] });
let topOrgs = orgs.sort((org1, org2) => org1.distanceDonationAmount - org2.distanceDonationAmount).slice(0, 9);
let responseOrgs: ResponseStatsOrgnisation[] = new Array<ResponseStatsOrgnisation>();
topOrgs.forEach(org => {
responseOrgs.push(new ResponseStatsOrgnisation(org));
});
return responseOrgs;
}
}

View File

@@ -0,0 +1,31 @@
import { Get, JsonController } from 'routing-controllers';
import { OpenAPI } from 'routing-controllers-openapi';
import { getConnection } from 'typeorm';
import { config } from '../config';
@JsonController()
export class StatusController {
@Get('/status')
@OpenAPI({ description: "A very basic status/health endpoint that just checks if the database connection is available. <br> The available information depth will be expanded later." })
get() {
let connection;
try {
connection = getConnection();
} catch {
throw new Error("sth is wrong, i can feel it....");
}
return {
"controllers": "✔",
"database connection": "✔"
};
}
@Get('/version')
@OpenAPI({ description: "A very basic endpoint that just returns the curent package version." })
getVersion() {
return {
"version": config.version
}
}
}

View File

@@ -1,91 +1,105 @@
import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers';
import { getConnectionManager, Repository } from 'typeorm';
import { EntityFromBody } from 'typeorm-routing-controllers-extensions';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { Track } from '../models/Track';
import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator';
class CreateTrack {
@IsString()
@IsNotEmpty()
name: string;
@IsInt()
@IsPositive()
length: number;
}
export class TrackNotFoundError extends NotFoundError {
constructor() {
super('Track not found!');
}
}
@JsonController('/tracks')
export class TrackController {
private trackRepository: Repository<Track>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.trackRepository = getConnectionManager().get().getRepository(Track);
}
@Get()
@ResponseSchema(Track, { isArray: true })
@OpenAPI({description: "Lists all tracks."})
getAll() {
return this.trackRepository.find();
}
@Get('/:id')
@ResponseSchema(Track)
@OnUndefined(TrackNotFoundError)
@OpenAPI({description: "Returns a track of a specified id (if it exists)"})
getOne(@Param('id') id: number) {
return this.trackRepository.findOne({ id: id });
}
@Post()
@ResponseSchema(Track)
@OpenAPI({description: "Create a new track object (id will be generated automagicly)."})
post(
@Body({ validate: true })
track: CreateTrack
) {
return this.trackRepository.save(track);
}
@Put('/:id')
@ResponseSchema(Track)
@OpenAPI({description: "Update a track object (id can't be changed)."})
async put(@Param('id') id: number, @EntityFromBody() track: Track) {
let oldTrack = await this.trackRepository.findOne({ id: id });
if (!oldTrack) {
throw new TrackNotFoundError();
}
if(oldTrack.id != track.id){
throw new NotAcceptableError("The id's don't match!");
}
await this.trackRepository.update(oldTrack, track);
return track;
}
@Delete('/:id')
@ResponseSchema(Track)
@OpenAPI({description: "Delete a specified track (if it exists)."})
async remove(@Param('id') id: number) {
let track = await this.trackRepository.findOne({ id: id });
if (!track) {
throw new TrackNotFoundError();
}
await this.trackRepository.delete(track);
return track;
}
}
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 { TrackHasScanStationsError, TrackIdsNotMatchingError, TrackLapTimeCantBeNegativeError, TrackNotFoundError } from "../errors/TrackErrors";
import { CreateTrack } from '../models/actions/create/CreateTrack';
import { UpdateTrack } from '../models/actions/update/UpdateTrack';
import { Track } from '../models/entities/Track';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseTrack } from '../models/responses/ResponseTrack';
import { ScanStationController } from './ScanStationController';
@JsonController('/tracks')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class TrackController {
private trackRepository: Repository<Track>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.trackRepository = getConnectionManager().get().getRepository(Track);
}
@Get()
@Authorized("TRACK:GET")
@ResponseSchema(ResponseTrack, { isArray: true })
@OpenAPI({ description: 'Lists all tracks.' })
async getAll() {
let responseTracks: ResponseTrack[] = new Array<ResponseTrack>();
const tracks = await this.trackRepository.find();
tracks.forEach(track => {
responseTracks.push(new ResponseTrack(track));
});
return responseTracks;
}
@Get('/:id')
@Authorized("TRACK:GET")
@ResponseSchema(ResponseTrack)
@ResponseSchema(TrackNotFoundError, { statusCode: 404 })
@OnUndefined(TrackNotFoundError)
@OpenAPI({ description: "Lists all information about the track whose id got provided." })
async getOne(@Param('id') id: number) {
let track = await this.trackRepository.findOne({ id: id });
if (!track) { throw new TrackNotFoundError(); }
return new ResponseTrack(track);
}
@Post()
@Authorized("TRACK:CREATE")
@ResponseSchema(ResponseTrack)
@ResponseSchema(TrackLapTimeCantBeNegativeError, { statusCode: 406 })
@OpenAPI({ description: "Create a new track. <br> Please remember that the track\'s distance must be greater than 0." })
async post(
@Body({ validate: true })
track: CreateTrack
) {
return new ResponseTrack(await this.trackRepository.save(await track.toEntity()));
}
@Put('/:id')
@Authorized("TRACK:UPDATE")
@ResponseSchema(ResponseTrack)
@ResponseSchema(TrackNotFoundError, { statusCode: 404 })
@ResponseSchema(TrackIdsNotMatchingError, { statusCode: 406 })
@ResponseSchema(TrackLapTimeCantBeNegativeError, { statusCode: 406 })
@OpenAPI({ description: "Update the track whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) updateTrack: UpdateTrack) {
let oldTrack = await this.trackRepository.findOne({ id: id });
if (!oldTrack) {
throw new TrackNotFoundError();
}
if (oldTrack.id != updateTrack.id) {
throw new TrackIdsNotMatchingError();
}
await this.trackRepository.save(await updateTrack.update(oldTrack));
return new ResponseTrack(await this.trackRepository.findOne({ id: id }));
}
@Delete('/:id')
@Authorized("TRACK:DELETE")
@ResponseSchema(ResponseTrack)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: "Delete the track whose id you provided. <br> If no track with this id exists it will just return 204(no content)." })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let track = await this.trackRepository.findOne({ id: id });
if (!track) { return null; }
const trackStations = (await this.trackRepository.findOne({ id: id }, { relations: ["stations"] })).stations;
if (trackStations.length != 0 && !force) {
throw new TrackHasScanStationsError();
}
const stationController = new ScanStationController;
for (let station of trackStations) {
await stationController.remove(station.id, force);
}
await this.trackRepository.delete(track);
return new ResponseTrack(track);
}
}

View File

@@ -0,0 +1,123 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { UserIdsNotMatchingError, UsernameContainsIllegalCharacterError, UserNotFoundError } from '../errors/UserErrors';
import { UserGroupNotFoundError } from '../errors/UserGroupErrors';
import { CreateUser } from '../models/actions/create/CreateUser';
import { UpdateUser } from '../models/actions/update/UpdateUser';
import { User } from '../models/entities/User';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseUser } from '../models/responses/ResponseUser';
import { ResponseUserPermissions } from '../models/responses/ResponseUserPermissions';
import { PermissionController } from './PermissionController';
@JsonController('/users')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class UserController {
private userRepository: Repository<User>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.userRepository = getConnectionManager().get().getRepository(User);
}
@Get()
@Authorized("USER:GET")
@ResponseSchema(ResponseUser, { isArray: true })
@OpenAPI({ description: 'Lists all users. <br> This includes their groups and permissions granted to them.' })
async getAll() {
let responseUsers: ResponseUser[] = new Array<ResponseUser>();
const users = await this.userRepository.find({ relations: ['permissions', 'groups', 'groups.permissions'] });
users.forEach(user => {
responseUsers.push(new ResponseUser(user));
});
return responseUsers;
}
@Get('/:id')
@Authorized("USER:GET")
@ResponseSchema(ResponseUser)
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@OnUndefined(UserNotFoundError)
@OpenAPI({ description: 'Lists all information about the user whose id got provided. <br> Please remember that all permissions granted to the user will show up here.' })
async getOne(@Param('id') id: number) {
let user = await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups', 'groups.permissions'] })
if (!user) { throw new UserNotFoundError(); }
return new ResponseUser(user);
}
@Get('/:id/permissions')
@Authorized("USER:GET")
@ResponseSchema(ResponseUser)
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@OnUndefined(UserNotFoundError)
@OpenAPI({ description: 'Lists all permissions granted to the user sorted into directly granted and inherited as permission response objects.' })
async getPermissions(@Param('id') id: number) {
let user = await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups', 'groups.permissions', 'permissions.principal', 'groups.permissions.principal'] })
if (!user) { throw new UserNotFoundError(); }
return new ResponseUserPermissions(user);
}
@Post()
@Authorized("USER:CREATE")
@ResponseSchema(ResponseUser)
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@ResponseSchema(UsernameContainsIllegalCharacterError, { 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;
try {
user = await createUser.toEntity();
} catch (error) {
throw error;
}
user = await this.userRepository.save(user)
return new ResponseUser(await this.userRepository.findOne({ id: user.id }, { relations: ['permissions', 'groups', 'groups.permissions'] }));
}
@Put('/:id')
@Authorized("USER:UPDATE")
@ResponseSchema(ResponseUser)
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 })
@ResponseSchema(UsernameContainsIllegalCharacterError, { 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 });
if (!oldUser) {
throw new UserNotFoundError();
}
if (oldUser.id != updateUser.id) {
throw new UserIdsNotMatchingError();
}
await this.userRepository.save(await updateUser.update(oldUser));
return new ResponseUser(await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups', 'groups.permissions'] }));
}
@Delete('/:id')
@Authorized("USER:DELETE")
@ResponseSchema(ResponseUser)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the user whose id you provided. <br> If there are any permissions directly granted to the user they will get deleted as well. <br> If no user with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let user = await this.userRepository.findOne({ id: id });
if (!user) { return null; }
const responseUser = await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups', 'groups.permissions'] });;
const permissionControler = new PermissionController();
for (let permission of responseUser.permissions) {
await permissionControler.remove(permission.id, true);
}
await this.userRepository.delete(user);
return new ResponseUser(responseUser);
}
}

View File

@@ -0,0 +1,100 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { EntityFromBody } from 'typeorm-routing-controllers-extensions';
import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors';
import { CreateUserGroup } from '../models/actions/create/CreateUserGroup';
import { UpdateUserGroup } from '../models/actions/update/UpdateUserGroup';
import { UserGroup } from '../models/entities/UserGroup';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseUserGroup } from '../models/responses/ResponseUserGroup';
import { PermissionController } from './PermissionController';
@JsonController('/usergroups')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class UserGroupController {
private userGroupsRepository: Repository<UserGroup>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.userGroupsRepository = getConnectionManager().get().getRepository(UserGroup);
}
@Get()
@Authorized("USERGROUP:GET")
@ResponseSchema(UserGroup, { isArray: true })
@OpenAPI({ description: 'Lists all groups. <br> The information provided might change while the project continues to evolve.' })
getAll() {
return this.userGroupsRepository.find({ relations: ["permissions"] });
}
@Get('/:id')
@Authorized("USERGROUP:GET")
@ResponseSchema(UserGroup)
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@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.' })
getOne(@Param('id') id: number) {
return this.userGroupsRepository.findOne({ id: id }, { relations: ["permissions"] });
}
@Post()
@Authorized("USERGROUP:CREATE")
@ResponseSchema(UserGroup)
@ResponseSchema(UserGroupNotFoundError)
@OpenAPI({ description: 'Create a new group. <br> If you want to grant permissions to the group you have to create them seperately by posting to /api/permissions after creating the group.' })
async post(@Body({ validate: true }) createUserGroup: CreateUserGroup) {
let userGroup;
try {
userGroup = await createUserGroup.toEntity();
} catch (error) {
throw error;
}
return this.userGroupsRepository.save(userGroup);
}
@Put('/:id')
@Authorized("USERGROUP:UPDATE")
@ResponseSchema(UserGroup)
@ResponseSchema(UserGroupNotFoundError, { statusCode: 404 })
@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." })
async put(@Param('id') id: number, @EntityFromBody() updateGroup: UpdateUserGroup) {
let oldGroup = await this.userGroupsRepository.findOne({ id: id });
if (!oldGroup) {
throw new UserGroupNotFoundError();
}
if (oldGroup.id != updateGroup.id) {
throw new UserGroupIdsNotMatchingError();
}
await this.userGroupsRepository.save(await updateGroup.update(oldGroup));
return (await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions', 'groups'] })).toResponse();
}
@Delete('/:id')
@Authorized("USERGROUP:DELETE")
@ResponseSchema(ResponseUserGroup)
@ResponseSchema(ResponseEmpty, { statusCode: 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).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let group = await this.userGroupsRepository.findOne({ id: id }, { relations: ["permissions"] });
if (!group) { return null; }
const responseGroup = await this.userGroupsRepository.findOne({ id: id }, { relations: ['permissions'] });
const permissionController = new PermissionController();
for (let permission of responseGroup.permissions) {
await permissionController.remove(permission.id, true);
}
await this.userGroupsRepository.delete(group);
return new ResponseUserGroup(responseGroup);
}
}

View File

@@ -0,0 +1,24 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw, when to provided address doesn't belong to the accepted types.
*/
export class AddressWrongTypeError extends NotAcceptableError {
@IsString()
name = "AddressWrongTypeError"
@IsString()
message = "The address must be an existing address's id. \n You provided a object of another type."
}
/**
* Error to throw, when a non-existent address get's loaded.
*/
export class AddressNotFoundError extends NotFoundError {
@IsString()
name = "AddressNotFoundError"
@IsString()
message = "The address you provided couldn't be located in the system. \n Please check your request."
}

140
src/errors/AuthError.ts Normal file
View File

@@ -0,0 +1,140 @@
import { IsString } from 'class-validator';
import { ForbiddenError, NotAcceptableError, NotFoundError, UnauthorizedError } from 'routing-controllers';
/**
* Error to throw when a jwt could not be parsed.
* For example: Wrong signature or expired.
*/
export class IllegalJWTError extends UnauthorizedError {
@IsString()
name = "IllegalJWTError"
@IsString()
message = "Your provided jwt could not be parsed."
}
/**
* Error to throw when user is nonexistant or refreshtoken is invalid.
* This can happen if someone provides a JWT with a invalid user id or the refreshTokenCount of the user is higher that the provided jwt's is.
*/
export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError {
@IsString()
name = "UserNonexistantOrRefreshtokenInvalidError"
@IsString()
message = "User is nonexistant or refreshtoken is invalid."
}
/**
* Error to throw when provided credentials are invalid.
* We don't have seperate errors for username/mail and passwords to protect against guessing attacks.
*/
export class InvalidCredentialsError extends UnauthorizedError {
@IsString()
name = "InvalidCredentialsError"
@IsString()
message = "Your provided credentials are invalid."
}
/**
* Error to throw when a jwt does not have permission for this route/action.
* Mainly used be the @Authorized decorator (via the authchecker).
*/
export class NoPermissionError extends ForbiddenError {
@IsString()
name = "NoPermissionError"
@IsString()
message = "Your provided jwt does not have permission for this route/ action."
}
/**
* Error to throw when no username and no email is set.
* Because we have to identify users somehow.
*/
export class UsernameOrEmailNeededError extends NotAcceptableError {
@IsString()
name = "UsernameOrEmailNeededError"
@IsString()
message = "Auth needs to have email or username set! \n You provided neither."
}
/**
* Error to throw when no password is provided for a new user.
* Passwords are the minimum we need for user security.
*/
export class PasswordNeededError extends NotAcceptableError {
@IsString()
name = "PasswordNeededError"
@IsString()
message = "No password is provided - you need to provide it."
}
/**
* Error to throw when no user could be found for a certain query.
*/
export class UserNotFoundError extends NotFoundError {
@IsString()
name = "UserNotFoundError"
@IsString()
message = "The user you provided couldn't be located in the system. \n Please check your request."
}
/**
* Error to throw when no jwt was provided (but one had to be).
*/
export class JwtNotProvidedError extends NotAcceptableError {
@IsString()
name = "JwtNotProvidedError"
@IsString()
message = "No jwt was provided."
}
/**
* Error to throw when user was not found or the jwt's refresh token count was invalid.
*/
export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableError {
@IsString()
name = "UserNotFoundOrRefreshTokenCountInvalidError"
@IsString()
message = "User was not found or the refresh token count is invalid."
}
/**
* Error to throw when refresh token count was invalid
*/
export class RefreshTokenCountInvalidError extends NotAcceptableError {
@IsString()
name = "RefreshTokenCountInvalidError"
@IsString()
message = "Refresh token count is invalid."
}
/**
* Error to throw when someone tries to reset a user's password more than once in 15 minutes.
*/
export class ResetAlreadyRequestedError extends NotAcceptableError {
@IsString()
name = "ResetAlreadyRequestedError"
@IsString()
message = "You already requested a password reset in the last 15 minutes. \n Please wait until the old reset code expires before requesting a new one."
}
/**
* Error to throw when someone tries a disabled user's password or login as a disabled user.
*/
export class UserDisabledError extends NotAcceptableError {
@IsString()
name = "UserDisabledError"
@IsString()
message = "This user is currently disabled. \n Please contact your administrator if this is a mistake."
}

View File

@@ -0,0 +1,25 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a Donation couldn't be found.
*/
export class DonationNotFoundError extends NotFoundError {
@IsString()
name = "DonationNotFoundError"
@IsString()
message = "Donation not found!"
}
/**
* Error to throw when two Donations' ids don't match.
* Usually occurs when a user tries to change a Donation's id.
*/
export class DonationIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "DonationIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a Donation's id: This isn't allowed!"
}

47
src/errors/DonorErrors.ts Normal file
View File

@@ -0,0 +1,47 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a donor couldn't be found.
*/
export class DonorNotFoundError extends NotFoundError {
@IsString()
name = "DonorNotFoundError"
@IsString()
message = "Donor not found!"
}
/**
* Error to throw when two donors' ids don't match.
* Usually occurs when a user tries to change a donor's id.
*/
export class DonorIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "DonorIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a donor's id: This isn't allowed!"
}
/**
* Error to throw when a donor needs a receipt, but no address is associated with them.
*/
export class DonorReceiptAddressNeededError extends NotAcceptableError {
@IsString()
name = "DonorReceiptAddressNeededError"
@IsString()
message = "An address is needed to create a receipt for a donor. \n You didn't provide one."
}
/**
* Error to throw when a donor still has donations associated.
*/
export class DonorHasDonationsError extends NotAcceptableError {
@IsString()
name = "DonorHasDonationsError"
@IsString()
message = "This donor still has donations associated with it. \n If you want to delete this donor with all it's donations and teams add `?force` to your query."
}

View File

@@ -0,0 +1,24 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw, when a provided groupContact doesn't belong to the accepted types.
*/
export class GroupContactWrongTypeError extends NotAcceptableError {
@IsString()
name = "GroupContactWrongTypeError"
@IsString()
message = "The groupContact must be an existing groupContact's id. \n You provided a object of another type."
}
/**
* Error to throw, when a non-existent groupContact get's loaded.
*/
export class GroupContactNotFoundError extends NotFoundError {
@IsString()
name = "GroupContactNotFoundError"
@IsString()
message = "The groupContact you provided couldn't be located in the system. \n Please check your request."
}

View File

@@ -0,0 +1,36 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a permission couldn't be found.
*/
export class PermissionNotFoundError extends NotFoundError {
@IsString()
name = "PermissionNotFoundError"
@IsString()
message = "Permission not found!"
}
/**
* Error to throw when two permissions' ids don't match.
* Usually occurs when a user tries to change a permission's id.
*/
export class PermissionIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "PermissionIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a permission's id: This isn't allowed!"
}
/**
* Error to throw when a permission gets provided without a principal.
*/
export class PermissionNeedsPrincipalError extends NotAcceptableError {
@IsString()
name = "PermissionNeedsPrincipalError"
@IsString()
message = "You provided no principal for this permission."
}

View File

@@ -0,0 +1,24 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a user couldn't be found.
*/
export class PrincipalNotFoundError extends NotFoundError {
@IsString()
name = "PrincipalNotFoundError"
@IsString()
message = "Principal not found!"
}
/**
* Error to throw, when a provided runner organization doesn't belong to the accepted types.
*/
export class PrincipalWrongTypeError extends NotAcceptableError {
@IsString()
name = "PrincipalWrongTypeError"
@IsString()
message = "The principal must have an existing principal's id. \n You provided a object of another type."
}

View File

@@ -0,0 +1,48 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a card couldn't be found.
*/
export class RunnerCardNotFoundError extends NotFoundError {
@IsString()
name = "RunnerCardNotFoundError"
@IsString()
message = "Card not found!"
}
/**
* Error to throw when two cards' ids don't match.
* Usually occurs when a user tries to change a card's id.
*/
export class RunnerCardIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "RunnerCardIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a cards's id: This isn't allowed"
}
/**
* Error to throw when a card still has scans associated.
*/
export class RunnerCardHasScansError extends NotAcceptableError {
@IsString()
name = "RunnerCardHasScansError"
@IsString()
message = "This card still has scans associated with it. \n If you want to delete this card with all it's scans add `?force` to your query. \n Otherwise please consider just disabling it."
}
/**
* Error to throw when a card's id is too big to generate a ean-13 barcode for it.
* This error should never reach a end user.
*/
export class RunnerCardIdOutOfRangeError extends Error {
@IsString()
name = "RunnerCardIdOutOfRangeError"
@IsString()
message = "The card's id is too big to fit into a ean-13 barcode. \n This has a very low probability of happening but means that you might want to switch your barcode format for something that can accept numbers over 9999999999."
}

View File

@@ -0,0 +1,47 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a runner couldn't be found.
*/
export class RunnerNotFoundError extends NotFoundError {
@IsString()
name = "RunnerNotFoundError"
@IsString()
message = "Runner not found!"
}
/**
* Error to throw when two runners' ids don't match.
* Usually occurs when a user tries to change a runner's id.
*/
export class RunnerIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "RunnerIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a runner's id: This isn't allowed!"
}
/**
* Error to throw when a runner is missing his group association.
*/
export class RunnerGroupNeededError extends NotAcceptableError {
@IsString()
name = "RunnerGroupNeededError"
@IsString()
message = "Runner's need to be part of one group (team or organisation)! \n You provided neither."
}
/**
* Error to throw when a runner still has distance donations associated.
*/
export class RunnerHasDistanceDonationsError extends NotAcceptableError {
@IsString()
name = "RunnerHasDistanceDonationsError"
@IsString()
message = "This runner still has distance donations associated with it. \n If you want to delete this runner with all it's donations and teams add `?force` to your query."
}

View File

@@ -0,0 +1,13 @@
import { IsString } from 'class-validator';
import { NotFoundError } from 'routing-controllers';
/**
* Error to throw when a runner group couldn't be found.
*/
export class RunnerGroupNotFoundError extends NotFoundError {
@IsString()
name = "RunnerGroupNotFoundError"
@IsString()
message = "RunnerGroup not found!"
}

View File

@@ -0,0 +1,58 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a runner organisation couldn't be found.
*/
export class RunnerOrganisationNotFoundError extends NotFoundError {
@IsString()
name = "RunnerOrganisationNotFoundError"
@IsString()
message = "RunnerOrganisation not found!"
}
/**
* Error to throw when two runner organisation's ids don't match.
* Usually occurs when a user tries to change a runner organisation's id.
*/
export class RunnerOrganisationIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a runner organisation's id: This isn't allowed!"
}
/**
* Error to throw when a organisation still has runners associated.
*/
export class RunnerOrganisationHasRunnersError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationHasRunnersError"
@IsString()
message = "This organisation still has runners associated with it. \n If you want to delete this organisation with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw when a organisation still has teams associated.
*/
export class RunnerOrganisationHasTeamsError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationHasTeamsError"
@IsString()
message = "This organisation still has teams associated with it. \n If you want to delete this organisation with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw, when a provided runnerOrganisation doesn't belong to the accepted types.
*/
export class RunnerOrganisationWrongTypeError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationWrongTypeError"
@IsString()
message = "The runner organisation must be an existing organisation's id. \n You provided a object of another type."
}

View File

@@ -0,0 +1,47 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a runner team couldn't be found.
*/
export class RunnerTeamNotFoundError extends NotFoundError {
@IsString()
name = "RunnerTeamNotFoundError"
@IsString()
message = "RunnerTeam not found!"
}
/**
* Error to throw when two runner teams' ids don't match.
* Usually occurs when a user tries to change a runner team's id.
*/
export class RunnerTeamIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "RunnerTeamIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a runner's id: This isn't allowed!"
}
/**
* Error to throw when a team still has runners associated.
*/
export class RunnerTeamHasRunnersError extends NotAcceptableError {
@IsString()
name = "RunnerTeamHasRunnersError"
@IsString()
message = "This team still has runners associated with it. \n If you want to delete this team with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw when a team still has runners associated.
*/
export class RunnerTeamNeedsParentError extends NotAcceptableError {
@IsString()
name = "RunnerTeamNeedsParentError"
@IsString()
message = "You provided no runner organisation as this team's parent group."
}

25
src/errors/ScanErrors.ts Normal file
View File

@@ -0,0 +1,25 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a Scan couldn't be found.
*/
export class ScanNotFoundError extends NotFoundError {
@IsString()
name = "ScanNotFoundError"
@IsString()
message = "Scan not found!"
}
/**
* Error to throw when two Scans' ids don't match.
* Usually occurs when a user tries to change a Scan's id.
*/
export class ScanIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "ScanIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a Scan's id: This isn't allowed!"
}

View File

@@ -0,0 +1,36 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw, when a non-existent scan station get's loaded.
*/
export class ScanStationNotFoundError extends NotFoundError {
@IsString()
name = "ScanStationNotFoundError"
@IsString()
message = "The scan station you provided couldn't be located in the system. \n Please check your request."
}
/**
* Error to throw when two scan stations' ids don't match.
* Usually occurs when a user tries to change a scan station's id.
*/
export class ScanStationIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "ScanStationIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a scan station's id: This isn't allowed!"
}
/**
* Error to throw when a station still has scans associated.
*/
export class ScanStationHasScansError extends NotAcceptableError {
@IsString()
name = "ScanStationHasScansError"
@IsString()
message = "This station still has scans associated with it. \n If you want to delete this station with all it's scans add `?force` to your query."
}

View File

@@ -0,0 +1,25 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw, when a non-existent stats client get's loaded.
*/
export class StatsClientNotFoundError extends NotFoundError {
@IsString()
name = "StatsClientNotFoundError"
@IsString()
message = "The stats client you provided couldn't be located in the system. \n Please check your request."
}
/**
* Error to throw when two stats clients' ids don't match.
* Usually occurs when a user tries to change a stats client's id.
*/
export class StatsClientIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "StatsClientIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a stats client's id: This isn't allowed!"
}

44
src/errors/TrackErrors.ts Normal file
View File

@@ -0,0 +1,44 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a track couldn't be found.
*/
export class TrackNotFoundError extends NotFoundError {
@IsString()
name = "TrackNotFoundError"
@IsString()
message = "Track not found!"
}
/**
* Error to throw when two tracks' ids don't match.
* Usually occurs when a user tries to change a track's id.
*/
export class TrackIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "TrackIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a track's id: This isn't allowed"
}
/**
* Error to throw when a track's lap time is set to a negative value.
*/
export class TrackLapTimeCantBeNegativeError extends NotAcceptableError {
@IsString()
name = "TrackLapTimeCantBeNegativeError"
@IsString()
message = "The minimum lap time you provided is negative - That isn't possible. \n If you wanted to disable it: Just set it to 0/null."
}
export class TrackHasScanStationsError extends NotAcceptableError {
@IsString()
name = "TrackHasScanStationsError"
@IsString()
message = "This track still has stations associated with it. \n If you want to delete this track with all it's stations and scans add `?force` to your query."
}

62
src/errors/UserErrors.ts Normal file
View File

@@ -0,0 +1,62 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when no username or email is set.
* We somehow need to identify you on login.
*/
export class UsernameOrEmailNeededError extends NotFoundError {
@IsString()
name = "UsernameOrEmailNeededError"
@IsString()
message = "No username or email is set!"
}
/**
* Error to throw when no username contains illegal characters.
* Right now the only one is "@" but this could change in the future.
*/
export class UsernameContainsIllegalCharacterError extends NotAcceptableError {
@IsString()
name = "UsernameContainsIllegalCharacterError"
@IsString()
message = "The provided username contains illegal characters! \n Right now the following characters are considered illegal: '@'"
}
/**
* Error to throw when no email is set.
* We somehow need to identify you :)
*/
export class UserEmailNeededError extends NotFoundError {
@IsString()
name = "UserEmailNeededError"
@IsString()
message = "No email is set! \n You have to provide email addresses for users (used for password reset among others)."
}
/**
* Error to throw when a user couldn't be found.
*/
export class UserNotFoundError extends NotFoundError {
@IsString()
name = "UserNotFoundError"
@IsString()
message = "User not found!"
}
/**
* Error to throw when two users' ids don't match.
* Usually occurs when a user tries to change a user's id.
*/
export class UserIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "UserIdsNotMatchingError"
@IsString()
message = "The ids don't match!! \n And if you wanted to change a user's id: This isn't allowed!"
}

View File

@@ -0,0 +1,36 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when no group name is set.
*/
export class GroupNameNeededError extends NotFoundError {
@IsString()
name = "GroupNameNeededError"
@IsString()
message = "No name is set for this group!"
}
/**
* Error to throw when a user group couldn't be found.
*/
export class UserGroupNotFoundError extends NotFoundError {
@IsString()
name = "UserGroupNotFoundError"
@IsString()
message = "User Group not found!"
}
/**
* Error to throw when two user groups' ids don't match.
* Usually occurs when a user tries to change a user groups's id.
*/
export class UserGroupIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "UserGroupIdsNotMatchingError"
@IsString()
message = "The ids don't match!! \n If you wanted to change a user group's id: This isn't allowed!"
}

111
src/jwtcreator.ts Normal file
View File

@@ -0,0 +1,111 @@
import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
import * as jsonwebtoken from "jsonwebtoken";
import { config } from './config';
import { User } from './models/entities/User';
/**
* This class is responsible for all things JWT creation.
*/
export class JwtCreator {
/**
* Creates a new refresh token for a given user
* @param user User entity that the refresh token shall be created for
* @param expiry_timestamp Timestamp for the token expiry. Will be generated if not provided.
*/
public static createRefresh(user: User, expiry_timestamp?: number) {
if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; }
return jsonwebtoken.sign({
refreshTokenCount: user.refreshTokenCount,
id: user.id,
exp: expiry_timestamp
}, config.jwt_secret)
}
/**
* Creates a new access token for a given user
* @param user User entity that the access token shall be created for
* @param expiry_timestamp Timestamp for the token expiry. Will be generated if not provided.
*/
public static createAccess(user: User, expiry_timestamp?: number) {
if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; }
return jsonwebtoken.sign({
userdetails: new JwtUser(user),
exp: expiry_timestamp
}, config.jwt_secret)
}
/**
* Creates a new password reset token for a given user.
* The token is valid for 15 minutes or 1 use - whatever comes first.
* @param user User entity that the password reset token shall be created for
*/
public static createReset(user: User) {
let expiry_timestamp = Math.floor(Date.now() / 1000) + 15 * 60;
return jsonwebtoken.sign({
id: user.id,
refreshTokenCount: user.refreshTokenCount,
exp: expiry_timestamp
}, config.jwt_secret)
}
}
/**
* Special variant of the user class that
*/
export class JwtUser {
@IsInt()
id: number;
@IsUUID(4)
uuid: string;
@IsOptional()
@IsEmail()
email?: string;
@IsOptional()
@IsString()
username?: string;
@IsString()
@IsNotEmpty()
firstname: string;
@IsString()
@IsOptional()
middlename?: string;
@IsString()
@IsNotEmpty()
lastname: string;
permissions: string[];
@IsBoolean()
enabled: boolean;
@IsInt()
@IsNotEmpty()
refreshTokenCount?: number;
@IsString()
@IsOptional()
profilePic?: string;
/**
* Creates a new instance of this class based on a provided user entity.
* @param user User entity that shall be encapsulated in a jwt.
*/
public constructor(user: User) {
this.id = user.id;
this.firstname = user.firstname;
this.middlename = user.middlename;
this.lastname = user.lastname;
this.username = user.username;
this.email = user.email;
this.refreshTokenCount = user.refreshTokenCount;
this.uuid = user.uuid;
this.profilePic = user.profilePic;
this.permissions = user.allPermissions;
}
}

View File

@@ -1,7 +1,16 @@
import { createConnection } from "typeorm";
import { runSeeder } from 'typeorm-seeding';
import { User } from '../models/entities/User';
import SeedUsers from '../seeds/SeedUsers';
/**
* Loader for the database that creates the database connection and initializes the database tabels.
* It also triggers the seeding process if no users got detected in the database.
*/
export default async () => {
const connection = await createConnection();
connection.synchronize();
await connection.synchronize();
if (await connection.getRepository(User).count() === 0) {
await runSeeder(SeedUsers);
}
return connection;
};

View File

@@ -1,8 +1,13 @@
import cookieParser from "cookie-parser";
import { Application } from "express";
import bodyParser from 'body-parser';
import cors from 'cors';
/**
* Loader for express related configurations.
* Configures proxy trusts, globally used middlewares and other express features.
*/
export default async (app: Application) => {
app.enable('trust proxy');
app.disable('x-powered-by');
app.disable('x-served-by');
app.use(cookieParser());
return app;
};

View File

@@ -1,8 +1,12 @@
import { Application } from "express";
import databaseLoader from "./database";
import expressLoader from "./express";
import openapiLoader from "./openapi";
import databaseLoader from "./database";
import { Application } from "express";
/**
* Index Loader that executes the other loaders in the right order.
* This basicly exists for abstraction and a overall better dev experience.
*/
export default async (app: Application) => {
await databaseLoader();
await openapiLoader(app);

View File

@@ -1,40 +1,24 @@
import { Application } from "express";
import * as swaggerUiExpress from "swagger-ui-express";
import { getMetadataArgsStorage } from "routing-controllers";
import { routingControllersToSpec } from "routing-controllers-openapi";
import { validationMetadatasToSchemas } from "class-validator-jsonschema";
import express, { Application } from "express";
import path from 'path';
import { getMetadataArgsStorage } from "routing-controllers";
import { generateSpec } from '../apispec';
/**
* Loader for everything openapi related - from creating the schema to serving it via a static route and swaggerUiExpress.
* All auth schema related stuff also has to be configured here
*/
export default async (app: Application) => {
const storage = getMetadataArgsStorage();
const schemas = validationMetadatasToSchemas({
refPointerPrefix: "#/components/schemas/",
});
const spec = routingControllersToSpec(
storage,
{
routePrefix: "/api"
},
{
components: {
schemas,
},
info: {
description: "The the backend API for the LfK! runner system.",
title: "LfK! Backend API",
version: "1.0.0",
},
}
);
const options = {
explorer: true,
};
app.use(
"/api/docs",
swaggerUiExpress.serve,
swaggerUiExpress.setup(spec, options)
);
app.get(["/api/openapi.json", "/api/swagger.json"], (req, res) => {
//Spec creation based on the previously created schemas
const spec = generateSpec(storage, schemas);
app.get(["/api/docs/openapi.json", "/api/docs/swagger.json"], (req, res) => {
res.json(spec);
});
app.use('/api/docs', express.static(path.join(__dirname, '../static/docs'), { index: "index.html", extensions: ['html'] }));
return app;
};

View File

@@ -0,0 +1,14 @@
import { ExpressErrorMiddlewareInterface, Middleware } from "routing-controllers";
/**
* Our Error handling middlware that returns our custom httperrors to the user.
*/
@Middleware({ type: "after" })
export class ErrorHandler implements ExpressErrorMiddlewareInterface {
public error(error: any, request: any, response: any, next: (err: any) => any) {
if (response.headersSent) {
return;
}
response.json(error);
}
}

View File

@@ -0,0 +1,23 @@
import { Request, Response } from 'express';
/**
* Custom express middleware that appends the raw body to the request object.
* Mainly used for parsing csvs from bodies.
*/
const RawBodyMiddleware = (req: Request, res: Response, next: () => void) => {
const body = []
req.on('data', chunk => {
body.push(chunk)
})
req.on('end', () => {
const rawBody = Buffer.concat(body)
req['rawBody'] = rawBody
next()
})
req.on('error', () => {
res.sendStatus(400)
})
}
export default RawBodyMiddleware

View File

@@ -0,0 +1,69 @@
import * as argon2 from "argon2";
import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm';
import { ScanStation } from '../models/entities/ScanStation';
import authchecker from './authchecker';
/**
* This middleware handles the authentication of scan station api tokens.
* The tokens have to be provided via Bearer authorization header.
* You have to manually use this middleware via @UseBefore(ScanAuth) instead of using @Authorized().
* @param req Express request object.
* @param res Express response object.
* @param next Next function to call on success.
*/
const ScanAuth = async (req: Request, res: Response, next: () => void) => {
let provided_token: string = req.headers["authorization"];
if (provided_token == "" || provided_token === undefined || provided_token === null) {
res.status(401).send("No api token provided.");
return;
}
try {
provided_token = provided_token.replace("Bearer ", "");
} catch (error) {
res.status(401).send("No valid jwt or api token provided.");
return;
}
let prefix = "";
try {
prefix = provided_token.split(".")[0];
}
finally {
if (prefix == "" || prefix == undefined || prefix == null) {
res.status(401).send("Api token non-existent or invalid syntax.");
return;
}
}
const station = await getConnectionManager().get().getRepository(ScanStation).findOne({ prefix: prefix });
if (!station) {
let user_authorized = false;
try {
let action = { request: req, response: res, context: null, next: next }
user_authorized = await authchecker(action, ["SCAN:CREATE"]);
}
finally {
if (user_authorized == false) {
res.status(401).send("Api token non-existent or invalid syntax.");
return;
}
else {
next();
}
}
}
else {
if (station.enabled == false) {
res.status(401).send("Station disabled.");
}
if (!(await argon2.verify(station.key, provided_token))) {
res.status(401).send("Api token invalid.");
return;
}
next();
}
}
export default ScanAuth;

View File

@@ -0,0 +1,66 @@
import * as argon2 from "argon2";
import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm';
import { StatsClient } from '../models/entities/StatsClient';
import authchecker from './authchecker';
/**
* This middleware handles the authentication of stats client api tokens.
* The tokens have to be provided via Bearer authorization header.
* You have to manually use this middleware via @UseBefore(StatsAuth) instead of using @Authorized().
* @param req Express request object.
* @param res Express response object.
* @param next Next function to call on success.
*/
const StatsAuth = async (req: Request, res: Response, next: () => void) => {
let provided_token: string = req.headers["authorization"];
if (provided_token == "" || provided_token === undefined || provided_token === null) {
res.status(401).send("No api token provided.");
return;
}
try {
provided_token = provided_token.replace("Bearer ", "");
} catch (error) {
res.status(401).send("No valid jwt or api token provided.");
return;
}
let prefix = "";
try {
prefix = provided_token.split(".")[0];
}
finally {
if (prefix == "" || prefix == undefined || prefix == null) {
res.status(401).send("Api token non-existant or invalid syntax.");
return;
}
}
const client = await getConnectionManager().get().getRepository(StatsClient).findOne({ prefix: prefix });
if (!client) {
let user_authorized = false;
try {
let action = { request: req, response: res, context: null, next: next }
user_authorized = await authchecker(action, ["RUNNER:GET", "TEAM:GET", "ORGANISATION:GET"]);
}
finally {
if (user_authorized == false) {
res.status(401).send("Api token non-existant or invalid syntax.");
return;
}
else {
next();
}
}
}
else {
if (!(await argon2.verify(client.key, provided_token))) {
res.status(401).send("Api token invalid.");
return;
}
next();
}
}
export default StatsAuth;

View File

@@ -0,0 +1,74 @@
import cookie from "cookie";
import * as jwt from "jsonwebtoken";
import { Action } from "routing-controllers";
import { getConnectionManager } from 'typeorm';
import { config } from '../config';
import { IllegalJWTError, NoPermissionError, UserDisabledError, UserNonexistantOrRefreshtokenInvalidError } from '../errors/AuthError';
import { JwtCreator, JwtUser } from '../jwtcreator';
import { User } from '../models/entities/User';
/**
* Handles authentication via jwt's (Bearer authorization header) for all api endpoints using the @Authorized decorator.
* @param action Routing-Controllers action object that provides request and response objects among other stuff.
* @param permissions The permissions that the endpoint using @Authorized requires.
*/
const authchecker = async (action: Action, permissions: string[] | string) => {
let required_permissions = undefined;
if (typeof permissions === "string") {
required_permissions = [permissions]
} else {
required_permissions = permissions
}
let jwtPayload = undefined
try {
let provided_token = "" + action.request.headers["authorization"].replace("Bearer ", "");
jwtPayload = <any>jwt.verify(provided_token, config.jwt_secret);
jwtPayload = jwtPayload["userdetails"];
} catch (error) {
jwtPayload = await refresh(action);
}
const user = await getConnectionManager().get().getRepository(User).findOne({ id: jwtPayload["id"], refreshTokenCount: jwtPayload["refreshTokenCount"] }, { relations: ['permissions'] })
if (!user) { throw new UserNonexistantOrRefreshtokenInvalidError() }
if (user.enabled == false) { throw new UserDisabledError(); }
if (!jwtPayload["permissions"]) { throw new NoPermissionError(); }
action.response.local = {}
action.response.local.jwtPayload = jwtPayload;
for (let required_permission of required_permissions) {
if (!(jwtPayload["permissions"].includes(required_permission))) { return false; }
}
return true;
}
/**
* Handles soft-refreshing of access-tokens.
* @param action Routing-Controllers action object that provides request and response objects among other stuff.
*/
const refresh = async (action: Action) => {
let refresh_token = undefined;
try {
refresh_token = cookie.parse(action.request.headers["cookie"])["lfk_backend__refresh_token"];
}
catch {
throw new IllegalJWTError();
}
let jwtPayload = undefined;
try {
jwtPayload = <any>jwt.verify(refresh_token, config.jwt_secret);
} catch (error) {
throw new IllegalJWTError();
}
const user = await getConnectionManager().get().getRepository(User).findOne({ id: jwtPayload["id"], refreshTokenCount: jwtPayload["refreshTokenCount"] }, { relations: ['permissions', 'groups', 'groups.permissions'] })
if (!user) { throw new UserNonexistantOrRefreshtokenInvalidError() }
if (user.enabled == false) { throw new UserDisabledError(); }
let newAccess = JwtCreator.createAccess(user);
action.response.header("authorization", "Bearer " + newAccess);
return await new JwtUser(user);
}
export default authchecker

View File

@@ -1,17 +0,0 @@
import { Request, Response, NextFunction } from "express";
// import bodyParser from 'body-parser';
// import cors from 'cors';
import * as jwt from "jsonwebtoken";
export default (req: Request, res: Response, next: NextFunction) => {
const token = <string>req.headers["auth"];
try {
const jwtPayload = <any>jwt.verify(token, "secretjwtsecret");
// const jwtPayload = <any>jwt.verify(token, process.env.JWT_SECRET);
res.locals.jwtPayload = jwtPayload;
} catch (error) {
console.log(error);
return res.status(401).send();
}
next();
};

View File

@@ -1,32 +0,0 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
import {
IsInt,
IsNotEmpty,
IsOptional,
IsPositive,
IsString,
} from "class-validator";
/**
* @classdesc Defines a track of given length.
* @property {number} id - Autogenerated unique id
* @property {string} name - The track's name
* @property {number} lenth - The track's length in meters
*/
@Entity()
export class Track {
@PrimaryGeneratedColumn()
@IsOptional()
@IsInt()
id: number;
@Column()
@IsString()
@IsNotEmpty()
name: string;
@Column()
@IsInt()
@IsPositive()
length: number;
}

View File

@@ -0,0 +1,49 @@
import { IsOptional, IsString } from 'class-validator';
import * as jsonwebtoken from 'jsonwebtoken';
import { getConnectionManager } from 'typeorm';
import { config } from '../../config';
import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError';
import { User } from '../entities/User';
import { Logout } from '../responses/ResponseLogout';
/**
* This class handels a user logging out of the system.
* Of course it check's the user's provided credential (token) before logging him out.
*/
export class HandleLogout {
/**
* A stringyfied jwt access token.
* Will get checked for validity.
*/
@IsString()
@IsOptional()
token?: string;
/**
* Logs the user out.
* This gets achived by increasing the user's refresh token count, thereby invalidateing all currently existing jwts for that user.
*/
public async logout(): Promise<Logout> {
let logout: Logout = new Logout();
if (!this.token || this.token === undefined) {
throw new JwtNotProvidedError()
}
let decoded;
try {
decoded = jsonwebtoken.verify(this.token, config.jwt_secret)
} catch (error) {
throw new IllegalJWTError()
}
logout.timestamp = Math.floor(Date.now() / 1000)
let found_user: User = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["id"] });
if (!found_user) {
throw new UserNotFoundError()
}
if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) {
throw new RefreshTokenCountInvalidError()
}
found_user.refreshTokenCount++;
await getConnectionManager().get().getRepository(User).update({ id: found_user.id }, found_user)
return logout;
}
}

View File

@@ -0,0 +1,97 @@
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { RunnerGroupNeededError } from '../../errors/RunnerErrors';
import { RunnerOrganisationNotFoundError } from '../../errors/RunnerOrganisationErrors';
import { RunnerGroup } from '../entities/RunnerGroup';
import { RunnerOrganisation } from '../entities/RunnerOrganisation';
import { RunnerTeam } from '../entities/RunnerTeam';
import { CreateRunner } from './create/CreateRunner';
/**
* Special class used to import runners from csv files - or json arrays created from csv to be exact.
* Why you ask? Because the past has shown us that a non excel/csv based workflow is too much for most schools.
*/
export class ImportRunner {
/**
* The new runner's first name.
*/
@IsString()
@IsNotEmpty()
firstname: string;
/**
* The new runner's middle name.
*/
@IsString()
@IsOptional()
middlename?: string;
/**
* The new runner's last name.
*/
@IsString()
@IsNotEmpty()
lastname: string;
/**
* The new runner's team's name (if not provided otherwise).
* The team will automaticly get generated if it doesn't exist in this org yet.
*/
@IsString()
@IsOptional()
team?: string;
/**
* Just an alias for team, because this is usually only used for importing data from schools.
*/
@IsOptional()
@IsString()
public set class(value: string) {
this.team = value;
}
/**
* Creates a CreateRunner object based on this.
* @param groupID Either the id of the new runner's group or the id of the org that the new runner's team is a part of.
*/
public async toCreateRunner(groupID: number): Promise<CreateRunner> {
let newRunner: CreateRunner = new CreateRunner();
newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname;
newRunner.group = (await this.getGroup(groupID)).id;
return newRunner;
}
/**
* Get's the new runners group.
* @param groupID Either the id of the new runner's group or the id of the org that the new runner's team is a part of.
*/
public async getGroup(groupID: number): Promise<RunnerGroup> {
if (this.team === undefined && groupID === undefined) {
throw new RunnerGroupNeededError();
}
let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: groupID });
if (team) { return team; }
let org = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: groupID });
if (!org) {
throw new RunnerOrganisationNotFoundError();
}
if (this.team === undefined) { return org; }
team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: org });
if (!team) {
let newRunnerTeam: RunnerTeam = new RunnerTeam();
newRunnerTeam.name = this.team;
newRunnerTeam.parentGroup = org;
team = await getConnectionManager().get().getRepository(RunnerTeam).save(newRunnerTeam);
}
return team;
}
}

View File

@@ -0,0 +1,56 @@
import { IsOptional, IsString } from 'class-validator';
import * as jsonwebtoken from 'jsonwebtoken';
import { getConnectionManager } from 'typeorm';
import { config } from '../../config';
import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserDisabledError, UserNotFoundError } from '../../errors/AuthError';
import { JwtCreator } from "../../jwtcreator";
import { User } from '../entities/User';
import { ResponseAuth } from '../responses/ResponseAuth';
/**
* This class is used to create refreshed auth credentials.
* To be a little bit more exact: Is takes in a refresh token and creates a new access and refresh token for it's user.
* It of course checks for user existance, jwt validity and so on.
*/
export class RefreshAuth {
/**
* A stringyfied jwt refresh token.
* Will get checked for validity.
*/
@IsString()
@IsOptional()
token?: string;
/**
* Creates a new auth object based on this.
*/
public async toAuth(): Promise<ResponseAuth> {
let newAuth: ResponseAuth = new ResponseAuth();
if (!this.token || this.token === undefined) {
throw new JwtNotProvidedError()
}
let decoded
try {
decoded = jsonwebtoken.verify(this.token, config.jwt_secret)
} catch (error) {
throw new IllegalJWTError()
}
const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["id"] }, { relations: ['groups', 'permissions', 'groups.permissions'] });
if (!found_user) {
throw new UserNotFoundError()
}
if (found_user.enabled == false) { throw new UserDisabledError(); }
if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) {
throw new RefreshTokenCountInvalidError()
}
//Create the auth token
const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60
newAuth.access_token = JwtCreator.createAccess(found_user, timestamp_accesstoken_expiry);
newAuth.access_token_expires_at = timestamp_accesstoken_expiry
//Create the refresh token
const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000
newAuth.refresh_token = JwtCreator.createRefresh(found_user, timestamp_refresh_expiry);
newAuth.refresh_token_expires_at = timestamp_refresh_expiry;
return newAuth;
}
}

View File

@@ -0,0 +1,57 @@
import * as argon2 from "argon2";
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import * as jsonwebtoken from 'jsonwebtoken';
import { getConnectionManager } from 'typeorm';
import { config } from '../../config';
import { IllegalJWTError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError';
import { User } from '../entities/User';
/**
* This class can be used to reset a user's password.
* To set a new password the user needs to provide a valid password reset token.
*/
export class ResetPassword {
/**
* The reset token on which the password reset will be based.
*/
@IsOptional()
@IsString()
resetToken?: string;
/**
* The user's new password
*/
@IsNotEmpty()
@IsString()
password: string;
/**
* Create a password reset token based on this.
*/
public async resetPassword(): Promise<any> {
if (!this.resetToken || this.resetToken === undefined) {
throw new JwtNotProvidedError()
}
if (!this.password || this.password === undefined) {
throw new PasswordNeededError()
}
let decoded;
try {
decoded = jsonwebtoken.verify(this.resetToken, config.jwt_secret)
} catch (error) {
throw new IllegalJWTError()
}
const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["id"] });
if (!found_user) { throw new UserNotFoundError(); }
if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) { throw new RefreshTokenCountInvalidError(); }
found_user.refreshTokenCount = found_user.refreshTokenCount + 1;
found_user.password = await argon2.hash(this.password + found_user.uuid);
await getConnectionManager().get().getRepository(User).save(found_user);
return "password reset successfull";
}
}

View File

@@ -0,0 +1,70 @@
import { IsNotEmpty, IsOptional, IsPostalCode, IsString } from 'class-validator';
import { config } from '../../../config';
import { Address } from '../../entities/Address';
/**
* This classed is used to create a new Address entity from a json body (post request).
*/
export class CreateAddress {
/**
* The newaddress's description.
*/
@IsString()
@IsOptional()
description?: string;
/**
* The new address's first line.
* Containing the street and house number.
*/
@IsString()
@IsNotEmpty()
address1: string;
/**
* The new address's second line.
* Containing optional information.
*/
@IsString()
@IsOptional()
address2?: string;
/**
* The new address's postal code.
* This will get checked against the postal code syntax for the configured country.
* TODO: Implement the config option.
*/
@IsString()
@IsNotEmpty()
@IsPostalCode(config.postalcode_validation_countrycode)
postalcode: string;
/**
* The new address's city.
*/
@IsString()
@IsNotEmpty()
city: string;
/**
* The new address's country.
*/
@IsString()
@IsNotEmpty()
country: string;
/**
* Creates a new Address entity from this.
*/
public async toEntity(): Promise<Address> {
let newAddress: Address = new Address();
newAddress.address1 = this.address1;
newAddress.address2 = this.address2;
newAddress.postalcode = this.postalcode;
newAddress.city = this.city;
newAddress.country = this.country;
return newAddress;
}
}

View File

@@ -0,0 +1,73 @@
import * as argon2 from "argon2";
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { InvalidCredentialsError, PasswordNeededError, UserDisabledError, UserNotFoundError } from '../../../errors/AuthError';
import { UsernameOrEmailNeededError } from '../../../errors/UserErrors';
import { JwtCreator } from '../../../jwtcreator';
import { User } from '../../entities/User';
import { ResponseAuth } from '../../responses/ResponseAuth';
/**
* This class is used to create auth credentials based on user credentials provided in a json body (post request).
* To be a little bit more exact: Is takes in a username/email + password and creates a new access and refresh token for the user.
* It of course checks for user existance, password validity and so on.
*/
export class CreateAuth {
/**
* The username of the user that want's to login.
* Either username or email have to be provided.
*/
@IsOptional()
@IsString()
username?: string;
/**
* The email address of the user that want's to login.
* Either username or email have to be provided.
*/
@IsOptional()
@IsEmail()
@IsString()
email?: string;
/**
* The user's password.
* Will be checked against an argon2 hash.
*/
@IsNotEmpty()
@IsString()
password: string;
/**
* Creates a new auth object based on this.
*/
public async toAuth(): Promise<ResponseAuth> {
let newAuth: ResponseAuth = new ResponseAuth();
if (this.email === undefined && this.username === undefined) {
throw new UsernameOrEmailNeededError();
}
if (!this.password) {
throw new PasswordNeededError();
}
const found_user = await getConnectionManager().get().getRepository(User).findOne({ relations: ['groups', 'permissions', 'groups.permissions'], where: [{ username: this.username }, { email: this.email }] });
if (!found_user) {
throw new UserNotFoundError();
}
if (found_user.enabled == false) { throw new UserDisabledError(); }
if (!(await argon2.verify(found_user.password, this.password + found_user.uuid))) {
throw new InvalidCredentialsError();
}
//Create the access token
const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60
newAuth.access_token = JwtCreator.createAccess(found_user, timestamp_accesstoken_expiry);
newAuth.access_token_expires_at = timestamp_accesstoken_expiry
//Create the refresh token
const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000
newAuth.refresh_token = JwtCreator.createRefresh(found_user, timestamp_refresh_expiry);
newAuth.refresh_token_expires_at = timestamp_refresh_expiry
return newAuth;
}
}

View File

@@ -0,0 +1,52 @@
import { IsInt, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
import { DistanceDonation } from '../../entities/DistanceDonation';
import { Runner } from '../../entities/Runner';
import { CreateDonation } from './CreateDonation';
/**
* This class is used to create a new FixedDonation entity from a json body (post request).
*/
export class CreateDistanceDonation extends CreateDonation {
/**
* The donation's associated runner.
* This is important to link the runner's distance ran to the donation.
*/
@IsInt()
@IsPositive()
runner: number;
/**
* The donation's amount per distance (full kilometer aka 1000 meters).
* The unit is your currency's smallest unit (default: euro cent).
*/
@IsInt()
@IsPositive()
amountPerDistance: number;
/**
* Creates a new FixedDonation entity from this.
*/
public async toEntity(): Promise<DistanceDonation> {
let newDonation = new DistanceDonation;
newDonation.amountPerDistance = this.amountPerDistance;
newDonation.donor = await this.getDonor();
newDonation.runner = await this.getRunner();
return newDonation;
}
/**
* Gets a runner based on the runner id provided via this.runner.
*/
public async getRunner(): Promise<Runner> {
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
if (!runner) {
throw new RunnerNotFoundError();
}
return runner;
}
}

View File

@@ -0,0 +1,34 @@
import { IsInt, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { DonorNotFoundError } from '../../../errors/DonorErrors';
import { Donation } from '../../entities/Donation';
import { Donor } from '../../entities/Donor';
/**
* This class is used to create a new Donation entity from a json body (post request).
*/
export abstract class CreateDonation {
/**
* The donation's associated donor.
* This is important to link donations to donors.
*/
@IsInt()
@IsPositive()
donor: number;
/**
* Creates a new Donation entity from this.
*/
public abstract toEntity(): Promise<Donation>;
/**
* Gets a donor based on the donor id provided via this.donor.
*/
public async getDonor(): Promise<Donor> {
const donor = await getConnection().getRepository(Donor).findOne({ id: this.donor });
if (!donor) {
throw new DonorNotFoundError();
}
return donor;
}
}

View File

@@ -0,0 +1,38 @@
import { IsBoolean, IsOptional } from 'class-validator';
import { DonorReceiptAddressNeededError } from '../../../errors/DonorErrors';
import { Donor } from '../../entities/Donor';
import { CreateParticipant } from './CreateParticipant';
/**
* This classed is used to create a new Donor entity from a json body (post request).
*/
export class CreateDonor extends CreateParticipant {
/**
* Does this donor need a receipt?
*/
@IsBoolean()
@IsOptional()
receiptNeeded?: boolean = false;
/**
* Creates a new Donor entity from this.
*/
public async toEntity(): Promise<Donor> {
let newDonor: Donor = new Donor();
newDonor.firstname = this.firstname;
newDonor.middlename = this.middlename;
newDonor.lastname = this.lastname;
newDonor.phone = this.phone;
newDonor.email = this.email;
newDonor.address = await this.getAddress();
newDonor.receiptNeeded = this.receiptNeeded;
if (this.receiptNeeded == true && this.address == null) {
throw new DonorReceiptAddressNeededError()
}
return newDonor;
}
}

View File

@@ -0,0 +1,28 @@
import { IsInt, IsPositive } from 'class-validator';
import { FixedDonation } from '../../entities/FixedDonation';
import { CreateDonation } from './CreateDonation';
/**
* This class is used to create a new FixedDonation entity from a json body (post request).
*/
export class CreateFixedDonation extends CreateDonation {
/**
* The donation's amount.
* The unit is your currency's smallest unit (default: euro cent).
*/
@IsInt()
@IsPositive()
amount: number;
/**
* Creates a new FixedDonation entity from this.
*/
public async toEntity(): Promise<FixedDonation> {
let newDonation = new FixedDonation;
newDonation.amount = this.amount;
newDonation.donor = await this.getDonor();
return newDonation;
}
}

View File

@@ -0,0 +1,85 @@
import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { config } from '../../../config';
import { AddressNotFoundError, AddressWrongTypeError } from '../../../errors/AddressErrors';
import { Address } from '../../entities/Address';
import { GroupContact } from '../../entities/GroupContact';
/**
* This classed is used to create a new Group entity from a json body (post request).
*/
export class CreateGroupContact {
/**
* The new contact's first name.
*/
@IsNotEmpty()
@IsString()
firstname: string;
/**
* The new contact's middle name.
*/
@IsOptional()
@IsString()
middlename?: string;
/**
* The new contact's last name.
*/
@IsNotEmpty()
@IsString()
lastname: string;
/**
* The new contact's address.
* Must be the address's id.
*/
@IsInt()
@IsOptional()
address?: number;
/**
* The contact's phone number.
* This will be validated against the configured country phone numer syntax (default: international).
*/
@IsOptional()
@IsPhoneNumber(config.phone_validation_countrycode)
phone?: string;
/**
* The contact's email address.
*/
@IsOptional()
@IsEmail()
email?: string;
/**
* Gets the new contact's address by it's id.
*/
public async getAddress(): Promise<Address> {
if (this.address === undefined || this.address === null) {
return null;
}
if (!isNaN(this.address)) {
let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address });
if (!address) { throw new AddressNotFoundError; }
return address;
}
throw new AddressWrongTypeError;
}
/**
* Creates a new Address entity from this.
*/
public async toEntity(): Promise<GroupContact> {
let contact: GroupContact = new GroupContact();
contact.firstname = this.firstname;
contact.middlename = this.middlename;
contact.lastname = this.lastname;
contact.email = this.email;
contact.phone = this.phone;
contact.address = await this.getAddress();
return null;
}
}

View File

@@ -0,0 +1,72 @@
import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { config } from '../../../config';
import { AddressNotFoundError, AddressWrongTypeError } from '../../../errors/AddressErrors';
import { Address } from '../../entities/Address';
/**
* This classed is used to create a new Participant entity from a json body (post request).
*/
export abstract class CreateParticipant {
/**
* The new participant's first name.
*/
@IsString()
@IsNotEmpty()
firstname: string;
/**
* The new participant's middle name.
*/
@IsString()
@IsOptional()
middlename?: string;
/**
* The new participant's last name.
*/
@IsString()
@IsNotEmpty()
lastname: string;
/**
* The new participant's phone number.
* This will be validated against the configured country phone numer syntax (default: international).
*/
@IsString()
@IsOptional()
@IsPhoneNumber(config.phone_validation_countrycode)
phone?: string;
/**
* The new participant's e-mail address.
*/
@IsString()
@IsOptional()
@IsEmail()
email?: string;
/**
* The new participant's address.
* Must be of type number (address id).
*/
@IsInt()
@IsOptional()
address?: number;
/**
* Gets the new participant's address by it's address.
*/
public async getAddress(): Promise<Address> {
if (this.address === undefined || this.address === null) {
return null;
}
if (!isNaN(this.address)) {
let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address });
if (!address) { throw new AddressNotFoundError; }
return address;
}
throw new AddressWrongTypeError;
}
}

View File

@@ -0,0 +1,60 @@
import {
IsEnum,
IsInt,
IsNotEmpty
} from "class-validator";
import { getConnectionManager } from 'typeorm';
import { PrincipalNotFoundError } from '../../../errors/PrincipalErrors';
import { Permission } from '../../entities/Permission';
import { Principal } from '../../entities/Principal';
import { PermissionAction } from '../../enums/PermissionAction';
import { PermissionTarget } from '../../enums/PermissionTargets';
/**
* This classed is used to create a new Permission entity from a json body (post request).
*/
export class CreatePermission {
/**
* The new permissions's principal's id.
*/
@IsInt()
@IsNotEmpty()
principal: number;
/**
* The new permissions's target.
*/
@IsNotEmpty()
@IsEnum(PermissionTarget)
target: PermissionTarget;
/**
* The new permissions's action.
*/
@IsNotEmpty()
@IsEnum(PermissionAction)
action: PermissionAction;
/**
* Creates a new Permission entity from this.
*/
public async toEntity(): Promise<Permission> {
let newPermission: Permission = new Permission();
newPermission.principal = await this.getPrincipal();
newPermission.target = this.target;
newPermission.action = this.action;
return newPermission;
}
/**
* Gets the new permission's principal by it's id.
*/
public async getPrincipal(): Promise<Principal> {
let principal = await getConnectionManager().get().getRepository(Principal).findOne({ id: this.principal })
if (!principal) { throw new PrincipalNotFoundError(); }
return principal;
}
}

View File

@@ -0,0 +1,50 @@
import { IsEmail, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { ResetAlreadyRequestedError, UserDisabledError, UserNotFoundError } from '../../../errors/AuthError';
import { UsernameOrEmailNeededError } from '../../../errors/UserErrors';
import { JwtCreator } from '../../../jwtcreator';
import { User } from '../../entities/User';
/**
* This calss is used to create password reset tokens for users.
* These password reset token can be used to set a new password for the user for the next 15mins.
*/
export class CreateResetToken {
/**
* The username of the user that wants to reset their password.
*/
@IsOptional()
@IsString()
username?: string;
/**
* The email address of the user that wants to reset their password.
*/
@IsOptional()
@IsEmail()
@IsString()
email?: string;
/**
* Create a password reset token based on this.
*/
public async toResetToken(): Promise<any> {
if (this.email === undefined && this.username === undefined) {
throw new UsernameOrEmailNeededError();
}
let found_user = await getConnectionManager().get().getRepository(User).findOne({ where: [{ username: this.username }, { email: this.email }] });
if (!found_user) { throw new UserNotFoundError(); }
if (found_user.enabled == false) { throw new UserDisabledError(); }
if (found_user.resetRequestedTimestamp > (Math.floor(Date.now() / 1000) - 15 * 60)) { throw new ResetAlreadyRequestedError(); }
found_user.refreshTokenCount = found_user.refreshTokenCount + 1;
found_user.resetRequestedTimestamp = Math.floor(Date.now() / 1000);
await getConnectionManager().get().getRepository(User).save(found_user);
//Create the reset token
let reset_token = JwtCreator.createReset(found_user);
return reset_token;
}
}

View File

@@ -0,0 +1,53 @@
import { IsInt } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors';
import { RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { Runner } from '../../entities/Runner';
import { RunnerGroup } from '../../entities/RunnerGroup';
import { CreateParticipant } from './CreateParticipant';
/**
* This classed is used to create a new Runner entity from a json body (post request).
*/
export class CreateRunner extends CreateParticipant {
/**
* The new runner's group's id.
*/
@IsInt()
group: number;
/**
* Creates a new Runner entity from this.
*/
public async toEntity(): Promise<Runner> {
let newRunner: Runner = new Runner();
newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname;
newRunner.phone = this.phone;
newRunner.email = this.email;
newRunner.group = await this.getGroup();
newRunner.address = await this.getAddress();
return newRunner;
}
/**
* Gets the new runner's group by it's id.
*/
public async getGroup(): Promise<RunnerGroup> {
if (this.group === undefined || this.group === null) {
throw new RunnerTeamNeedsParentError();
}
if (!isNaN(this.group)) {
let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: this.group });
if (!group) { throw new RunnerGroupNotFoundError; }
return group;
}
throw new RunnerOrganisationWrongTypeError;
}
}

View File

@@ -0,0 +1,45 @@
import { IsBoolean, IsInt, IsOptional } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
import { Runner } from '../../entities/Runner';
import { RunnerCard } from '../../entities/RunnerCard';
/**
* This classed is used to create a new RunnerCard entity from a json body (post request).
*/
export class CreateRunnerCard {
/**
* The card's associated runner.
*/
@IsInt()
@IsOptional()
runner?: number;
/**
* Is the new card enabled (for fraud reasons)?
* Default: true
*/
@IsBoolean()
enabled: boolean = true;
/**
* Creates a new RunnerCard entity from this.
*/
public async toEntity(): Promise<RunnerCard> {
let newCard: RunnerCard = new RunnerCard();
newCard.enabled = this.enabled;
newCard.runner = await this.getRunner();
return newCard;
}
public async getRunner(): Promise<Runner> {
if (!this.runner) { return null; }
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
if (!runner) {
throw new RunnerNotFoundError();
}
return runner;
}
}

View File

@@ -0,0 +1,40 @@
import { IsInt, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { GroupContactNotFoundError, GroupContactWrongTypeError } from '../../../errors/GroupContactErrors';
import { GroupContact } from '../../entities/GroupContact';
/**
* This classed is used to create a new RunnerGroup entity from a json body (post request).
*/
export abstract class CreateRunnerGroup {
/**
* The new group's name.
*/
@IsNotEmpty()
@IsString()
name: string;
/**
* The new group's contact.
* Optional
*/
@IsInt()
@IsOptional()
contact?: number;
/**
* Gets the new group's contact by it's id.
*/
public async getContact(): Promise<GroupContact> {
if (this.contact === undefined || this.contact === null) {
return null;
}
if (!isNaN(this.contact)) {
let contact = await getConnectionManager().get().getRepository(GroupContact).findOne({ id: this.contact });
if (!contact) { throw new GroupContactNotFoundError; }
return contact;
}
throw new GroupContactWrongTypeError;
}
}

View File

@@ -0,0 +1,48 @@
import { IsInt, IsOptional } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { AddressNotFoundError, AddressWrongTypeError } from '../../../errors/AddressErrors';
import { Address } from '../../entities/Address';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation';
import { CreateRunnerGroup } from './CreateRunnerGroup';
/**
* This classed is used to create a new RunnerOrganisation entity from a json body (post request).
*/
export class CreateRunnerOrganisation extends CreateRunnerGroup {
/**
* The new organisation's address.
* Must be of type number (address id).
*/
@IsInt()
@IsOptional()
address?: number;
/**
* Gets the org's address by it's id.
*/
public async getAddress(): Promise<Address> {
if (this.address === undefined || this.address === null) {
return null;
}
if (!isNaN(this.address)) {
let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address });
if (!address) { throw new AddressNotFoundError; }
return address;
}
throw new AddressWrongTypeError;
}
/**
* Creates a new RunnerOrganisation entity from this.
*/
public async toEntity(): Promise<RunnerOrganisation> {
let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation();
newRunnerOrganisation.name = this.name;
newRunnerOrganisation.contact = await this.getContact();
// newRunnerOrganisation.address = await this.getAddress();
return newRunnerOrganisation;
}
}

View File

@@ -0,0 +1,50 @@
import { IsInt, IsNotEmpty } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { RunnerOrganisationNotFoundError, RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation';
import { RunnerTeam } from '../../entities/RunnerTeam';
import { CreateRunnerGroup } from './CreateRunnerGroup';
/**
* This classed is used to create a new RunnerTeam entity from a json body (post request).
*/
export class CreateRunnerTeam extends CreateRunnerGroup {
/**
* The new team's parent group (organisation).
*/
@IsInt()
@IsNotEmpty()
parentGroup: number;
/**
* Gets the new team's parent org based on it's id.
*/
public async getParent(): Promise<RunnerOrganisation> {
if (this.parentGroup === undefined || this.parentGroup === null) {
throw new RunnerTeamNeedsParentError();
}
if (!isNaN(this.parentGroup)) {
let parentGroup = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: this.parentGroup });
if (!parentGroup) { throw new RunnerOrganisationNotFoundError();; }
return parentGroup;
}
throw new RunnerOrganisationWrongTypeError;
}
/**
* Creates a new RunnerTeam entity from this.
*/
public async toEntity(): Promise<RunnerTeam> {
let newRunnerTeam: RunnerTeam = new RunnerTeam();
newRunnerTeam.name = this.name;
newRunnerTeam.parentGroup = await this.getParent();
newRunnerTeam.contact = await this.getContact()
return newRunnerTeam;
}
}

View File

@@ -0,0 +1,59 @@
import { IsBoolean, IsInt, IsOptional, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
import { Runner } from '../../entities/Runner';
import { Scan } from '../../entities/Scan';
/**
* This class is used to create a new Scan entity from a json body (post request).
*/
export abstract class CreateScan {
/**
* The scan's associated runner.
* This is important to link ran distances to runners.
*/
@IsInt()
@IsPositive()
runner: number;
/**
* Is the scan valid (for fraud reasons).
* The determination of validity will work differently for every child class.
* Default: true
*/
@IsBoolean()
@IsOptional()
valid?: boolean = true;
/**
* The scan's distance in meters.
* Can be set manually or derived from another object.
*/
@IsInt()
@IsPositive()
public distance: number;
/**
* Creates a new Scan entity from this.
*/
public async toEntity(): Promise<Scan> {
let newScan = new Scan();
newScan.distance = this.distance;
newScan.valid = this.valid;
newScan.runner = await this.getRunner();
return newScan;
}
/**
* Gets a runner based on the runner id provided via this.runner.
*/
public async getRunner(): Promise<Runner> {
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
if (!runner) {
throw new RunnerNotFoundError();
}
return runner;
}
}

View File

@@ -0,0 +1,64 @@
import * as argon2 from "argon2";
import { IsBoolean, IsInt, IsOptional, IsPositive, IsString } from 'class-validator';
import crypto from 'crypto';
import { getConnection } from 'typeorm';
import * as uuid from 'uuid';
import { TrackNotFoundError } from '../../../errors/TrackErrors';
import { ScanStation } from '../../entities/ScanStation';
import { Track } from '../../entities/Track';
/**
* This class is used to create a new StatsClient entity from a json body (post request).
*/
export class CreateScanStation {
/**
* The new station's description.
*/
@IsString()
@IsOptional()
description?: string;
/**
* The station's associated track.
*/
@IsInt()
@IsPositive()
track: number;
/**
* Is this station enabled?
*/
@IsBoolean()
@IsOptional()
enabled?: boolean = true;
/**
* Converts this to a ScanStation entity.
*/
public async toEntity(): Promise<ScanStation> {
let newStation: ScanStation = new ScanStation();
newStation.description = this.description;
newStation.enabled = this.enabled;
newStation.track = await this.getTrack();
let newUUID = uuid.v4().toUpperCase();
newStation.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
newStation.key = await argon2.hash(newStation.prefix + "." + newUUID);
newStation.cleartextkey = newStation.prefix + "." + newUUID;
return newStation;
}
/**
* Get's a track by it's id provided via this.track.
* Used to link the new station to a track.
*/
public async getTrack(): Promise<Track> {
const track = await getConnection().getRepository(Track).findOne({ id: this.track });
if (!track) {
throw new TrackNotFoundError();
}
return track;
}
}

View File

@@ -0,0 +1,33 @@
import * as argon2 from "argon2";
import { IsOptional, IsString } from 'class-validator';
import crypto from 'crypto';
import * as uuid from 'uuid';
import { StatsClient } from '../../entities/StatsClient';
/**
* This classed is used to create a new StatsClient entity from a json body (post request).
*/
export class CreateStatsClient {
/**
* The new client's description.
*/
@IsString()
@IsOptional()
description?: string;
/**
* Converts this to a StatsClient entity.
*/
public async toEntity(): Promise<StatsClient> {
let newClient: StatsClient = new StatsClient();
newClient.description = this.description;
let newUUID = uuid.v4().toUpperCase();
newClient.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
newClient.key = await argon2.hash(newClient.prefix + "." + newUUID);
newClient.cleartextkey = newClient.prefix + "." + newUUID;
return newClient;
}
}

View File

@@ -0,0 +1,46 @@
import { IsInt, IsNotEmpty, IsOptional, IsPositive, IsString } from 'class-validator';
import { TrackLapTimeCantBeNegativeError } from '../../../errors/TrackErrors';
import { Track } from '../../entities/Track';
/**
* This classed is used to create a new Track entity from a json body (post request).
*/
export class CreateTrack {
/**
* The new track's name.
*/
@IsString()
@IsNotEmpty()
name: string;
/**
* The new track's distance in meters (must be greater than 0).
*/
@IsInt()
@IsPositive()
distance: number;
/**
* The minimum time a runner should take to run a lap on this track (in seconds).
* Will be used for fraud detection.
*/
@IsInt()
@IsOptional()
minimumLapTime: number;
/**
* Creates a new Track entity from this.
*/
public toEntity(): Track {
let newTrack: Track = new Track();
newTrack.name = this.name;
newTrack.distance = this.distance;
newTrack.minimumLapTime = this.minimumLapTime;
if (this.minimumLapTime < 0) {
throw new TrackLapTimeCantBeNegativeError();
}
return newTrack;
}
}

View File

@@ -0,0 +1,79 @@
import { IsInt, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerCardNotFoundError } from '../../../errors/RunnerCardErrors';
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
import { ScanStationNotFoundError } from '../../../errors/ScanStationErrors';
import { RunnerCard } from '../../entities/RunnerCard';
import { ScanStation } from '../../entities/ScanStation';
import { TrackScan } from '../../entities/TrackScan';
/**
* This classed is used to create a new Scan entity from a json body (post request).
*/
export class CreateTrackScan {
/**
* The runnerCard associated with the scan.
* This get's saved for documentation and management purposes.
*/
@IsInt()
@IsPositive()
card: number;
/**
* The scanning station that created the scan.
* Mainly used for logging and traceing back scans (or errors)
*/
@IsInt()
@IsPositive()
station: number;
/**
* Creates a new Track entity from this.
*/
public async toEntity(): Promise<TrackScan> {
let newScan: TrackScan = new TrackScan();
newScan.station = await this.getStation();
newScan.card = await this.getCard();
newScan.track = newScan.station.track;
newScan.runner = newScan.card.runner;
if (!newScan.runner) {
throw new RunnerNotFoundError();
}
newScan.timestamp = Math.round(new Date().getTime() / 1000);
newScan.valid = await this.validateScan(newScan);
return newScan;
}
public async getCard(): Promise<RunnerCard> {
const track = await getConnection().getRepository(RunnerCard).findOne({ id: this.card }, { relations: ["runner"] });
if (!track) {
throw new RunnerCardNotFoundError();
}
return track;
}
public async getStation(): Promise<ScanStation> {
const station = await getConnection().getRepository(ScanStation).findOne({ id: this.station }, { relations: ["track"] });
if (!station) {
throw new ScanStationNotFoundError();
}
return station;
}
public async validateScan(scan: TrackScan): Promise<boolean> {
const scans = await getConnection().getRepository(TrackScan).find({ where: { runner: scan.runner, valid: true }, relations: ["track"] });
if (scans.length == 0) { return true; }
const newestScan = scans[scans.length - 1];
if ((scan.timestamp - newestScan.timestamp) > scan.track.minimumLapTime) {
return true;
}
return false;
}
}

View File

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

View File

@@ -0,0 +1,33 @@
import { IsOptional, IsString } from 'class-validator';
import { UserGroup } from '../../entities/UserGroup';
/**
* This classed is used to create a new UserGroup entity from a json body (post request).
*/
export class CreateUserGroup {
/**
* The new group's name.
*/
@IsString()
name: string;
/**
* The new group's description.
* Optinal.
*/
@IsOptional()
@IsString()
description?: string;
/**
* Creates a new UserGroup entity from this.
*/
public async toEntity(): Promise<UserGroup> {
let newUserGroup: UserGroup = new UserGroup();
newUserGroup.name = this.name;
newUserGroup.description = this.description;
return newUserGroup;
}
}

View File

@@ -0,0 +1,51 @@
import { IsInt, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
import { DistanceDonation } from '../../entities/DistanceDonation';
import { Runner } from '../../entities/Runner';
import { UpdateDonation } from './UpdateDonation';
/**
* This class is used to update a DistanceDonation entity (via put request).
*/
export class UpdateDistanceDonation extends UpdateDonation {
/**
* The donation's associated runner.
* This is important to link the runner's distance ran to the donation.
*/
@IsInt()
@IsPositive()
runner: number;
/**
* The donation's amount per distance (full kilometer aka 1000 meters).
* The unit is your currency's smallest unit (default: euro cent).
*/
@IsInt()
@IsPositive()
amountPerDistance: number;
/**
* Update a DistanceDonation entity based on this.
* @param donation The donation that shall be updated.
*/
public async update(donation: DistanceDonation): Promise<DistanceDonation> {
donation.amountPerDistance = this.amountPerDistance;
donation.donor = await this.getDonor();
donation.runner = await this.getRunner();
return donation;
}
/**
* Gets a runner based on the runner id provided via this.runner.
*/
public async getRunner(): Promise<Runner> {
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
if (!runner) {
throw new RunnerNotFoundError();
}
return runner;
}
}

View File

@@ -0,0 +1,41 @@
import { IsInt, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { DonorNotFoundError } from '../../../errors/DonorErrors';
import { Donation } from '../../entities/Donation';
import { Donor } from '../../entities/Donor';
/**
* This class is used to update a Donation entity (via put request).
*/
export abstract class UpdateDonation {
/**
* The updated donation's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated donation's associated donor.
* This is important to link donations to donors.
*/
@IsInt()
@IsPositive()
donor: number;
/**
* Creates a new Donation entity from this.
*/
public abstract update(donation: Donation): Promise<Donation>;
/**
* Gets a donor based on the donor id provided via this.donor.
*/
public async getDonor(): Promise<Donor> {
const donor = await getConnection().getRepository(Donor).findOne({ id: this.donor });
if (!donor) {
throw new DonorNotFoundError();
}
return donor;
}
}

View File

@@ -0,0 +1,44 @@
import { IsBoolean, IsInt, IsOptional } from 'class-validator';
import { DonorReceiptAddressNeededError } from '../../../errors/DonorErrors';
import { Donor } from '../../entities/Donor';
import { CreateParticipant } from '../create/CreateParticipant';
/**
* This class is used to update a Donor entity (via put request).
*/
export class UpdateDonor extends CreateParticipant {
/**
* The updated donor's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* Does the updated donor need a receipt?
*/
@IsBoolean()
@IsOptional()
receiptNeeded?: boolean;
/**
* Updates a provided Donor entity based on this.
*/
public async update(donor: Donor): Promise<Donor> {
donor.firstname = this.firstname;
donor.middlename = this.middlename;
donor.lastname = this.lastname;
donor.phone = this.phone;
donor.email = this.email;
donor.receiptNeeded = this.receiptNeeded;
donor.address = await this.getAddress();
if (this.receiptNeeded == true && this.address == null) {
throw new DonorReceiptAddressNeededError()
}
return donor;
}
}

View File

@@ -0,0 +1,27 @@
import { IsInt, IsPositive } from 'class-validator';
import { FixedDonation } from '../../entities/FixedDonation';
import { UpdateDonation } from './UpdateDonation';
/**
* This class is used to update a FixedDonation entity (via put request).
*/
export class UpdateFixedDonation extends UpdateDonation {
/**
* The updated donation's amount.
* The unit is your currency's smallest unit (default: euro cent).
*/
@IsInt()
@IsPositive()
amount: number;
/**
* Update a FixedDonation entity based on this.
* @param donation The donation that shall be updated.
*/
public async update(donation: FixedDonation): Promise<FixedDonation> {
donation.amount = this.amount;
donation.donor = await this.getDonor();
return donation;
}
}

View File

@@ -0,0 +1,68 @@
import { IsInt, IsNotEmpty, IsObject } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { PermissionNeedsPrincipalError } from '../../../errors/PermissionErrors';
import { PrincipalNotFoundError, PrincipalWrongTypeError } from '../../../errors/PrincipalErrors';
import { Permission } from '../../entities/Permission';
import { Principal } from '../../entities/Principal';
import { PermissionAction } from '../../enums/PermissionAction';
import { PermissionTarget } from '../../enums/PermissionTargets';
/**
* This class is used to update a Permission entity (via put request).
*/
export class UpdatePermission {
/**
* The updated permission's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated permissions's principal.
* Just has to contain the principal's id -everything else won't be checked or changed.
*/
@IsObject()
@IsNotEmpty()
principal: Principal;
/**
* The permissions's target.
*/
@IsNotEmpty()
target: PermissionTarget;
/**
* The permissions's action.
*/
@IsNotEmpty()
action: PermissionAction;
/**
* Updates a provided Permission entity based on this.
*/
public async update(permission: Permission): Promise<Permission> {
permission.principal = await this.getPrincipal();
permission.target = this.target;
permission.action = this.action;
return permission;
}
/**
* Loads the updated permission's principal based on it's id.
*/
public async getPrincipal(): Promise<Principal> {
if (this.principal === undefined || this.principal === null) {
throw new PermissionNeedsPrincipalError();
}
if (!isNaN(this.principal.id)) {
let principal = await getConnectionManager().get().getRepository(Principal).findOne({ id: this.principal.id });
if (!principal) { throw new PrincipalNotFoundError(); }
return principal;
}
throw new PrincipalWrongTypeError();
}
}

View File

@@ -0,0 +1,59 @@
import { IsInt, IsObject } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors';
import { RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { Runner } from '../../entities/Runner';
import { RunnerGroup } from '../../entities/RunnerGroup';
import { CreateParticipant } from '../create/CreateParticipant';
/**
* This class is used to update a Runner entity (via put request).
*/
export class UpdateRunner extends CreateParticipant {
/**
* The updated runner's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated runner's new team/org.
* Just has to contain the group's id -everything else won't be checked or changed.
*/
@IsObject()
group: RunnerGroup;
/**
* Updates a provided Runner entity based on this.
*/
public async update(runner: Runner): Promise<Runner> {
runner.firstname = this.firstname;
runner.middlename = this.middlename;
runner.lastname = this.lastname;
runner.phone = this.phone;
runner.email = this.email;
runner.group = await this.getGroup();
runner.address = await this.getAddress();
return runner;
}
/**
* Loads the updated runner's group based on it's id.
*/
public async getGroup(): Promise<RunnerGroup> {
if (this.group === undefined || this.group === null) {
throw new RunnerTeamNeedsParentError();
}
if (!isNaN(this.group.id)) {
let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: this.group.id });
if (!group) { throw new RunnerGroupNotFoundError; }
return group;
}
throw new RunnerOrganisationWrongTypeError;
}
}

View File

@@ -0,0 +1,51 @@
import { IsBoolean, IsInt, IsOptional, IsPositive } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
import { Runner } from '../../entities/Runner';
import { RunnerCard } from '../../entities/RunnerCard';
/**
* This class is used to update a RunnerCard entity (via put request).
*/
export class UpdateRunnerCard {
/**
* The updated card's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
@IsPositive()
id?: number;
/**
* The updated card's associated runner.
*/
@IsInt()
@IsOptional()
runner?: number;
/**
* Is the updated card enabled (for fraud reasons)?
* Default: true
*/
@IsBoolean()
enabled: boolean = true;
/**
* Creates a new RunnerCard entity from this.
*/
public async update(card: RunnerCard): Promise<RunnerCard> {
card.enabled = this.enabled;
card.runner = await this.getRunner();
return card;
}
public async getRunner(): Promise<Runner> {
if (!this.runner) { return null; }
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
if (!runner) {
throw new RunnerNotFoundError();
}
return runner;
}
}

View File

@@ -0,0 +1,52 @@
import { IsInt, IsOptional } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { AddressNotFoundError } from '../../../errors/AddressErrors';
import { Address } from '../../entities/Address';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation';
import { CreateRunnerGroup } from '../create/CreateRunnerGroup';
/**
* This class is used to update a RunnerOrganisation entity (via put request).
*/
export class UpdateRunnerOrganisation extends CreateRunnerGroup {
/**
* The updated orgs's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated organisation's address.
* Just has to contain the address's id - everything else won't be checked or changed.
* Optional.
*/
@IsInt()
@IsOptional()
address?: Address;
/**
* Loads the organisation's address based on it's id.
*/
public async getAddress(): Promise<Address> {
if (this.address === undefined || this.address === null) {
return null;
}
let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address.id });
if (!address) { throw new AddressNotFoundError; }
return address;
}
/**
* Updates a provided RunnerOrganisation entity based on this.
*/
public async update(organisation: RunnerOrganisation): Promise<RunnerOrganisation> {
organisation.name = this.name;
organisation.contact = await this.getContact();
// organisation.address = await this.getAddress();
return organisation;
}
}

View File

@@ -0,0 +1,56 @@
import { IsInt, IsNotEmpty, IsObject } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { RunnerOrganisationNotFoundError, RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation';
import { RunnerTeam } from '../../entities/RunnerTeam';
import { CreateRunnerGroup } from '../create/CreateRunnerGroup';
/**
* This class is used to update a RunnerTeam entity (via put request).
*/
export class UpdateRunnerTeam extends CreateRunnerGroup {
/**
* The updated team's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated team's parentGroup.
* Just has to contain the organisation's id - everything else won't be checked or changed.
*/
@IsObject()
@IsNotEmpty()
parentGroup: RunnerOrganisation;
/**
* Loads the updated teams's parentGroup based on it's id.
*/
public async getParent(): Promise<RunnerOrganisation> {
if (this.parentGroup === undefined || this.parentGroup === null) {
throw new RunnerTeamNeedsParentError();
}
if (!isNaN(this.parentGroup.id)) {
let parentGroup = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: this.parentGroup.id });
if (!parentGroup) { throw new RunnerOrganisationNotFoundError();; }
return parentGroup;
}
throw new RunnerOrganisationWrongTypeError;
}
/**
* Updates a provided RunnerTeam entity based on this.
*/
public async update(team: RunnerTeam): Promise<RunnerTeam> {
team.name = this.name;
team.parentGroup = await this.getParent();
team.contact = await this.getContact()
return team;
}
}

Some files were not shown because too many files have changed in this diff Show More