Compare commits

..

70 Commits

Author SHA1 Message Date
f0e20e4130 🚀Bumped version to v1.0.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-18 20:03:51 +02:00
80de188565 Merge pull request 'feature/205-pagination' (#206) from feature/205-pagination into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #206
Reviewed-by: Philipp Dormann <philipp@noreply.git.odit.services>
2023-04-18 18:03:20 +00:00
2f305e127c Updated test for attribute
All checks were successful
continuous-integration/drone/pr Build is passing
2023-04-18 20:02:03 +02:00
513d7f6fba usergroup pagination
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:44:15 +02:00
244da61892 users pagination
ref #205
2023-04-18 18:43:13 +02:00
2a72aea10e Track pagination
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:41:57 +02:00
71ebce6f8e statsclient pagination
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:40:45 +02:00
f60025b6de scanstation pagination
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:39:37 +02:00
0fa663a341 RunnerTeam Pagination
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:38:27 +02:00
538622aa18 Added pagination for runner orgs
ref #205
2023-04-18 18:37:09 +02:00
86a21dbfa4 Get all pagination for permissions
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:35:25 +02:00
1e9e24d99d Pagination for group contacts
ref #205
2023-04-18 18:34:08 +02:00
4493c0e3d9 Added pagination for get all donors
Some checks failed
continuous-integration/drone/pr Build is failing
ref #205
2023-04-18 18:30:20 +02:00
f5d48fc638 Added pagination for donations
ref #205
2023-04-18 18:28:55 +02:00
b35a2dd2fa Added pagination for runnercards
ref #205
2023-04-18 18:27:11 +02:00
a28ffe06e5 Formatting
ref #205
2023-04-18 18:21:09 +02:00
d873674819 Added pagination for runners
ref #205
2023-04-18 18:20:56 +02:00
37b2ac974b Added pagination for get all scans
ref #205
2023-04-18 18:17:10 +02:00
81aed1de40 🚀Bumped version to v0.15.4
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 22:52:10 +02:00
0f0c3c7214 Fixed possible null
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 22:51:48 +02:00
3909ed34f7 🚀Bumped version to v0.15.3
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 22:36:09 +02:00
b2ac70e0ae Faster stats (not including donations) 2023-04-15 22:35:55 +02:00
5f17e7f783 🚀Bumped version to v0.15.2
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 21:16:56 +02:00
a5a56a263a Resolve groups again for card generation 2023-04-15 21:15:29 +02:00
2d8f7528d9 Don't resolve runner group and parten with get all card requests 2023-04-15 21:13:14 +02:00
9581185b24 🚀Bumped version to v0.15.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 21:11:56 +02:00
2905884c02 Log batch time in mass scan script 2023-04-15 21:11:32 +02:00
e9914e317b Faster trackscan creation by only loading the latest scan 2023-04-15 21:08:08 +02:00
702070da66 Dont load cards with get all runners request 2023-04-15 20:55:22 +02:00
cc89ba8afb 🚀Bumped version to v0.15.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 20:51:28 +02:00
7c4ff42a3b More scan request optimizations 2023-04-15 20:51:13 +02:00
8007117434 Added test script for creating mass scans 2023-04-15 20:50:48 +02:00
23fa78eb9d Get all scans speed improvement 2023-04-15 20:31:52 +02:00
3b3e68900b 🚀Bumped version to v0.14.6
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 18:20:54 +02:00
3ff666fd3e Missing orm file 2023-04-15 18:19:47 +02:00
4e4435010f 🚀Bumped version to v0.14.5
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-15 18:16:09 +02:00
de9af5a909 Entrypoint fix 2023-04-15 18:15:57 +02:00
ac631f0af4 Fixed copy 2023-04-15 18:13:58 +02:00
6bbdd5bb04 🚀Bumped version to v0.14.4
Some checks reported errors
continuous-integration/drone/pr Build was killed
continuous-integration/drone/push Build is passing
2023-04-15 18:09:49 +02:00
a8fc755840 Back to ean13 based codes
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/pr Build is failing
2023-04-15 18:09:24 +02:00
27e74e824c pinned pnpm to 8
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-12 14:12:05 +02:00
b5c0a288ac coherent baseimage
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2023-03-29 20:35:16 +02:00
85dc3444ac custom pnpm cache
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is passing
2023-03-29 20:29:56 +02:00
d02743984d install prod in first step
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is passing
2023-03-29 20:29:08 +02:00
734c826fac added missing ci env
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-29 20:27:01 +02:00
33b25c9743 bumped final pnpm version
Some checks reported errors
continuous-integration/drone/pr Build was killed
continuous-integration/drone/push Build is passing
2023-03-29 20:03:38 +02:00
6275aaa326 Switched ci over to pnpm + cache
Some checks reported errors
continuous-integration/drone/pr Build was killed
continuous-integration/drone/push Build is failing
2023-03-29 19:56:05 +02:00
2a94bfa622 pinned pnpm version 2023-03-29 19:53:42 +02:00
a64f6c9822 COPY by stage name 2023-03-29 19:52:59 +02:00
93d43b7684 Switched dockerfile to pnpm 8 with cache 2023-03-29 19:52:31 +02:00
16ce0a8480 🚀Bumped version to v0.14.3
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-18 22:15:02 +01:00
9a8d618ae4 Adjusted modulo for new fixed card length 2023-03-18 22:14:50 +01:00
38da2d3318 🚀Bumped version to v0.14.2
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-18 21:55:23 +01:00
068deb4960 Back to modulo 2023-03-18 21:55:10 +01:00
13f093bb61 🚀Bumped version to v0.14.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-18 21:46:38 +01:00
6289f30740 Switched from card prefix replacement via modulo to regex 2023-03-18 21:46:21 +01:00
6ff764bc34 🚀Bumped version to v0.14.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-15 14:44:34 +01:00
ea87cc793b Updated default length 2023-03-15 14:44:19 +01:00
92517e3653 Removed sqlite journal 2023-03-15 14:39:40 +01:00
ffee887ddf breaking(runnercards): shorter runnercard codes (padding to 12 was a bit tooo ambitious) 2023-03-15 14:39:24 +01:00
3bac75e7ab 🚀Bumped version to v0.13.3
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-02-15 14:55:41 +01:00
d05eddcae1 Merge pull request 'feature/201-no_citizen-deletion' (#202) from feature/201-no_citizen-deletion into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #202
2023-02-15 13:54:54 +00:00
d5c689d693 Updated tests
All checks were successful
continuous-integration/drone/pr Build is passing
ref #201
2023-02-15 14:35:58 +01:00
8fedd4ef3b Added delete check for citizen org
ref #201
2023-02-15 14:34:12 +01:00
e8b2e6f261 🚀Bumped version to v0.13.2
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-03 16:12:20 +01:00
39f3b0e01f Merge pull request 'move selfservice magic link endpoint to 15min rate limit' (#200) from feature/runner-selfservice-login-link-rate-limit into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #200
2023-02-03 15:09:34 +00:00
edaf255e8f move to 15min limit
All checks were successful
continuous-integration/drone/pr Build is passing
2023-02-03 14:12:28 +01:00
41c4ed4d0f Merge pull request 'Releases 0.12.0 and 0.13.0' (#199) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #199
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
2023-02-03 13:04:39 +00:00
f2bd88aadf 🚀Bumped version to v0.13.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-02-02 16:16:50 +01:00
67a3661448 Updated description 2023-02-02 16:16:36 +01:00
26 changed files with 402 additions and 109 deletions

View File

@@ -26,6 +26,13 @@ get:
path: odit-ci-bot path: odit-ci-bot
name: apikey name: apikey
---
kind: secret
name: npm_url
get:
path: odit-npm-cache
name: url
--- ---
kind: pipeline kind: pipeline
type: kubernetes type: kubernetes
@@ -41,8 +48,12 @@ steps:
- name: run tests - name: run tests
image: registry.odit.services/hub/library/node:19.5.0-alpine3.16 image: registry.odit.services/hub/library/node:19.5.0-alpine3.16
commands: commands:
- yarn - npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
- yarn test:ci - pnpm i
- pnpm test:ci
environment:
NPM_REGISTRY_URL:
from_secret: npm_url
trigger: trigger:
event: event:
- pull_request - pull_request
@@ -69,10 +80,8 @@ steps:
password: password:
from_secret: docker_password from_secret: docker_password
build_args: build_args:
- NPM_REGISTRY_DOMAIN: - NPM_REGISTRY_URL:
from_secret: npmjs_domain from_secret: npm_url
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/backend repo: lfk/backend
tags: tags:
- dev - dev
@@ -109,10 +118,8 @@ steps:
password: password:
from_secret: docker_password from_secret: docker_password
build_args: build_args:
- NPM_REGISTRY_DOMAIN: - NPM_REGISTRY_URL:
from_secret: npmjs_domain from_secret: npm_url
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/backend repo: lfk/backend
tags: tags:
- latest - latest
@@ -149,10 +156,8 @@ steps:
password: password:
from_secret: docker_password from_secret: docker_password
build_args: build_args:
- NPM_REGISTRY_DOMAIN: - NPM_REGISTRY_URL:
from_secret: npmjs_domain from_secret: npm_url
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/backend repo: lfk/backend
tags: tags:
- "${DRONE_TAG}" - "${DRONE_TAG}"

View File

@@ -2,10 +2,160 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v1.0.0](https://git.odit.services/lfk/backend/compare/v0.15.4...v1.0.0)
- Merge pull request 'feature/205-pagination' (#206) from feature/205-pagination into dev [`80de188`](https://git.odit.services/lfk/backend/commit/80de188565523d642407612272432ef07672b890)
- Added pagination for runner orgs [`538622a`](https://git.odit.services/lfk/backend/commit/538622aa1841e27256f304e15b4204c2f6d24d76)
- RunnerTeam Pagination [`0fa663a`](https://git.odit.services/lfk/backend/commit/0fa663a34104d438dd8fc9ab02458fdf289329f8)
- users pagination [`244da61`](https://git.odit.services/lfk/backend/commit/244da618926377f58bb12dbbd89b7bb39d84596e)
- Track pagination [`2a72aea`](https://git.odit.services/lfk/backend/commit/2a72aea10ef940fbdd4a9e6137b22933fdec7734)
- usergroup pagination [`513d7f6`](https://git.odit.services/lfk/backend/commit/513d7f6fbaebe39beab6ec95e6e42eb10c62296d)
- statsclient pagination [`71ebce6`](https://git.odit.services/lfk/backend/commit/71ebce6f8eebf110bb973a53b91dd6a49e1def99)
- scanstation pagination [`f60025b`](https://git.odit.services/lfk/backend/commit/f60025b6de79b0f5f89995bf59260194f5de9af0)
- Get all pagination for permissions [`86a21db`](https://git.odit.services/lfk/backend/commit/86a21dbfa4b50d8e80c611ea6e3eabfc2b8ae365)
- Pagination for group contacts [`1e9e24d`](https://git.odit.services/lfk/backend/commit/1e9e24d99d75ce6dc846ff662e62c886646ea974)
- Added pagination for get all donors [`4493c0e`](https://git.odit.services/lfk/backend/commit/4493c0e3d9beebbf7f601b39e1a2579771b4d152)
- Added pagination for donations [`f5d48fc`](https://git.odit.services/lfk/backend/commit/f5d48fc638080c9333efe474d86f131794c809af)
- Added pagination for runnercards [`b35a2dd`](https://git.odit.services/lfk/backend/commit/b35a2dd2fab708253373b3326f11ab574be18371)
- Added pagination for runners [`d873674`](https://git.odit.services/lfk/backend/commit/d873674819e6cb33cf89da4f8fdc30a0b41707e4)
- Added pagination for get all scans [`37b2ac9`](https://git.odit.services/lfk/backend/commit/37b2ac974b2276efd13538c127ba5ddda2537fe3)
- Updated test for attribute [`2f305e1`](https://git.odit.services/lfk/backend/commit/2f305e127c75e9e6ff8e9fc0cfc10cc3db44759d)
- Formatting [`a28ffe0`](https://git.odit.services/lfk/backend/commit/a28ffe06e5f3f69e4af6fdf0c66c9a1dfda10cfa)
#### [v0.15.4](https://git.odit.services/lfk/backend/compare/v0.15.3...v0.15.4)
> 15 April 2023
- Fixed possible null [`0f0c3c7`](https://git.odit.services/lfk/backend/commit/0f0c3c7214f357d991518aafd015ffc4d387ce59)
- 🚀Bumped version to v0.15.4 [`81aed1d`](https://git.odit.services/lfk/backend/commit/81aed1de40166f4cefabdb478d7638017127b25c)
#### [v0.15.3](https://git.odit.services/lfk/backend/compare/v0.15.2...v0.15.3)
> 15 April 2023
- Faster stats (not including donations) [`b2ac70e`](https://git.odit.services/lfk/backend/commit/b2ac70e0aec1064e54a5043a104e7892984b2338)
- 🚀Bumped version to v0.15.3 [`3909ed3`](https://git.odit.services/lfk/backend/commit/3909ed34f739e9fee90828f16757c75da90bab0f)
#### [v0.15.2](https://git.odit.services/lfk/backend/compare/v0.15.1...v0.15.2)
> 15 April 2023
- 🚀Bumped version to v0.15.2 [`5f17e7f`](https://git.odit.services/lfk/backend/commit/5f17e7f783a7e8e2efc8f7dbbf2c98bcd1d80240)
- Don't resolve runner group and parten with get all card requests [`2d8f752`](https://git.odit.services/lfk/backend/commit/2d8f7528d98144832e7609f5aa6fac8de4723c4a)
- Resolve groups again for card generation [`a5a56a2`](https://git.odit.services/lfk/backend/commit/a5a56a263a01dbd911a799ab57084166e17b80ac)
#### [v0.15.1](https://git.odit.services/lfk/backend/compare/v0.15.0...v0.15.1)
> 15 April 2023
- 🚀Bumped version to v0.15.1 [`9581185`](https://git.odit.services/lfk/backend/commit/9581185b24039338e7f238ecdcc3881bb5203759)
- Faster trackscan creation by only loading the latest scan [`e9914e3`](https://git.odit.services/lfk/backend/commit/e9914e317b7fd78863cfd8549bad65da9292b7ca)
- Log batch time in mass scan script [`2905884`](https://git.odit.services/lfk/backend/commit/2905884c024d7f275b3ad2c2858a2f0911adb95b)
- Dont load cards with get all runners request [`702070d`](https://git.odit.services/lfk/backend/commit/702070da669cc605b93e6f5b62d712c28f079dd0)
#### [v0.15.0](https://git.odit.services/lfk/backend/compare/v0.14.6...v0.15.0)
> 15 April 2023
- Added test script for creating mass scans [`8007117`](https://git.odit.services/lfk/backend/commit/80071174342d87199fcbd981cd8c92300b0a51e4)
- 🚀Bumped version to v0.15.0 [`cc89ba8`](https://git.odit.services/lfk/backend/commit/cc89ba8afb3120569613a889baf962555612e95a)
- Get all scans speed improvement [`23fa78e`](https://git.odit.services/lfk/backend/commit/23fa78eb9dcc01ecc036347f6703aacc0d163d7d)
- More scan request optimizations [`7c4ff42`](https://git.odit.services/lfk/backend/commit/7c4ff42a3b3e7b186e16c85a97d9ecc854a32cb0)
#### [v0.14.6](https://git.odit.services/lfk/backend/compare/v0.14.5...v0.14.6)
> 15 April 2023
- 🚀Bumped version to v0.14.6 [`3b3e689`](https://git.odit.services/lfk/backend/commit/3b3e68900beca16cfff88dbef22540f77750d29b)
- Missing orm file [`3ff666f`](https://git.odit.services/lfk/backend/commit/3ff666fd3e84ac8cf41b30e9e17082b10548d55b)
#### [v0.14.5](https://git.odit.services/lfk/backend/compare/v0.14.4...v0.14.5)
> 15 April 2023
- 🚀Bumped version to v0.14.5 [`4e44350`](https://git.odit.services/lfk/backend/commit/4e4435010fd7095e3b9742e207cba1b68cd6da3b)
- Entrypoint fix [`de9af5a`](https://git.odit.services/lfk/backend/commit/de9af5a90907dcfc9bfb1d5a56420eed8bb59922)
- Fixed copy [`ac631f0`](https://git.odit.services/lfk/backend/commit/ac631f0af467446552478873b7b4802a9310f865)
#### [v0.14.4](https://git.odit.services/lfk/backend/compare/v0.14.3...v0.14.4)
> 15 April 2023
- Switched ci over to pnpm + cache [`6275aaa`](https://git.odit.services/lfk/backend/commit/6275aaa326f1c02c8dd42aa31608978408c44ab7)
- 🚀Bumped version to v0.14.4 [`6bbdd5b`](https://git.odit.services/lfk/backend/commit/6bbdd5bb04a1c38e4b3a150db24b76e9c96490dd)
- Back to ean13 based codes [`a8fc755`](https://git.odit.services/lfk/backend/commit/a8fc7558408b97da4b2c469ae5e73ab502b4fda0)
- install prod in first step [`d027439`](https://git.odit.services/lfk/backend/commit/d02743984dfea8057be3081bd3a32a8f67e610aa)
- Switched dockerfile to pnpm 8 with cache [`93d43b7`](https://git.odit.services/lfk/backend/commit/93d43b76843d7cb411f37fd2066c6a5364c05415)
- COPY by stage name [`a64f6c9`](https://git.odit.services/lfk/backend/commit/a64f6c9822af2b927e91b0b55f1f50176de30169)
- pinned pnpm version [`2a94bfa`](https://git.odit.services/lfk/backend/commit/2a94bfa6227d14f635b5fc2789b59c36d490937e)
- custom pnpm cache [`85dc344`](https://git.odit.services/lfk/backend/commit/85dc3444acc677ddd242f9f2543ce477fe427a7c)
- added missing ci env [`734c826`](https://git.odit.services/lfk/backend/commit/734c826face58dd5c3bb2607bda6e7f6d051012e)
- pinned pnpm to 8 [`27e74e8`](https://git.odit.services/lfk/backend/commit/27e74e824cd1e23d4d53c1a983a1668dd87f5d59)
- coherent baseimage [`b5c0a28`](https://git.odit.services/lfk/backend/commit/b5c0a288ac3c020f5d753c558aee160fea0bae14)
- bumped final pnpm version [`33b25c9`](https://git.odit.services/lfk/backend/commit/33b25c9743abb7cefb3538f08cc2f78a646905c8)
#### [v0.14.3](https://git.odit.services/lfk/backend/compare/v0.14.2...v0.14.3)
> 18 March 2023
- 🚀Bumped version to v0.14.3 [`16ce0a8`](https://git.odit.services/lfk/backend/commit/16ce0a848050b74c4b6dd93f17e5a6e9024cdb7d)
- Adjusted modulo for new fixed card length [`9a8d618`](https://git.odit.services/lfk/backend/commit/9a8d618ae4584640e8be1ce9fe4bddd2ef7a92ae)
#### [v0.14.2](https://git.odit.services/lfk/backend/compare/v0.14.1...v0.14.2)
> 18 March 2023
- 🚀Bumped version to v0.14.2 [`38da2d3`](https://git.odit.services/lfk/backend/commit/38da2d33187f4b24eef878642e153663ecd95de1)
- Back to modulo [`068deb4`](https://git.odit.services/lfk/backend/commit/068deb4960bd16decf99887ffbda7a7d3dd9ff0b)
#### [v0.14.1](https://git.odit.services/lfk/backend/compare/v0.14.0...v0.14.1)
> 18 March 2023
- 🚀Bumped version to v0.14.1 [`13f093b`](https://git.odit.services/lfk/backend/commit/13f093bb6138a498f93a05ef6dd812ae92f2676a)
- Switched from card prefix replacement via modulo to regex [`6289f30`](https://git.odit.services/lfk/backend/commit/6289f307400aacaa9cfe03f3024c1e0d5554d4f2)
#### [v0.14.0](https://git.odit.services/lfk/backend/compare/v0.13.3...v0.14.0)
> 15 March 2023
- 🚀Bumped version to v0.14.0 [`6ff764b`](https://git.odit.services/lfk/backend/commit/6ff764bc340ca25b3bdd62c6892259e228723973)
- Updated default length [`ea87cc7`](https://git.odit.services/lfk/backend/commit/ea87cc793b163bf0d4405a25bbe83fbc8e31c206)
- breaking(runnercards): shorter runnercard codes (padding to 12 was a bit tooo ambitious) [`ffee887`](https://git.odit.services/lfk/backend/commit/ffee887ddf6a71102ee39533d7cd504d1fd6698f)
- Removed sqlite journal [`92517e3`](https://git.odit.services/lfk/backend/commit/92517e365393f4baac3814f5668874b5752dc7c8)
#### [v0.13.3](https://git.odit.services/lfk/backend/compare/v0.13.2...v0.13.3)
> 15 February 2023
- 🚀Bumped version to v0.13.3 [`3bac75e`](https://git.odit.services/lfk/backend/commit/3bac75e7ab9f16ecab1fbfa9915a7edb923883f6)
- Merge pull request 'feature/201-no_citizen-deletion' (#202) from feature/201-no_citizen-deletion into dev [`d05eddc`](https://git.odit.services/lfk/backend/commit/d05eddcae198427ce9a334096563b3aadcff2b56)
- Updated tests [`d5c689d`](https://git.odit.services/lfk/backend/commit/d5c689d6937288df7dca14ce26fbbd4f46a8752a)
- Added delete check for citizen org [`8fedd4e`](https://git.odit.services/lfk/backend/commit/8fedd4ef3bdd48dc42abc1d53006eefc145175e3)
#### [v0.13.2](https://git.odit.services/lfk/backend/compare/v0.13.1...v0.13.2)
> 3 February 2023
- 🚀Bumped version to v0.13.2 [`e8b2e6f`](https://git.odit.services/lfk/backend/commit/e8b2e6f26140a18c06b017e4461742d7e7942f08)
- Merge pull request 'move selfservice magic link endpoint to 15min rate limit' (#200) from feature/runner-selfservice-login-link-rate-limit into dev [`39f3b0e`](https://git.odit.services/lfk/backend/commit/39f3b0e01f03bfbcfcb0ea08d697268ce068e63d)
- move to 15min limit [`edaf255`](https://git.odit.services/lfk/backend/commit/edaf255e8f609185dcd6c2c0cd2e8b007b785e0c)
- Merge pull request 'Releases 0.12.0 and 0.13.0' (#199) from dev into main [`41c4ed4`](https://git.odit.services/lfk/backend/commit/41c4ed4d0faaed382801bbe480f31dafa6f3912d)
#### [v0.13.1](https://git.odit.services/lfk/backend/compare/v0.13.0...v0.13.1)
> 2 February 2023
- 🚀Bumped version to v0.13.1 [`f2bd88a`](https://git.odit.services/lfk/backend/commit/f2bd88aadfcb6ffa0485ea6afac8c7664a37f5f4)
- Updated description [`67a3661`](https://git.odit.services/lfk/backend/commit/67a36614485b2ea83c2de41e0684708b95a05b32)
#### [v0.13.0](https://git.odit.services/lfk/backend/compare/v0.12.0...v0.13.0) #### [v0.13.0](https://git.odit.services/lfk/backend/compare/v0.12.0...v0.13.0)
> 2 February 2023
- Added faker for testing [`e184673`](https://git.odit.services/lfk/backend/commit/e1846739638905aab6ba7e059fd2cbf8ff467bf3) - Added faker for testing [`e184673`](https://git.odit.services/lfk/backend/commit/e1846739638905aab6ba7e059fd2cbf8ff467bf3)
- 📖New license file version [CI SKIP] [skip ci] [`2b641fa`](https://git.odit.services/lfk/backend/commit/2b641faa29c47d95f69983770dc4ab37e674604f) - 📖New license file version [CI SKIP] [skip ci] [`2b641fa`](https://git.odit.services/lfk/backend/commit/2b641faa29c47d95f69983770dc4ab37e674604f)
- 🚀Bumped version to v0.13.0 [`0c763a2`](https://git.odit.services/lfk/backend/commit/0c763a2dfd39607b480d9aff7d3c883791f41700)
- Updated selfservice tests to prevent email duplication [`9bc80aa`](https://git.odit.services/lfk/backend/commit/9bc80aac8aab9b4dedc26c9bc3ce705d7fe9c0bf) - Updated selfservice tests to prevent email duplication [`9bc80aa`](https://git.odit.services/lfk/backend/commit/9bc80aac8aab9b4dedc26c9bc3ce705d7fe9c0bf)
- Moved license and changelog export to releaseit hooks [`77c6303`](https://git.odit.services/lfk/backend/commit/77c6303014578edbbadeeaa790f7974bde2a9764) - Moved license and changelog export to releaseit hooks [`77c6303`](https://git.odit.services/lfk/backend/commit/77c6303014578edbbadeeaa790f7974bde2a9764)
- Updated readme [`4cdba8b`](https://git.odit.services/lfk/backend/commit/4cdba8bc77ce543f6fb636711b8728bce794eac7) - Updated readme [`4cdba8b`](https://git.odit.services/lfk/backend/commit/4cdba8bc77ce543f6fb636711b8728bce794eac7)

View File

@@ -1,15 +1,23 @@
# Typescript Build # Typescript Build
FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16 FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16 as build
ARG NPM_REGISTRY_URL=https://registry.npmjs.org
WORKDIR /app WORKDIR /app
COPY package.json ./ COPY package.json ./
RUN npx pnpm@7.26.3 i RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i
COPY tsconfig.json ormconfig.js ./ COPY tsconfig.json ormconfig.js ./
COPY src ./src COPY src ./src
RUN npm run build RUN pnpm run build \
&& rm -rf /app/node_modules \
&& pnpm i --production --prefer-offline
# final image # final image
FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16 FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16 as final
COPY package.json ormconfig.js ./ WORKDIR /app
RUN npx pnpm@7.26.3 i --prod COPY --from=build /app/package.json /app/package.json
COPY --from=0 /app/dist dist COPY --from=build /app/ormconfig.js /app/ormconfig.js
ENTRYPOINT ["node", "dist/app.js"] COPY --from=build /app/dist /app/dist
COPY --from=build /app/node_modules /app/node_modules
ENTRYPOINT ["node", "/app/dist/app.js"]

View File

@@ -1,8 +1,11 @@
{ {
"name": "@odit/lfk-backend", "name": "@odit/lfk-backend",
"version": "0.13.0", "version": "1.0.0",
"main": "src/app.ts", "main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend", "repository": "https://git.odit.services/lfk/backend",
"engines": {
"pnpm": "8"
},
"author": { "author": {
"name": "ODIT.Services", "name": "ODIT.Services",
"email": "info@odit.services", "email": "info@odit.services",

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { DonationIdsNotMatchingError, DonationNotFoundError } from '../errors/DonationErrors'; import { DonationIdsNotMatchingError, DonationNotFoundError } from '../errors/DonationErrors';
import { DonorNotFoundError } from '../errors/DonorErrors'; import { DonorNotFoundError } from '../errors/DonorErrors';
import { RunnerNotFoundError } from '../errors/RunnerErrors'; import { RunnerNotFoundError } from '../errors/RunnerErrors';
@@ -36,9 +36,16 @@ export class DonationController {
@ResponseSchema(ResponseDonation, { isArray: true }) @ResponseSchema(ResponseDonation, { isArray: true })
@ResponseSchema(ResponseDistanceDonation, { 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).' }) @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() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseDonations: ResponseDonation[] = new Array<ResponseDonation>(); let responseDonations: ResponseDonation[] = new Array<ResponseDonation>();
const donations = await this.donationRepository.find({ relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] }); let donations: Array<Donation>;
if (page) {
donations = await this.donationRepository.find({ relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'], skip: page * page_size, take: page_size });
} else {
donations = await this.donationRepository.find({ relations: ['runner', 'donor', 'runner.scans', 'runner.scans.track'] });
}
donations.forEach(donation => { donations.forEach(donation => {
responseDonations.push(donation.toResponse()); responseDonations.push(donation.toResponse());
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { DonorHasDonationsError, DonorIdsNotMatchingError, DonorNotFoundError } from '../errors/DonorErrors'; import { DonorHasDonationsError, DonorIdsNotMatchingError, DonorNotFoundError } from '../errors/DonorErrors';
import { CreateDonor } from '../models/actions/create/CreateDonor'; import { CreateDonor } from '../models/actions/create/CreateDonor';
import { UpdateDonor } from '../models/actions/update/UpdateDonor'; import { UpdateDonor } from '../models/actions/update/UpdateDonor';
@@ -25,9 +25,16 @@ export class DonorController {
@Authorized("DONOR:GET") @Authorized("DONOR:GET")
@ResponseSchema(ResponseDonor, { isArray: true }) @ResponseSchema(ResponseDonor, { isArray: true })
@OpenAPI({ description: 'Lists all donor. <br> This includes the donor\'s current donation amount.' }) @OpenAPI({ description: 'Lists all donor. <br> This includes the donor\'s current donation amount.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseDonors: ResponseDonor[] = new Array<ResponseDonor>(); let responseDonors: ResponseDonor[] = new Array<ResponseDonor>();
const donors = await this.donorRepository.find({ relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] }); let donors: Array<Donor>;
if (page) {
donors = await this.donorRepository.find({ relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'], skip: page * page_size, take: page_size });
} else {
donors = await this.donorRepository.find({ relations: ['donations', 'donations.runner', 'donations.runner.scans', 'donations.runner.scans.track'] });
}
donors.forEach(donor => { donors.forEach(donor => {
responseDonors.push(new ResponseDonor(donor)); responseDonors.push(new ResponseDonor(donor));
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnection, getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnection, getConnectionManager } from 'typeorm';
import { GroupContactIdsNotMatchingError, GroupContactNotFoundError } from '../errors/GroupContactErrors'; import { GroupContactIdsNotMatchingError, GroupContactNotFoundError } from '../errors/GroupContactErrors';
import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors';
import { CreateGroupContact } from '../models/actions/create/CreateGroupContact'; import { CreateGroupContact } from '../models/actions/create/CreateGroupContact';
@@ -26,9 +26,16 @@ export class GroupContactController {
@Authorized("CONTACT:GET") @Authorized("CONTACT:GET")
@ResponseSchema(ResponseGroupContact, { isArray: true }) @ResponseSchema(ResponseGroupContact, { isArray: true })
@OpenAPI({ description: 'Lists all contacts. <br> This includes the contact\'s associated groups.' }) @OpenAPI({ description: 'Lists all contacts. <br> This includes the contact\'s associated groups.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseContacts: ResponseGroupContact[] = new Array<ResponseGroupContact>(); let responseContacts: ResponseGroupContact[] = new Array<ResponseGroupContact>();
const contacts = await this.contactRepository.find({ relations: ['groups', 'groups.parentGroup'] }); let contacts: Array<GroupContact>;
if (page) {
contacts = await this.contactRepository.find({ relations: ['groups', 'groups.parentGroup'], skip: page * page_size, take: page_size });
} else {
contacts = await this.contactRepository.find({ relations: ['groups', 'groups.parentGroup'] });
}
contacts.forEach(contact => { contacts.forEach(contact => {
responseContacts.push(contact.toResponse()); responseContacts.push(contact.toResponse());
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { PermissionIdsNotMatchingError, PermissionNeedsPrincipalError, PermissionNotFoundError } from '../errors/PermissionErrors'; import { PermissionIdsNotMatchingError, PermissionNeedsPrincipalError, PermissionNotFoundError } from '../errors/PermissionErrors';
import { PrincipalNotFoundError } from '../errors/PrincipalErrors'; import { PrincipalNotFoundError } from '../errors/PrincipalErrors';
import { CreatePermission } from '../models/actions/create/CreatePermission'; import { CreatePermission } from '../models/actions/create/CreatePermission';
@@ -27,9 +27,16 @@ export class PermissionController {
@Authorized("PERMISSION:GET") @Authorized("PERMISSION:GET")
@ResponseSchema(ResponsePermission, { isArray: true }) @ResponseSchema(ResponsePermission, { isArray: true })
@OpenAPI({ description: 'Lists all permissions for all users and groups.' }) @OpenAPI({ description: 'Lists all permissions for all users and groups.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responsePermissions: ResponsePermission[] = new Array<ResponsePermission>(); let responsePermissions: ResponsePermission[] = new Array<ResponsePermission>();
const permissions = await this.permissionRepository.find({ relations: ['principal'] }); let permissions: Array<Permission>;
if (page) {
permissions = await this.permissionRepository.find({ relations: ['principal'], skip: page * page_size, take: page_size });
} else {
permissions = await this.permissionRepository.find({ relations: ['principal'] });
}
permissions.forEach(permission => { permissions.forEach(permission => {
responsePermissions.push(new ResponsePermission(permission)); responsePermissions.push(new ResponsePermission(permission));
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { RunnerCardHasScansError, RunnerCardIdsNotMatchingError, RunnerCardNotFoundError } from '../errors/RunnerCardErrors'; import { RunnerCardHasScansError, RunnerCardIdsNotMatchingError, RunnerCardNotFoundError } from '../errors/RunnerCardErrors';
import { RunnerNotFoundError } from '../errors/RunnerErrors'; import { RunnerNotFoundError } from '../errors/RunnerErrors';
import { CreateRunnerCard } from '../models/actions/create/CreateRunnerCard'; import { CreateRunnerCard } from '../models/actions/create/CreateRunnerCard';
@@ -26,9 +26,16 @@ export class RunnerCardController {
@Authorized("CARD:GET") @Authorized("CARD:GET")
@ResponseSchema(ResponseRunnerCard, { isArray: true }) @ResponseSchema(ResponseRunnerCard, { isArray: true })
@OpenAPI({ description: 'Lists all card.' }) @OpenAPI({ description: 'Lists all card.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseCards: ResponseRunnerCard[] = new Array<ResponseRunnerCard>(); let responseCards: ResponseRunnerCard[] = new Array<ResponseRunnerCard>();
const cards = await this.cardRepository.find({ relations: ['runner', 'runner.group', 'runner.group.parentGroup'] }); let cards: Array<RunnerCard>;
if (page) {
cards = await this.cardRepository.find({ relations: ['runner', 'runner.group', 'runner.group.parentGroup'], skip: page * page_size, take: page_size });
} else {
cards = await this.cardRepository.find({ relations: ['runner', 'runner.group', 'runner.group.parentGroup'] });
}
cards.forEach(card => { cards.forEach(card => {
responseCards.push(new ResponseRunnerCard(card)); responseCards.push(new ResponseRunnerCard(card));
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { RunnerGroupNeededError, RunnerHasDistanceDonationsError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; import { RunnerGroupNeededError, RunnerHasDistanceDonationsError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors';
import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors';
import { CreateRunner } from '../models/actions/create/CreateRunner'; import { CreateRunner } from '../models/actions/create/CreateRunner';
@@ -30,9 +30,16 @@ export class RunnerController {
@Authorized("RUNNER:GET") @Authorized("RUNNER:GET")
@ResponseSchema(ResponseRunner, { isArray: true }) @ResponseSchema(ResponseRunner, { isArray: true })
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' }) @OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>(); let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
const runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }); let runners: Array<Runner>;
if (page) {
runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track'], skip: page * page_size, take: page_size });
} else {
runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track'] });
}
runners.forEach(runner => { runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner)); responseRunners.push(new ResponseRunner(runner));
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, BadRequestError, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { RunnerOrganizationHasRunnersError, RunnerOrganizationHasTeamsError, RunnerOrganizationIdsNotMatchingError, RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors'; import { RunnerOrganizationHasRunnersError, RunnerOrganizationHasTeamsError, RunnerOrganizationIdsNotMatchingError, RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization'; import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization';
import { UpdateRunnerOrganization } from '../models/actions/update/UpdateRunnerOrganization'; import { UpdateRunnerOrganization } from '../models/actions/update/UpdateRunnerOrganization';
@@ -29,13 +29,20 @@ export class RunnerOrganizationController {
@Authorized("ORGANIZATION:GET") @Authorized("ORGANIZATION:GET")
@ResponseSchema(ResponseRunnerOrganization, { isArray: true }) @ResponseSchema(ResponseRunnerOrganization, { isArray: true })
@OpenAPI({ description: 'Lists all organizations. <br> This includes their address, contact and teams (if existing/associated).' }) @OpenAPI({ description: 'Lists all organizations. <br> This includes their address, contact and teams (if existing/associated).' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseTeams: ResponseRunnerOrganization[] = new Array<ResponseRunnerOrganization>(); let responseOrgs: ResponseRunnerOrganization[] = new Array<ResponseRunnerOrganization>();
const runners = await this.runnerOrganizationRepository.find({ relations: ['contact', 'teams'] }); let orgs: Array<RunnerOrganization>;
runners.forEach(runner => {
responseTeams.push(new ResponseRunnerOrganization(runner)); if (page) {
orgs = await this.runnerOrganizationRepository.find({ relations: ['contact', 'teams'], skip: page * page_size, take: page_size });
} else {
orgs = await this.runnerOrganizationRepository.find({ relations: ['contact', 'teams'] });
}
orgs.forEach(org => {
responseOrgs.push(new ResponseRunnerOrganization(org));
}); });
return responseTeams; return responseOrgs;
} }
@Get('/:id') @Get('/:id')
@@ -114,6 +121,10 @@ export class RunnerOrganizationController {
@OnUndefined(204) @OnUndefined(204)
@OpenAPI({ description: 'Delete the organsisation whose id you provided. <br> If the organization still has runners and/or teams associated this will fail. <br> To delete the organization with all associated runners and teams set the force QueryParam to true (cascading deletion might take a while). <br> This won\'t delete the associated contact. <br> If no organization with this id exists it will just return 204(no content).' }) @OpenAPI({ description: 'Delete the organsisation whose id you provided. <br> If the organization still has runners and/or teams associated this will fail. <br> To delete the organization with all associated runners and teams set the force QueryParam to true (cascading deletion might take a while). <br> This won\'t delete the associated contact. <br> If no organization with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
if (id == 1) {
throw new BadRequestError("You can't delete the citizen runner org.");
}
let organization = await this.runnerOrganizationRepository.findOne({ id: id }); let organization = await this.runnerOrganizationRepository.findOne({ id: id });
if (!organization) { return null; } if (!organization) { return null; }
let runnerOrganization = await this.runnerOrganizationRepository.findOne(organization, { relations: ['contact', 'runners', 'teams'] }); let runnerOrganization = await this.runnerOrganizationRepository.findOne(organization, { relations: ['contact', 'runners', 'teams'] });

View File

@@ -119,7 +119,7 @@ export class RunnerSelfServiceController {
@Post('/runners/login') @Post('/runners/login')
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@OnUndefined(ResponseEmpty) @OnUndefined(ResponseEmpty)
@OpenAPI({ description: 'Use this endpoint to reuqest a new selfservice token/link to be sent to your mail address (rate limited to one mail every 24hrs).' }) @OpenAPI({ description: 'Use this endpoint to reuqest a new selfservice magic-login-link to be sent to your mail address (rate limited to one mail every 15mins).' })
async requestNewToken(@QueryParam('mail') mail: string, @QueryParam("locale") locale: string = "en") { async requestNewToken(@QueryParam('mail') mail: string, @QueryParam("locale") locale: string = "en") {
if (!mail) { if (!mail) {
throw new RunnerNotFoundError(); throw new RunnerNotFoundError();
@@ -127,7 +127,7 @@ export class RunnerSelfServiceController {
const runner = await this.runnerRepository.findOne({ email: mail }); const runner = await this.runnerRepository.findOne({ email: mail });
if (!runner) { throw new RunnerNotFoundError(); } if (!runner) { throw new RunnerNotFoundError(); }
if (runner.resetRequestedTimestamp > (Math.floor(Date.now() / 1000) - 60 * 60 * 24)) { throw new RunnerSelfserviceTimeoutError(); } if (runner.resetRequestedTimestamp > (Math.floor(Date.now() / 1000) - 60 * 15)) { throw new RunnerSelfserviceTimeoutError(); }
const token = JwtCreator.createSelfService(runner); const token = JwtCreator.createSelfService(runner);
try { try {

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { RunnerTeamHasRunnersError, RunnerTeamIdsNotMatchingError, RunnerTeamNotFoundError } from '../errors/RunnerTeamErrors'; import { RunnerTeamHasRunnersError, RunnerTeamIdsNotMatchingError, RunnerTeamNotFoundError } from '../errors/RunnerTeamErrors';
import { CreateRunnerTeam } from '../models/actions/create/CreateRunnerTeam'; import { CreateRunnerTeam } from '../models/actions/create/CreateRunnerTeam';
import { UpdateRunnerTeam } from '../models/actions/update/UpdateRunnerTeam'; import { UpdateRunnerTeam } from '../models/actions/update/UpdateRunnerTeam';
@@ -27,11 +27,18 @@ export class RunnerTeamController {
@Authorized("TEAM:GET") @Authorized("TEAM:GET")
@ResponseSchema(ResponseRunnerTeam, { isArray: true }) @ResponseSchema(ResponseRunnerTeam, { isArray: true })
@OpenAPI({ description: 'Lists all teams. <br> This includes their parent organization and contact (if existing/associated).' }) @OpenAPI({ description: 'Lists all teams. <br> This includes their parent organization and contact (if existing/associated).' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseTeams: ResponseRunnerTeam[] = new Array<ResponseRunnerTeam>(); let responseTeams: ResponseRunnerTeam[] = new Array<ResponseRunnerTeam>();
const runners = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] }); let teams: Array<RunnerTeam>;
runners.forEach(runner => {
responseTeams.push(new ResponseRunnerTeam(runner)); if (page) {
teams = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'], skip: page * page_size, take: page_size });
} else {
teams = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] });
}
teams.forEach(team => {
responseTeams.push(new ResponseRunnerTeam(team));
}); });
return responseTeams; return responseTeams;
} }

View File

@@ -1,7 +1,7 @@
import { Request } from "express"; import { Request } from "express";
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam, Req, UseBefore } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam, Req, UseBefore } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { RunnerNotFoundError } from '../errors/RunnerErrors'; import { RunnerNotFoundError } from '../errors/RunnerErrors';
import { ScanIdsNotMatchingError, ScanNotFoundError } from '../errors/ScanErrors'; import { ScanIdsNotMatchingError, ScanNotFoundError } from '../errors/ScanErrors';
import { ScanStationNotFoundError } from '../errors/ScanStationErrors'; import { ScanStationNotFoundError } from '../errors/ScanStationErrors';
@@ -34,9 +34,16 @@ export class ScanController {
@ResponseSchema(ResponseScan, { isArray: true }) @ResponseSchema(ResponseScan, { isArray: true })
@ResponseSchema(ResponseTrackScan, { 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.' }) @OpenAPI({ description: 'Lists all scans (normal or track) from all runners. <br> This includes the scan\'s runner\'s distance ran.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseScans: ResponseScan[] = new Array<ResponseScan>(); let responseScans: ResponseScan[] = new Array<ResponseScan>();
const scans = await this.scanRepository.find({ relations: ['runner', 'track', 'runner.scans', 'runner.group', 'runner.scans.track', 'card', 'station'] }); let scans: Array<Scan>;
if (page) {
scans = await this.scanRepository.find({ relations: ['runner', 'track'], skip: page * page_size, take: page_size });
} else {
scans = await this.scanRepository.find({ relations: ['runner', 'track'] });
}
scans.forEach(scan => { scans.forEach(scan => {
responseScans.push(scan.toResponse()); responseScans.push(scan.toResponse());
}); });
@@ -51,7 +58,7 @@ export class ScanController {
@OnUndefined(ScanNotFoundError) @OnUndefined(ScanNotFoundError)
@OpenAPI({ description: 'Lists all information about the scan whose id got provided. This includes the scan\'s runner\'s distance ran.' }) @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) { async getOne(@Param('id') id: number) {
let scan = await this.scanRepository.findOne({ id: id }, { relations: ['runner', 'track', 'runner.scans', 'runner.group', 'runner.scans.track', 'card', 'station'] }) let scan = await this.scanRepository.findOne({ id: id }, { relations: ['runner', 'track', 'runner.group', 'card', 'station'] })
if (!scan) { throw new ScanNotFoundError(); } if (!scan) { throw new ScanNotFoundError(); }
return scan.toResponse(); return scan.toResponse();
} }

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { ScanStationHasScansError, ScanStationIdsNotMatchingError, ScanStationNotFoundError } from '../errors/ScanStationErrors'; import { ScanStationHasScansError, ScanStationIdsNotMatchingError, ScanStationNotFoundError } from '../errors/ScanStationErrors';
import { TrackNotFoundError } from '../errors/TrackErrors'; import { TrackNotFoundError } from '../errors/TrackErrors';
import { CreateScanStation } from '../models/actions/create/CreateScanStation'; import { CreateScanStation } from '../models/actions/create/CreateScanStation';
@@ -26,9 +26,16 @@ export class ScanStationController {
@Authorized("STATION:GET") @Authorized("STATION:GET")
@ResponseSchema(ResponseScanStation, { isArray: true }) @ResponseSchema(ResponseScanStation, { isArray: true })
@OpenAPI({ description: 'Lists all stations. <br> This includes their associated tracks.' }) @OpenAPI({ description: 'Lists all stations. <br> This includes their associated tracks.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseStations: ResponseScanStation[] = new Array<ResponseScanStation>(); let responseStations: ResponseScanStation[] = new Array<ResponseScanStation>();
const stations = await this.stationRepository.find({ relations: ['track'] }); let stations: Array<ScanStation>;
if (page) {
stations = await this.stationRepository.find({ relations: ['track'], skip: page * page_size, take: page_size });
} else {
stations = await this.stationRepository.find({ relations: ['track'] });
}
stations.forEach(station => { stations.forEach(station => {
responseStations.push(station.toResponse()); responseStations.push(station.toResponse());
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { StatsClientNotFoundError } from '../errors/StatsClientErrors'; import { StatsClientNotFoundError } from '../errors/StatsClientErrors';
import { TrackNotFoundError } from "../errors/TrackErrors"; import { TrackNotFoundError } from "../errors/TrackErrors";
import { CreateStatsClient } from '../models/actions/create/CreateStatsClient'; import { CreateStatsClient } from '../models/actions/create/CreateStatsClient';
@@ -24,9 +24,16 @@ export class StatsClientController {
@Authorized("STATSCLIENT:GET") @Authorized("STATSCLIENT:GET")
@ResponseSchema(ResponseStatsClient, { isArray: true }) @ResponseSchema(ResponseStatsClient, { isArray: true })
@OpenAPI({ description: 'Lists all stats clients. Please remember that the key can only be viewed on creation.' }) @OpenAPI({ description: 'Lists all stats clients. Please remember that the key can only be viewed on creation.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseClients: ResponseStatsClient[] = new Array<ResponseStatsClient>(); let responseClients: ResponseStatsClient[] = new Array<ResponseStatsClient>();
const clients = await this.clientRepository.find(); let clients: Array<StatsClient>;
if (page) {
clients = await this.clientRepository.find({ skip: page * page_size, take: page_size });
} else {
clients = await this.clientRepository.find();
}
clients.forEach(clients => { clients.forEach(clients => {
responseClients.push(new ResponseStatsClient(clients)); responseClients.push(new ResponseStatsClient(clients));
}); });

View File

@@ -21,14 +21,22 @@ export class StatsController {
@ResponseSchema(ResponseStats) @ResponseSchema(ResponseStats)
@OpenAPI({ description: "A very basic stats endpoint providing basic counters for a dashboard or simmilar" }) @OpenAPI({ description: "A very basic stats endpoint providing basic counters for a dashboard or simmilar" })
async get() { async get() {
let connection = getConnection(); const connection = getConnection();
let runners = await connection.getRepository(Runner).find({ relations: ['scans', 'scans.track'] }); const runners = await connection.getRepository(Runner).count();
let teams = await connection.getRepository(RunnerTeam).find(); const teams = await connection.getRepository(RunnerTeam).count();
let orgs = await connection.getRepository(RunnerOrganization).find(); const orgs = await connection.getRepository(RunnerOrganization).count();
let users = await connection.getRepository(User).find(); const users = await connection.getRepository(User).count();
let scans = await connection.getRepository(Scan).find(); const scans = await connection.getRepository(Scan).count({ where: { valid: true } });
const distance_query = await connection.getRepository(Scan).createQueryBuilder('scan')
.leftJoinAndSelect("scan.track", "track").where("scan.valid = TRUE")
.select("SUM(track.distance)", "sum_track").addSelect("SUM(_distance)", "sum_distance")
.getRawOne();
let distace = parseInt(distance_query.sum_track)
if (distance_query.sum_distance) {
distace += parseInt(distance_query.sum_distance)
}
let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] }); let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] });
return new ResponseStats(runners, teams, orgs, users, scans, donations) return new ResponseStats(runners, teams, orgs, users, scans, donations, distace)
} }
@Get("/runners/distance") @Get("/runners/distance")

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { TrackHasScanStationsError, TrackIdsNotMatchingError, TrackLapTimeCantBeNegativeError, TrackNotFoundError } from "../errors/TrackErrors"; import { TrackHasScanStationsError, TrackIdsNotMatchingError, TrackLapTimeCantBeNegativeError, TrackNotFoundError } from "../errors/TrackErrors";
import { CreateTrack } from '../models/actions/create/CreateTrack'; import { CreateTrack } from '../models/actions/create/CreateTrack';
import { UpdateTrack } from '../models/actions/update/UpdateTrack'; import { UpdateTrack } from '../models/actions/update/UpdateTrack';
@@ -25,9 +25,17 @@ export class TrackController {
@Authorized("TRACK:GET") @Authorized("TRACK:GET")
@ResponseSchema(ResponseTrack, { isArray: true }) @ResponseSchema(ResponseTrack, { isArray: true })
@OpenAPI({ description: 'Lists all tracks.' }) @OpenAPI({ description: 'Lists all tracks.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseTracks: ResponseTrack[] = new Array<ResponseTrack>(); let responseTracks: ResponseTrack[] = new Array<ResponseTrack>();
const tracks = await this.trackRepository.find(); let tracks: Array<Track>;
if (page) {
tracks = await this.trackRepository.find({ skip: page * page_size, take: page_size });
}
else {
tracks = await this.trackRepository.find();
}
tracks.forEach(track => { tracks.forEach(track => {
responseTracks.push(new ResponseTrack(track)); responseTracks.push(new ResponseTrack(track));
}); });

View File

@@ -1,7 +1,7 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, UserDeletionNotConfirmedError, UserIdsNotMatchingError, UsernameContainsIllegalCharacterError, UserNotFoundError } from '../errors/UserErrors'; import { PasswordMustContainLowercaseLetterError, PasswordMustContainNumberError, PasswordMustContainUppercaseLetterError, PasswordTooShortError, UserDeletionNotConfirmedError, UserIdsNotMatchingError, UserNotFoundError, UsernameContainsIllegalCharacterError } from '../errors/UserErrors';
import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; import { UserGroupNotFoundError } from '../errors/UserGroupErrors';
import { CreateUser } from '../models/actions/create/CreateUser'; import { CreateUser } from '../models/actions/create/CreateUser';
import { UpdateUser } from '../models/actions/update/UpdateUser'; import { UpdateUser } from '../models/actions/update/UpdateUser';
@@ -28,9 +28,17 @@ export class UserController {
@Authorized("USER:GET") @Authorized("USER:GET")
@ResponseSchema(ResponseUser, { isArray: true }) @ResponseSchema(ResponseUser, { isArray: true })
@OpenAPI({ description: 'Lists all users. <br> This includes their groups and permissions granted to them.' }) @OpenAPI({ description: 'Lists all users. <br> This includes their groups and permissions granted to them.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseUsers: ResponseUser[] = new Array<ResponseUser>(); let responseUsers: ResponseUser[] = new Array<ResponseUser>();
const users = await this.userRepository.find({ relations: ['permissions', 'groups', 'groups.permissions'] }); let users: Array<User>;
if (page) {
users = await this.userRepository.find({ relations: ['permissions', 'groups', 'groups.permissions'], skip: page * page_size, take: page_size });
}
else {
users = await this.userRepository.find({ relations: ['permissions', 'groups', 'groups.permissions'] });
}
users.forEach(user => { users.forEach(user => {
responseUsers.push(new ResponseUser(user)); responseUsers.push(new ResponseUser(user));
}); });

View File

@@ -1,6 +1,6 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { Repository, getConnectionManager } from 'typeorm';
import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors'; import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors';
import { CreateUserGroup } from '../models/actions/create/CreateUserGroup'; import { CreateUserGroup } from '../models/actions/create/CreateUserGroup';
import { UpdateUserGroup } from '../models/actions/update/UpdateUserGroup'; import { UpdateUserGroup } from '../models/actions/update/UpdateUserGroup';
@@ -27,9 +27,16 @@ export class UserGroupController {
@Authorized("USERGROUP:GET") @Authorized("USERGROUP:GET")
@ResponseSchema(ResponseUserGroup, { isArray: true }) @ResponseSchema(ResponseUserGroup, { isArray: true })
@OpenAPI({ description: 'Lists all groups. <br> The information provided might change while the project continues to evolve.' }) @OpenAPI({ description: 'Lists all groups. <br> The information provided might change while the project continues to evolve.' })
async getAll() { async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
let responseGroups: ResponseUserGroup[] = new Array<ResponseUserGroup>(); let responseGroups: ResponseUserGroup[] = new Array<ResponseUserGroup>();
const groups = await this.userGroupsRepository.find({ relations: ['permissions'] }); let groups: Array<UserGroup>;
if (page) {
groups = await this.userGroupsRepository.find({ relations: ['permissions'], skip: page * page_size, take: page_size });
} else {
groups = await this.userGroupsRepository.find({ relations: ['permissions'] });
}
groups.forEach(group => { groups.forEach(group => {
responseGroups.push(group.toResponse()); responseGroups.push(group.toResponse());
}); });

View File

@@ -58,11 +58,11 @@ export class CreateTrackScan {
*/ */
public async getCard(): Promise<RunnerCard> { public async getCard(): Promise<RunnerCard> {
const id = this.card % 200000000000; const id = this.card % 200000000000;
const track = await getConnection().getRepository(RunnerCard).findOne({ id: id }, { relations: ["runner"] }); const runnerCard = await getConnection().getRepository(RunnerCard).findOne({ id: id }, { relations: ["runner"] });
if (!track) { if (!runnerCard) {
throw new RunnerCardNotFoundError(); throw new RunnerCardNotFoundError();
} }
return track; return runnerCard;
} }
/** /**
@@ -86,14 +86,13 @@ export class CreateTrackScan {
* @returns The validated scan with it's laptime set. * @returns The validated scan with it's laptime set.
*/ */
public async validateScan(scan: TrackScan): Promise<TrackScan> { public async validateScan(scan: TrackScan): Promise<TrackScan> {
const scans = await getConnection().getRepository(TrackScan).find({ where: { runner: scan.runner, valid: true }, relations: ["track"] }); const latestScan = await getConnection().getRepository(TrackScan).findOne({ where: { runner: scan.runner, valid: true }, relations: ["track"], order: { id: 'DESC' } });
if (scans.length == 0) { if (!latestScan) {
scan.lapTime = 0; scan.lapTime = 0;
scan.valid = true; scan.valid = true;
} }
else { else {
const newestScan = scans[scans.length - 1]; scan.lapTime = scan.timestamp - latestScan.timestamp;
scan.lapTime = scan.timestamp - newestScan.timestamp;
scan.valid = (scan.lapTime > scan.track.minimumLapTime); scan.valid = (scan.lapTime > scan.track.minimumLapTime);
} }
return scan; return scan;

View File

@@ -52,13 +52,7 @@ export class RunnerCard {
* Generates a ean-13 compliant string for barcode generation. * Generates a ean-13 compliant string for barcode generation.
*/ */
public get code(): string { public get code(): string {
const multiply = [1, 3]; return this.paddedId
let total = 0;
this.paddedId.split('').forEach((letter, index) => {
total += parseInt(letter, 10) * multiply[index % 2];
});
const checkSum = (Math.ceil(total / 10) * 10) - total;
return this.paddedId + checkSum.toString();
} }
/** /**

View File

@@ -2,11 +2,6 @@ import {
IsInt IsInt
} from "class-validator"; } from "class-validator";
import { Donation } from '../entities/Donation'; import { Donation } from '../entities/Donation';
import { Runner } from '../entities/Runner';
import { RunnerOrganization } from '../entities/RunnerOrganization';
import { RunnerTeam } from '../entities/RunnerTeam';
import { Scan } from '../entities/Scan';
import { User } from '../entities/User';
import { ResponseObjectType } from '../enums/ResponseObjectType'; import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse'; import { IResponse } from './IResponse';
@@ -78,13 +73,13 @@ export class ResponseStats implements IResponse {
* @param scans Array containing all scans - no relations have to be resolved. * @param scans Array containing all scans - no relations have to be resolved.
* @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track * @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track
*/ */
public constructor(runners: Runner[], teams: RunnerTeam[], orgs: RunnerOrganization[], users: User[], scans: Scan[], donations: Donation[]) { public constructor(runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number) {
this.total_runners = runners.length; this.total_runners = runners;
this.total_teams = teams.length; this.total_teams = teams;
this.total_orgs = orgs.length; this.total_orgs = orgs;
this.total_users = users.length; this.total_users = users;
this.total_scans = scans.filter(scan => { scan.valid === true }).length; this.total_scans = scans;
this.total_distance = runners.reduce((sum, current) => sum + current.distance, 0); this.total_distance = distance;
this.total_donation = donations.reduce((sum, current) => sum + current.amount, 0); this.total_donation = donations.reduce((sum, current) => sum + current.amount, 0);
this.average_distance = this.total_distance / this.total_runners; this.average_distance = this.total_distance / this.total_runners;
} }

View File

@@ -0,0 +1,19 @@
import axios from 'axios';
async function main() {
console.time("batches")
for (let i = 0; i < 100; i++) {
const batch = [];
for (let i = 0; i < 6; i++) {
batch.push(axios.post('http://localhost:4010/api/scans/trackscans', { card: 200000000001, station: 2 }, {
headers: {
Authorization: 'Bearer 10F2E64.BB4F6CC5-2148-4CCF-88B5-0AA85D0508A9'
}
}))
}
await Promise.all(batch)
console.timeLog("batches", `Finished batch ${i}`)
}
console.timeEnd("batches")
}
main();

View File

@@ -22,6 +22,12 @@ describe('deletion (non-existant)', () => {
expect(res2.status).toEqual(204); expect(res2.status).toEqual(204);
}); });
}); });
describe('deletion of citizen sould fail', () => {
it('delete', async () => {
const res3 = await axios.delete(base + '/api/organizations/1', axios_config);
expect(res3.status).toEqual(400);
});
});
// --------------- // ---------------
describe('adding + deletion (successfull)', () => { describe('adding + deletion (successfull)', () => {
let added_org_id let added_org_id

View File

@@ -66,6 +66,8 @@ describe('adding + getting scans', () => {
const res = await axios.get(base + '/api/scans/' + added_scan.id, axios_config); const res = await axios.get(base + '/api/scans/' + added_scan.id, axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
delete res.data.runner.distance;
delete added_scan.runner.distance;
expect(res.data).toEqual(added_scan); expect(res.data).toEqual(added_scan);
}); });
it('check if scans was added via the runner/scans endpoint.', async () => { it('check if scans was added via the runner/scans endpoint.', async () => {