Compare commits

..

2 Commits
1.3.6 ... main

Author SHA1 Message Date
5ef3b6eb97 merge dev to main (#208)
Co-authored-by: Nicolai Ort <info@nicolai-ort.com>
Reviewed-on: #208
Co-authored-by: Philipp Dormann <philipp@philippdormann.de>
Co-committed-by: Philipp Dormann <philipp@philippdormann.de>
2023-11-06 17:18:48 +00:00
e98e7717aa Merge pull request 'Releases 0.13.2 & 0.13.3' (#203) from dev into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #203
Reviewed-by: Philipp Dormann <philipp@noreply.git.odit.services>
2023-02-15 13:59:07 +00:00
36 changed files with 4986 additions and 6354 deletions

174
.drone.yml Normal file
View File

@@ -0,0 +1,174 @@
---
kind: secret
name: docker_username
get:
path: odit-registry-builder
name: username
---
kind: secret
name: docker_password
get:
path: odit-registry-builder
name: password
---
kind: secret
name: git_ssh
get:
path: odit-git-bot
name: sshkey
---
kind: secret
name: ci_token
get:
path: odit-ci-bot
name: apikey
---
kind: secret
name: npm_url
get:
path: odit-npm-cache
name: url
---
kind: pipeline
type: kubernetes
name: tests:node
clone:
disable: true
steps:
- name: checkout pr
image: alpine/git
commands:
- git clone $DRONE_REMOTE_URL .
- git checkout $DRONE_SOURCE_BRANCH
- name: run tests
image: registry.odit.services/hub/library/node:19.5.0-alpine3.16
commands:
- npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
- pnpm i
- pnpm test:ci
environment:
NPM_REGISTRY_URL:
from_secret: npm_url
trigger:
event:
- pull_request
---
kind: pipeline
type: kubernetes
name: build:dev
clone:
disable: true
steps:
- name: clone
image: alpine/git
commands:
- git clone $DRONE_REMOTE_URL .
- git checkout dev
- name: build dev
depends_on: ["clone"]
image: registry.odit.services/library/drone-kaniko
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
build_args:
- NPM_REGISTRY_URL:
from_secret: npm_url
repo: lfk/backend
tags:
- dev
cache: true
registry: registry.odit.services
trigger:
branch:
- dev
event:
- push
---
kind: pipeline
type: kubernetes
name: build:latest
clone:
disable: true
steps:
- name: clone
image: alpine/git
commands:
- git clone $DRONE_REMOTE_URL .
- git checkout dev
- git merge main
- git checkout main
- name: build latest
depends_on: ["clone"]
image: registry.odit.services/library/drone-kaniko
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
build_args:
- NPM_REGISTRY_URL:
from_secret: npm_url
repo: lfk/backend
tags:
- latest
cache: true
registry: registry.odit.services
- name: push merge to repo
depends_on: ["clone"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: false
remote: git@git.odit.services:lfk/backend.git
ssh_key:
from_secret: git_ssh
trigger:
branch:
- main
event:
- push
---
kind: pipeline
type: kubernetes
name: build:tags
steps:
- name: build $DRONE_TAG
depends_on: ["clone"]
image: registry.odit.services/library/drone-kaniko
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
build_args:
- NPM_REGISTRY_URL:
from_secret: npm_url
repo: lfk/backend
tags:
- "${DRONE_TAG}"
cache: true
registry: registry.odit.services
- 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: ci_token
trigger:
event:
- tag

View File

@@ -7,5 +7,4 @@ DB_PASSWORD=bla
DB_NAME=./test.sqlite DB_NAME=./test.sqlite
NODE_ENV=production NODE_ENV=production
POSTALCODE_COUNTRYCODE=DE POSTALCODE_COUNTRYCODE=DE
SEED_TEST_DATA=false SEED_TEST_DATA=false
SELFSERVICE_URL=bla

View File

@@ -1,33 +0,0 @@
name: Build release images
on:
push:
tags:
- "*.*.*"
jobs:
build-container:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 19
- run: npm i -g pnpm@10.7 && pnpm i
- run: pnpm licenses:export
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.odit.services
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: |
${{ vars.REGISTRY }}/lfk/backend:${{ github.ref_name }}
platforms: linux/amd64,linux/arm64

View File

@@ -9,7 +9,8 @@
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features", "editor.defaultFormatter": "vscode.typescript-language-features",
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.organizeImports": "explicit" "source.organizeImports": true,
// "source.fixAll": true
} }
}, },
"javascript.preferences.quoteStyle": "single", "javascript.preferences.quoteStyle": "single",

View File

@@ -2,99 +2,8 @@
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.
#### [1.3.6](https://git.odit.services/lfk/backend/compare/1.3.5...1.3.6)
- feat(runners): Allow created via being set via api [`d6755ed`](https://git.odit.services/lfk/backend/commit/d6755ed134071df635bc9d5821ceb2396c0f1d22)
- fix(participant): Switch to correct type [`599c75f`](https://git.odit.services/lfk/backend/commit/599c75fc00217eaec3cc87c0de50d059bdde685f)
#### [1.3.5](https://git.odit.services/lfk/backend/compare/1.3.4...1.3.5)
> 8 April 2025
- feat(runners): Generate selfservice urls on runner if requested or create/update/get single [`5415cd3`](https://git.odit.services/lfk/backend/commit/5415cd38a727e76632a01a4d2634a1777df5542c)
- chore(release): 1.3.5 [`bb213f0`](https://git.odit.services/lfk/backend/commit/bb213f001eff2157abf8741128f624f9cc991afe)
#### [1.3.4](https://git.odit.services/lfk/backend/compare/1.3.3...1.3.4)
> 28 March 2025
- feat: add runnersViaSelfservice to statsControllerGet [`5c5000a`](https://git.odit.services/lfk/backend/commit/5c5000a218b47815e6846ac8b857dcd1995bfa6f)
- chore(release): 1.3.4 [`175ba52`](https://git.odit.services/lfk/backend/commit/175ba52ffae8e6ba1fdc1603ac2f5eba15602046)
#### [1.3.3](https://git.odit.services/lfk/backend/compare/v1.3.2...1.3.3)
> 28 March 2025
- chore(release): 1.3.3 [`d559d04`](https://git.odit.services/lfk/backend/commit/d559d0403191c703fd6da0e3f3dab53eec9258c0)
- ci: remove "v" prefix from tags [`2af682d`](https://git.odit.services/lfk/backend/commit/2af682d1dd09df496eb9f3a9111c50c0c4117356)
#### [v1.3.2](https://git.odit.services/lfk/backend/compare/v1.3.1...v1.3.2)
> 28 March 2025
- chore(release): v1.3.2 [`30905e4`](https://git.odit.services/lfk/backend/commit/30905e481c69cfe62b4261544b4277de3a1a43c2)
- ci: pnpm@10.7 [`752d405`](https://git.odit.services/lfk/backend/commit/752d405bda9129f3cd288a956d5444cab316c2af)
#### [v1.3.1](https://git.odit.services/lfk/backend/compare/1.3.0...v1.3.1)
> 28 March 2025
- fix: TypeError: Cannot read properties of undefined (reading 'filter') - when trying to delete a org/team with runners [`#210`](https://git.odit.services/lfk/backend/issues/210)
- pnpm@10.7, node@23, argon-&gt;@node-rs/argon2 [`78dcad0`](https://git.odit.services/lfk/backend/commit/78dcad085794c93829499dd550a786c38d6186f5)
- chore(release): v1.3.1 [`8fa4ed7`](https://git.odit.services/lfk/backend/commit/8fa4ed7c3319c3e56a71701ba266ceda64d2ef69)
#### [1.3.0](https://git.odit.services/lfk/backend/compare/1.2.1...1.3.0)
> 28 March 2025
- feat: created_via for tracking how runners got into the system [`#212`](https://git.odit.services/lfk/backend/pull/212)
- feat: created_via for tracking how runners got into the system (#212) [`#211`](https://git.odit.services/lfk/backend/issues/211)
- ci: move to gitea workflows [`ebde8c6`](https://git.odit.services/lfk/backend/commit/ebde8c6ffd8b17c6752da8c4d8eb3095105f6132)
- chore(release): v1.3.0 [`93e0cdf`](https://git.odit.services/lfk/backend/commit/93e0cdf577654898b2d63790d91598c458a2db59)
- build: docker "AS" casing [`0a43f1b`](https://git.odit.services/lfk/backend/commit/0a43f1bb5b26d3acb0d4d91648473f0dc55e8637)
- ci: change release commit message [`6efcd94`](https://git.odit.services/lfk/backend/commit/6efcd94726957b8c527820f1a9b0130151ce22f1)
- refactor(RunnerController.remove): only load necessary relations [`8c6fdb2`](https://git.odit.services/lfk/backend/commit/8c6fdb22390218e385780fadb3bdaf32148ac054)
- refactor(RunnerTeamController.remove): only load necessary relations [`c0d5af5`](https://git.odit.services/lfk/backend/commit/c0d5af5d7ab44cfdf19014e0d774fb560d08f6d7)
- fix: add .created_via to ResponseParticipant constructor [`2e271bc`](https://git.odit.services/lfk/backend/commit/2e271bcd52f02ab7449cd15916b0afc86e8b0a90)
#### [1.2.1](https://git.odit.services/lfk/backend/compare/1.2.0...1.2.1)
> 11 December 2024
- refactor: allow selfservice link every 30s [`07bf28b`](https://git.odit.services/lfk/backend/commit/07bf28b14458849930748ce041fb65e572759482)
- chore(release): 1.2.1 [`4008a5e`](https://git.odit.services/lfk/backend/commit/4008a5ee720b212bac9cba64417058bf4526060b)
#### [1.2.0](https://git.odit.services/lfk/backend/compare/v1.1.4...1.2.0)
> 11 December 2024
- refactor: move to new mailer [`0f4c8b2`](https://git.odit.services/lfk/backend/commit/0f4c8b2051cae17fbdd7e02017ad5b41c61e210c)
- refactor(ci): Switch to new woodpecker [`b3a73b2`](https://git.odit.services/lfk/backend/commit/b3a73b25e80a0466ff83e43481271fc0cd499a0d)
- feat: middlename [`6eff243`](https://git.odit.services/lfk/backend/commit/6eff2438035b368eb45931fad9402a6cb942b350)
- SELFSERVICE_URL [`765ef84`](https://git.odit.services/lfk/backend/commit/765ef849035ca4f8b2253bb76d15be8e9a3e6763)
- FRONTEND_URL env [`296ba8d`](https://git.odit.services/lfk/backend/commit/296ba8ddab1dba46f8201829d9a7e5fc1c88c0f8)
- chore: update readme [`d842c14`](https://git.odit.services/lfk/backend/commit/d842c14240fb4a7f70c66143bbe877f8168ef6d4)
- chore(release): 1.2.0 [`6764bf8`](https://git.odit.services/lfk/backend/commit/6764bf80eac832d186e688319d8a959543a1495f)
- Merge pull request 'refactor: move to new mailer' (#209) from refactor/new-mailer into dev [`bda1f97`](https://git.odit.services/lfk/backend/commit/bda1f971d1a14ea403439533c7ae31280c7df167)
#### [v1.1.4](https://git.odit.services/lfk/backend/compare/v1.1.3...v1.1.4)
> 20 November 2024
- build: package lock [`50dd703`](https://git.odit.services/lfk/backend/commit/50dd703a1bd276a607cc10a087c7e90fd880847a)
- fix(deps): Bump sqlite3 [`cd3cd81`](https://git.odit.services/lfk/backend/commit/cd3cd81360777e8bc4d78e861354e58c8da79cc7)
- feat(ci)!: Switch to woodpecker [`3192365`](https://git.odit.services/lfk/backend/commit/3192365793fae59f2b89e3231db298654f0a28e9)
- fix(deps): Bumped argon2 to latest version for arm support [`cf48c00`](https://git.odit.services/lfk/backend/commit/cf48c00ddb2ac33263549876928db50ae152c12d)
- fix: updated README for pnpm, typos [`5082b1b`](https://git.odit.services/lfk/backend/commit/5082b1b8b1c0ae9e8ffa9c71c4d7923fd9223c87)
- 🚀Bumped version to v1.1.4 [`a54cb28`](https://git.odit.services/lfk/backend/commit/a54cb287a4323ac8de77f51711cc6c52ec290859)
- ci: drop lfk-client-node [`075d484`](https://git.odit.services/lfk/backend/commit/075d484f1169bfc5c5b68cb9712116b0e270b471)
- fix(dependencies): Switch back to previous class-validator version to produce a working build [`74d334f`](https://git.odit.services/lfk/backend/commit/74d334f9b747a77115bd9b97729ef1120822e128)
#### [v1.1.3](https://git.odit.services/lfk/backend/compare/v1.1.2...v1.1.3) #### [v1.1.3](https://git.odit.services/lfk/backend/compare/v1.1.2...v1.1.3)
> 10 May 2023
- 🚀Bumped version to v1.1.3 [`057a8ee`](https://git.odit.services/lfk/backend/commit/057a8ee699d08c0e4a80cb50a8820f819569c9ac)
- feat(orgs): Also resolve child-teams' distances and add them to org total [`8d94186`](https://git.odit.services/lfk/backend/commit/8d9418635d3e381c0f55a2521a3334ba497c169a) - feat(orgs): Also resolve child-teams' distances and add them to org total [`8d94186`](https://git.odit.services/lfk/backend/commit/8d9418635d3e381c0f55a2521a3334ba497c169a)
- fix(orgs): Removed unused log [`f2832a2`](https://git.odit.services/lfk/backend/commit/f2832a2daecc7bc7bbee4d4fceeab8db194730cf) - fix(orgs): Removed unused log [`f2832a2`](https://git.odit.services/lfk/backend/commit/f2832a2daecc7bc7bbee4d4fceeab8db194730cf)

View File

@@ -1,12 +1,10 @@
# Typescript Build # Typescript Build
FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS build FROM registry.odit.services/hub/library/node:21.1.0-alpine3.18 as build
ARG NPM_REGISTRY_URL=https://registry.npmjs.org ARG NPM_REGISTRY_URL=https://registry.npmjs.org
WORKDIR /app WORKDIR /app
COPY package.json ./ COPY package.json ./
COPY pnpm-workspace.yaml ./ RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
COPY pnpm-lock.yaml ./
RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@10.7
RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i
COPY tsconfig.json ormconfig.js ./ COPY tsconfig.json ormconfig.js ./
@@ -16,11 +14,9 @@ RUN pnpm run build \
&& pnpm i --production --prefer-offline && pnpm i --production --prefer-offline
# final image # final image
FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS final FROM registry.odit.services/hub/library/node:21.1.0-alpine3.18 as final
WORKDIR /app WORKDIR /app
COPY --from=build /app/package.json /app/package.json COPY --from=build /app/package.json /app/package.json
COPY --from=build /app/pnpm-lock.yaml /app/pnpm-lock.yaml
COPY --from=build /app/pnpm-workspace.yaml /app/pnpm-workspace.yaml
COPY --from=build /app/ormconfig.js /app/ormconfig.js COPY --from=build /app/ormconfig.js /app/ormconfig.js
COPY --from=build /app/dist /app/dist COPY --from=build /app/dist /app/dist
COPY --from=build /app/node_modules /app/node_modules COPY --from=build /app/node_modules /app/node_modules

View File

@@ -35,6 +35,13 @@ pnpm test:watch
pnpm test:ci pnpm test:ci
``` ```
### Use your own mail templates
> You use your own mail templates by replacing the default ones we provided (either in-code or by mounting them into the /app/static/mail_templates folder).
The mail templates always come in a .html and a .txt variant to provide compatability with legacy mail clients.
Currently the following templates exist:
* pw-reset.(html/txt)
### Generate Docs ### Generate Docs
```bash ```bash
pnpm docs pnpm docs
@@ -59,7 +66,6 @@ pnpm docs
| SEED_TEST_DATA | Boolean | False | If you want the app to seed some example data set this to true | | SEED_TEST_DATA | Boolean | False | If you want the app to seed some example data set this to true |
| MAILER_URL | String(Url) | N/A | The mailer's base url (no trailing slash) | | MAILER_URL | String(Url) | N/A | The mailer's base url (no trailing slash) |
| MAILER_KEY | String | N/A | The mailer's api key. | | MAILER_KEY | String | N/A | The mailer's api key. |
| SELFSERVICE_URL | String(Url) | N/A | The link to selfservice (no trailing slash) |
| IMPRINT_URL | String(Url) | /imprint | The link to a imprint page for the system (Defaults to the frontend's imprint) | | IMPRINT_URL | String(Url) | /imprint | The link to a imprint page for the system (Defaults to the frontend's imprint) |
| PRIVACY_URL | String(Url) | /privacy | The link to a privacy page for the system (Defaults to the frontend's privacy page) | | PRIVACY_URL | String(Url) | /privacy | The link to a privacy page for the system (Defaults to the frontend's privacy page) |

View File

@@ -1,3 +1,4 @@
version: "3"
services: services:
backend_server: backend_server:
build: . build: .
@@ -13,7 +14,7 @@ services:
DB_NAME: ./db.sqlite DB_NAME: ./db.sqlite
NODE_ENV: production NODE_ENV: production
POSTALCODE_COUNTRYCODE: DE POSTALCODE_COUNTRYCODE: DE
SEED_TEST_DATA: "true" SEED_TEST_DATA: "false"
MAILER_URL: https://dev.lauf-fuer-kaya.de/mailer MAILER_URL: https://dev.lauf-fuer-kaya.de/mailer
MAILER_KEY: asdasd MAILER_KEY: asdasd
# APP_PORT: 4010 # APP_PORT: 4010

View File

@@ -1,32 +1,3 @@
# @node-rs/argon2
**Author**: undefined
**Repo**: [object Object]
**License**: MIT
**Description**: RustCrypto: Argon2 binding for Node.js
## License Text
MIT License
Copyright (c) 2020-present LongYinan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# @odit/class-validator-jsonschema # @odit/class-validator-jsonschema
**Author**: Aleksi Pekkala <aleksipekkala@gmail.com> **Author**: Aleksi Pekkala <aleksipekkala@gmail.com>
**Repo**: git@github.com:epiphone/class-validator-jsonschema.git **Repo**: git@github.com:epiphone/class-validator-jsonschema.git
@@ -56,6 +27,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
# argon2
**Author**: Ranieri Althoff <ranisalt+argon2@gmail.com>
**Repo**: [object Object]
**License**: MIT
**Description**: An Argon2 library for Node
## License Text
The MIT License (MIT)
Copyright (c) 2015 Ranieri Althoff
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# axios # axios
**Author**: Matt Zabriskie **Author**: Matt Zabriskie
**Repo**: [object Object] **Repo**: [object Object]

View File

@@ -1,8 +1,11 @@
{ {
"name": "@odit/lfk-backend", "name": "@odit/lfk-backend",
"version": "1.3.6", "version": "1.1.3",
"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",
@@ -22,13 +25,13 @@
], ],
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
"dependencies": { "dependencies": {
"@node-rs/argon2": "^2.0.2",
"@odit/class-validator-jsonschema": "2.1.1", "@odit/class-validator-jsonschema": "2.1.1",
"argon2": "0.27.1",
"axios": "0.21.1", "axios": "0.21.1",
"body-parser": "1.19.0", "body-parser": "1.19.0",
"check-password-strength": "2.0.2", "check-password-strength": "2.0.2",
"class-transformer": "0.3.1", "class-transformer": "0.3.1",
"class-validator": "0.13.0", "class-validator": "0.13.1",
"consola": "2.15.0", "consola": "2.15.0",
"cookie": "0.4.1", "cookie": "0.4.1",
"cookie-parser": "1.4.5", "cookie-parser": "1.4.5",
@@ -43,7 +46,7 @@
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"routing-controllers": "0.9.0-alpha.6", "routing-controllers": "0.9.0-alpha.6",
"routing-controllers-openapi": "2.2.0", "routing-controllers-openapi": "2.2.0",
"sqlite3": "5.1.7", "sqlite3": "5.0.0",
"typeorm": "0.2.30", "typeorm": "0.2.30",
"typeorm-routing-controllers-extensions": "0.2.0", "typeorm-routing-controllers-extensions": "0.2.0",
"typeorm-seeding": "1.6.1", "typeorm-seeding": "1.6.1",
@@ -91,12 +94,12 @@
"git": { "git": {
"commit": true, "commit": true,
"requireCleanWorkingDir": false, "requireCleanWorkingDir": false,
"commitMessage": "chore(release): ${version}", "commitMessage": "🚀Bumped version to v${version}",
"requireBranch": "dev", "requireBranch": "dev",
"push": true, "push": true,
"tag": true, "tag": true,
"tagName": "${version}", "tagName": "v${version}",
"tagAnnotation": "${version}" "tagAnnotation": "v${version}"
}, },
"npm": { "npm": {
"publish": false "publish": false
@@ -111,4 +114,4 @@
"docs/*" "docs/*"
] ]
} }
} }

10735
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
onlyBuiltDependencies:
- sqlite3

View File

@@ -30,7 +30,7 @@ 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(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100, @QueryParam("selfservice_links", { required: false }) selfservice_links: boolean = false) { 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>();
let runners: Array<Runner>; let runners: Array<Runner>;
@@ -41,7 +41,7 @@ export class RunnerController {
} }
runners.forEach(runner => { runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner, selfservice_links)); responseRunners.push(new ResponseRunner(runner));
}); });
return responseRunners; return responseRunners;
} }
@@ -55,7 +55,7 @@ export class RunnerController {
async getOne(@Param('id') id: number) { async getOne(@Param('id') id: number) {
let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }) let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] })
if (!runner) { throw new RunnerNotFoundError(); } if (!runner) { throw new RunnerNotFoundError(); }
return new ResponseRunner(runner, true); return new ResponseRunner(runner);
} }
@Get('/:id/scans') @Get('/:id/scans')
@@ -98,7 +98,7 @@ export class RunnerController {
} }
runner = await this.runnerRepository.save(runner) runner = await this.runnerRepository.save(runner)
return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }), true); return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }));
} }
@Put('/:id') @Put('/:id')
@@ -119,7 +119,7 @@ export class RunnerController {
} }
await this.runnerRepository.save(await runner.update(oldRunner)); await this.runnerRepository.save(await runner.update(oldRunner));
return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }), true); return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }));
} }
@Delete('/:id') @Delete('/:id')
@@ -132,7 +132,7 @@ export class RunnerController {
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let runner = await this.runnerRepository.findOne({ id: id }); let runner = await this.runnerRepository.findOne({ id: id });
if (!runner) { return null; } if (!runner) { return null; }
const responseRunner = await this.runnerRepository.findOne(runner); const responseRunner = await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] });
if (!runner) { if (!runner) {
throw new RunnerNotFoundError(); throw new RunnerNotFoundError();

View File

@@ -127,11 +127,11 @@ 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) - 30)) { 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 {
await Mailer.sendSelfserviceForgottenMail(runner.email, runner.id, runner.firstname, runner.middlename, runner.lastname, token, locale) await Mailer.sendSelfserviceForgottenMail(runner.email, token, locale)
} catch (error) { } catch (error) {
throw new MailSendingError(); throw new MailSendingError();
} }
@@ -157,7 +157,7 @@ export class RunnerSelfServiceController {
response.token = JwtCreator.createSelfService(runner); response.token = JwtCreator.createSelfService(runner);
try { try {
await Mailer.sendSelfserviceWelcomeMail(runner.email, runner.id, runner.firstname, runner.middlename, runner.lastname, response.token, locale) await Mailer.sendSelfserviceWelcomeMail(runner.email, response.token, locale)
} catch (error) { } catch (error) {
throw new MailSendingError(); throw new MailSendingError();
} }
@@ -182,7 +182,7 @@ export class RunnerSelfServiceController {
response.token = JwtCreator.createSelfService(runner); response.token = JwtCreator.createSelfService(runner);
try { try {
await Mailer.sendSelfserviceWelcomeMail(runner.email, runner.id, runner.firstname, runner.middlename, runner.lastname, response.token, locale) await Mailer.sendSelfserviceWelcomeMail(runner.email, response.token, locale)
} catch (error) { } catch (error) {
throw new MailSendingError(); throw new MailSendingError();
} }

View File

@@ -119,7 +119,7 @@ export class RunnerTeamController {
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let team = await this.runnerTeamRepository.findOne({ id: id }); let team = await this.runnerTeamRepository.findOne({ id: id });
if (!team) { return null; } if (!team) { return null; }
let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['runners'] }); let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['parentGroup', 'contact', 'runners'] });
if (!force) { if (!force) {
if (runnerTeam.runners.length != 0) { if (runnerTeam.runners.length != 0) {

View File

@@ -23,7 +23,6 @@ export class StatsController {
@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() {
const connection = getConnection(); const connection = getConnection();
const runnersViaSelfservice = await connection.getRepository(Runner).count({ where: { created_via: "selfservice" } });
const runners = await connection.getRepository(Runner).count(); const runners = await connection.getRepository(Runner).count();
const teams = await connection.getRepository(RunnerTeam).count(); const teams = await connection.getRepository(RunnerTeam).count();
const orgs = await connection.getRepository(RunnerOrganization).count(); const orgs = await connection.getRepository(RunnerOrganization).count();
@@ -42,7 +41,7 @@ export class StatsController {
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'] });
const donors = await connection.getRepository(Donor).count(); const donors = await connection.getRepository(Donor).count();
return new ResponseStats(runnersViaSelfservice, runners, teams, orgs, users, scans, donations, distace, donors) return new ResponseStats(runners, teams, orgs, users, scans, donations, distace, donors)
} }
@Get("/runners/distance") @Get("/runners/distance")

View File

@@ -47,14 +47,14 @@ export class RunnerEmailNeededError extends NotAcceptableError {
} }
/** /**
* Error to throw when a runner already requested a new selfservice link in the last 30s. * Error to throw when a runner already requested a new selfservice link in the last 24hrs.
*/ */
export class RunnerSelfserviceTimeoutError extends NotAcceptableError { export class RunnerSelfserviceTimeoutError extends NotAcceptableError {
@IsString() @IsString()
name = "RunnerSelfserviceTimeoutError" name = "RunnerSelfserviceTimeoutError"
@IsString() @IsString()
message = "You can only reqest a new token every 30s." message = "You can only reqest a new token every 24hrs."
} }
/** /**

View File

@@ -18,19 +18,9 @@ export class Mailer {
*/ */
public static async sendResetMail(to_address: string, token: string, locale: string = "en") { public static async sendResetMail(to_address: string, token: string, locale: string = "en") {
try { try {
await axios.request({ await axios.post(`${Mailer.base}/reset?locale=${locale}&key=${Mailer.key}`, {
method: 'POST', address: to_address,
url: `${Mailer.base}/api/v1/email`, resetKey: token
headers: {
authorization: `Bearer ${Mailer.key}`,
'content-type': 'application/json'
},
data: {
to: to_address,
templateName: 'password-reset',
language: locale,
data: { token: token }
}
}); });
} catch (error) { } catch (error) {
if (Mailer.testing) { return true; } if (Mailer.testing) { return true; }
@@ -42,26 +32,12 @@ export class Mailer {
* Function for sending a runner selfservice welcome mail. * Function for sending a runner selfservice welcome mail.
* @param to_address The address the mail will be sent to. Should always get pulled from a runner object. * @param to_address The address the mail will be sent to. Should always get pulled from a runner object.
* @param token The requested selfservice token - will be combined with the app_url to generate a selfservice profile link. * @param token The requested selfservice token - will be combined with the app_url to generate a selfservice profile link.
*/ */
public static async sendSelfserviceWelcomeMail(to_address: string, runner_id: number, firstname: string, middlename: string, lastname: string, token: string, locale: string = "en") { public static async sendSelfserviceWelcomeMail(to_address: string, token: string, locale: string = "en") {
try { try {
await axios.request({ await axios.post(`${Mailer.base}/registration?locale=${locale}&key=${Mailer.key}`, {
method: 'POST', address: to_address,
url: `${Mailer.base}/api/v1/email`, selfserviceToken: token
headers: {
authorization: `Bearer ${Mailer.key}`,
'content-type': 'application/json'
},
data: {
to: to_address,
templateName: 'welcome',
language: locale,
data: {
name: `${firstname} ${middlename} ${lastname}`,
barcode_content: `${runner_id}`,
link: `${process.env.SELFSERVICE_URL}/profile/${token}`
}
}
}); });
} catch (error) { } catch (error) {
if (Mailer.testing) { return true; } if (Mailer.testing) { return true; }
@@ -73,26 +49,12 @@ export class Mailer {
* Function for sending a runner selfservice link forgotten mail. * Function for sending a runner selfservice link forgotten mail.
* @param to_address The address the mail will be sent to. Should always get pulled from a runner object. * @param to_address The address the mail will be sent to. Should always get pulled from a runner object.
* @param token The requested selfservice token - will be combined with the app_url to generate a selfservice profile link. * @param token The requested selfservice token - will be combined with the app_url to generate a selfservice profile link.
*/ */
public static async sendSelfserviceForgottenMail(to_address: string, runner_id: number, firstname: string, middlename: string, lastname: string, token: string, locale: string = "en") { public static async sendSelfserviceForgottenMail(to_address: string, token: string, locale: string = "en") {
try { try {
await axios.request({ await axios.post(`${Mailer.base}/registration_forgot?locale=${locale}&key=${Mailer.key}`, {
method: 'POST', address: to_address,
url: `${Mailer.base}/api/v1/email`, selfserviceToken: token
headers: {
authorization: `Bearer ${Mailer.key}`,
'content-type': 'application/json'
},
data: {
to: to_address,
templateName: 'welcome',
language: locale,
data: {
name: `${firstname} ${middlename} ${lastname}`,
barcode_content: `${runner_id}`,
link: `${process.env.SELFSERVICE_URL}/profile/${token}`
}
}
}); });
} catch (error) { } catch (error) {
if (Mailer.testing) { return true; } if (Mailer.testing) { return true; }

View File

@@ -1,4 +1,4 @@
import { verify } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { ScanStation } from '../models/entities/ScanStation'; import { ScanStation } from '../models/entities/ScanStation';
@@ -58,7 +58,7 @@ const ScanAuth = async (req: Request, res: Response, next: () => void) => {
if (station.enabled == false) { if (station.enabled == false) {
res.status(401).send({ http_code: 401, short: "station_disabled", message: "Station is disabled." }); res.status(401).send({ http_code: 401, short: "station_disabled", message: "Station is disabled." });
} }
if (!(await verify(station.key, provided_token))) { if (!(await argon2.verify(station.key, provided_token))) {
res.status(401).send({ http_code: 401, short: "invalid_token", message: "Api token non-existent or invalid syntax." }); res.status(401).send({ http_code: 401, short: "invalid_token", message: "Api token non-existent or invalid syntax." });
return; return;
} }

View File

@@ -1,4 +1,4 @@
import { verify } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { StatsClient } from '../models/entities/StatsClient'; import { StatsClient } from '../models/entities/StatsClient';
@@ -55,7 +55,7 @@ const StatsAuth = async (req: Request, res: Response, next: () => void) => {
} }
} }
else { else {
if (!(await verify(client.key, provided_token))) { if (!(await argon2.verify(client.key, provided_token))) {
res.status(401).send("Api token invalid."); res.status(401).send("Api token invalid.");
return; return;
} }

View File

@@ -1,4 +1,4 @@
import { hash } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import * as jsonwebtoken from 'jsonwebtoken'; import * as jsonwebtoken from 'jsonwebtoken';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
@@ -49,7 +49,7 @@ export class ResetPassword {
if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) { throw new RefreshTokenCountInvalidError(); } if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) { throw new RefreshTokenCountInvalidError(); }
found_user.refreshTokenCount = found_user.refreshTokenCount + 1; found_user.refreshTokenCount = found_user.refreshTokenCount + 1;
found_user.password = await hash(this.password + found_user.uuid); found_user.password = await argon2.hash(this.password + found_user.uuid);
await getConnectionManager().get().getRepository(User).save(found_user); await getConnectionManager().get().getRepository(User).save(found_user);
return "password reset successfull"; return "password reset successfull";

View File

@@ -1,4 +1,4 @@
import { verify } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { InvalidCredentialsError, PasswordNeededError, UserDisabledError, UserNotFoundError } from '../../../errors/AuthError'; import { InvalidCredentialsError, PasswordNeededError, UserDisabledError, UserNotFoundError } from '../../../errors/AuthError';
@@ -56,7 +56,7 @@ export class CreateAuth {
throw new UserNotFoundError(); throw new UserNotFoundError();
} }
if (found_user.enabled == false) { throw new UserDisabledError(); } if (found_user.enabled == false) { throw new UserDisabledError(); }
if (!(await verify(found_user.password, this.password + found_user.uuid))) { if (!(await argon2.verify(found_user.password, this.password + found_user.uuid))) {
throw new InvalidCredentialsError(); throw new InvalidCredentialsError();
} }

View File

@@ -50,11 +50,4 @@ export abstract class CreateParticipant {
@IsOptional() @IsOptional()
@IsObject() @IsObject()
address?: Address; address?: Address;
/**
* how the participant got into the system
*/
@IsOptional()
@IsString()
created_via?: string;
} }

View File

@@ -32,9 +32,6 @@ export class CreateRunner extends CreateParticipant {
newRunner.email = this.email; newRunner.email = this.email;
newRunner.group = await this.getGroup(); newRunner.group = await this.getGroup();
newRunner.address = this.address; newRunner.address = this.address;
if (this.created_via) {
newRunner.created_via = this.created_via;
}
Address.validate(newRunner.address); Address.validate(newRunner.address);
return newRunner; return newRunner;

View File

@@ -1,4 +1,4 @@
import { hash } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { IsBoolean, IsInt, IsOptional, IsPositive, IsString } from 'class-validator'; import { IsBoolean, IsInt, IsOptional, IsPositive, IsString } from 'class-validator';
import crypto from 'crypto'; import crypto from 'crypto';
import { getConnection } from 'typeorm'; import { getConnection } from 'typeorm';
@@ -44,7 +44,7 @@ export class CreateScanStation {
let newUUID = uuid.v4().toUpperCase(); let newUUID = uuid.v4().toUpperCase();
newStation.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase(); newStation.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
newStation.key = await hash(newStation.prefix + "." + newUUID); newStation.key = await argon2.hash(newStation.prefix + "." + newUUID);
newStation.cleartextkey = newStation.prefix + "." + newUUID; newStation.cleartextkey = newStation.prefix + "." + newUUID;
return newStation; return newStation;

View File

@@ -26,7 +26,6 @@ export class CreateSelfServiceCitizenRunner extends CreateParticipant {
public async toEntity(): Promise<Runner> { public async toEntity(): Promise<Runner> {
let newRunner: Runner = new Runner(); let newRunner: Runner = new Runner();
newRunner.created_via = "selfservice";
newRunner.firstname = this.firstname; newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename; newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname; newRunner.lastname = this.lastname;

View File

@@ -28,7 +28,6 @@ export class CreateSelfServiceRunner extends CreateParticipant {
public async toEntity(group: RunnerGroup): Promise<Runner> { public async toEntity(group: RunnerGroup): Promise<Runner> {
let newRunner: Runner = new Runner(); let newRunner: Runner = new Runner();
newRunner.created_via = "selfservice";
newRunner.firstname = this.firstname; newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename; newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname; newRunner.lastname = this.lastname;

View File

@@ -1,4 +1,4 @@
import { hash } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { IsOptional, IsString } from 'class-validator'; import { IsOptional, IsString } from 'class-validator';
import crypto from 'crypto'; import crypto from 'crypto';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
@@ -25,7 +25,7 @@ export class CreateStatsClient {
let newUUID = uuid.v4().toUpperCase(); let newUUID = uuid.v4().toUpperCase();
newClient.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase(); newClient.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
newClient.key = await hash(newClient.prefix + "." + newUUID); newClient.key = await argon2.hash(newClient.prefix + "." + newUUID);
newClient.cleartextkey = newClient.prefix + "." + newUUID; newClient.cleartextkey = newClient.prefix + "." + newUUID;
return newClient; return newClient;

View File

@@ -1,4 +1,4 @@
import { hash } from "@node-rs/argon2"; import * as argon2 from "argon2";
import { passwordStrength } from "check-password-strength"; import { passwordStrength } from "check-password-strength";
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator'; import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
@@ -110,7 +110,7 @@ export class CreateUser {
newUser.lastname = this.lastname newUser.lastname = this.lastname
newUser.uuid = uuid.v4() newUser.uuid = uuid.v4()
newUser.phone = this.phone newUser.phone = this.phone
newUser.password = await hash(this.password + newUser.uuid); newUser.password = await argon2.hash(this.password + newUser.uuid);
newUser.groups = await this.getGroups(); newUser.groups = await this.getGroups();
newUser.enabled = this.enabled; newUser.enabled = this.enabled;

View File

@@ -1,4 +1,4 @@
import { hash } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { passwordStrength } from "check-password-strength"; import { passwordStrength } from "check-password-strength";
import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator'; import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
@@ -111,7 +111,7 @@ export class UpdateUser {
if (!password_strength.contains.includes("lowercase")) { throw new PasswordMustContainLowercaseLetterError(); } if (!password_strength.contains.includes("lowercase")) { throw new PasswordMustContainLowercaseLetterError(); }
if (!password_strength.contains.includes("number")) { throw new PasswordMustContainNumberError(); } if (!password_strength.contains.includes("number")) { throw new PasswordMustContainNumberError(); }
if (!(password_strength.length > 9)) { throw new PasswordTooShortError(); } if (!(password_strength.length > 9)) { throw new PasswordTooShortError(); }
user.password = await hash(this.password + user.uuid); user.password = await argon2.hash(this.password + user.uuid);
user.refreshTokenCount = user.refreshTokenCount + 1; user.refreshTokenCount = user.refreshTokenCount + 1;
} }

View File

@@ -75,14 +75,6 @@ export abstract class Participant {
@IsEmail() @IsEmail()
email?: string; email?: string;
/**
* how the participant got into the system
*/
@Column({ nullable: true, default: "backend" })
@IsOptional()
@IsString()
created_via?: string;
/** /**
* Turns this entity into it's response class. * Turns this entity into it's response class.
*/ */

View File

@@ -57,10 +57,7 @@ export class Runner extends Participant {
* This is implemented here to avoid duplicate code in other files. * This is implemented here to avoid duplicate code in other files.
*/ */
public get validScans(): Scan[] { public get validScans(): Scan[] {
if (this.scans) { return this.scans.filter(scan => scan.valid == true);
return this.scans.filter(scan => scan.valid == true);
}
return []
} }
/** /**

View File

@@ -50,12 +50,6 @@ export abstract class ResponseParticipant implements IResponse {
@IsString() @IsString()
email?: string; email?: string;
/**
* how the participant got into the system
*/
@IsString()
created_via?: string;
/** /**
* The participant's address. * The participant's address.
*/ */
@@ -70,7 +64,6 @@ export abstract class ResponseParticipant implements IResponse {
public constructor(participant: Participant) { public constructor(participant: Participant) {
this.id = participant.id; this.id = participant.id;
this.firstname = participant.firstname; this.firstname = participant.firstname;
this.created_via = participant.created_via;
this.middlename = participant.middlename; this.middlename = participant.middlename;
this.lastname = participant.lastname; this.lastname = participant.lastname;
this.phone = participant.phone; this.phone = participant.phone;

View File

@@ -1,10 +1,7 @@
import { import {
IsInt, IsInt,
IsObject, IsObject
IsOptional,
IsString
} from "class-validator"; } from "class-validator";
import { JwtCreator } from '../../jwtcreator';
import { Runner } from '../entities/Runner'; import { Runner } from '../entities/Runner';
import { ResponseObjectType } from '../enums/ResponseObjectType'; import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse'; import { IResponse } from './IResponse';
@@ -33,26 +30,14 @@ export class ResponseRunner extends ResponseParticipant implements IResponse {
@IsObject() @IsObject()
group: ResponseRunnerGroup; group: ResponseRunnerGroup;
/**
* A selfservice link for our new runner.
*/
@IsOptional()
@IsString()
selfserviceLink: string;
/** /**
* Creates a ResponseRunner object from a runner. * Creates a ResponseRunner object from a runner.
* @param runner The user the response shall be build for. * @param runner The user the response shall be build for.
*/ */
public constructor(runner: Runner, generateSelfServiceLink: boolean = false) { public constructor(runner: Runner) {
super(runner); super(runner);
if (!runner.scans) { this.distance = 0 } if (!runner.scans) { this.distance = 0 }
else { this.distance = runner.validScans.reduce((sum, current) => sum + current.distance, 0); } else { this.distance = runner.validScans.reduce((sum, current) => sum + current.distance, 0); }
if (runner.group) { this.group = runner.group.toResponse(); } if (runner.group) { this.group = runner.group.toResponse(); }
if (generateSelfServiceLink) {
const token = JwtCreator.createSelfService(runner);
this.selfserviceLink = `${process.env.SELFSERVICE_URL}/profile/${token}`;
}
} }
} }

View File

@@ -16,12 +16,6 @@ export class ResponseStats implements IResponse {
*/ */
responseType: ResponseObjectType = ResponseObjectType.STATS; responseType: ResponseObjectType = ResponseObjectType.STATS;
/**
* The amount of runners registered via selfservice.
*/
@IsInt()
runnersViaSelfservice: number;
/** /**
* The amount of runners registered in the system. * The amount of runners registered in the system.
*/ */
@@ -90,16 +84,14 @@ export class ResponseStats implements IResponse {
/** /**
* Creates a new stats response containing some basic statistics for a dashboard or public display. * Creates a new stats response containing some basic statistics for a dashboard or public display.
* @param runnersViaSelfservice number of runners registered via selfservice * @param runners Array containing all runners - the following relations have to be resolved: scans, scans.track
* @param runners number of runners * @param teams Array containing all teams - no relations have to be resolved.
* @param teams number of teams - no relations have to be resolved. * @param orgs Array containing all orgs - no relations have to be resolved.
* @param orgs number of orgs - no relations have to be resolved. * @param users Array containing all users - no relations have to be resolved.
* @param users number of users - no relations have to be resolved. * @param scans Array containing all scans - no relations have to be resolved.
* @param scans number of 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(runnersViaSelfservice: number, runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number, donors: number) { public constructor(runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number, donors: number) {
this.runnersViaSelfservice = runnersViaSelfservice;
this.total_runners = runners; this.total_runners = runners;
this.total_teams = teams; this.total_teams = teams;
this.total_orgs = orgs; this.total_orgs = orgs;

View File

@@ -1,4 +1,4 @@
import { hash } from '@node-rs/argon2'; import * as argon2 from "argon2";
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { Factory, Seeder } from 'typeorm-seeding'; import { Factory, Seeder } from 'typeorm-seeding';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
@@ -33,7 +33,7 @@ export default class SeedUsers implements Seeder {
initialUser.lastname = "demo"; initialUser.lastname = "demo";
initialUser.username = "demo"; initialUser.username = "demo";
initialUser.uuid = uuid.v4(); initialUser.uuid = uuid.v4();
initialUser.password = await hash("demo" + initialUser.uuid); initialUser.password = await argon2.hash("demo" + initialUser.uuid);
initialUser.email = "demo@dev.lauf-fuer-kaya.de" initialUser.email = "demo@dev.lauf-fuer-kaya.de"
initialUser.groups = [group]; initialUser.groups = [group];
return await connection.getRepository(User).save(initialUser); return await connection.getRepository(User).save(initialUser);