Merge pull request 'Releases 0.12.0 and 0.13.0' (#199) from dev into main
continuous-integration/drone/push Build is passing Details

Reviewed-on: #199
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
This commit is contained in:
Philipp Dormann 2023-02-03 13:04:39 +00:00
commit 41c4ed4d0f
Signed by: git.odit.services
GPG Key ID: 76E155504123332E
14 changed files with 397 additions and 208 deletions

View File

@ -29,7 +29,7 @@ get:
---
kind: pipeline
type: kubernetes
name: tests:node_14.15.1-alpine3.12
name: tests:node
clone:
disable: true
steps:
@ -39,7 +39,7 @@ steps:
- git clone $DRONE_REMOTE_URL .
- git checkout $DRONE_SOURCE_BRANCH
- name: run tests
image: node:14.15.1-alpine3.12
image: registry.odit.services/hub/library/node:19.5.0-alpine3.16
commands:
- yarn
- yarn test:ci
@ -61,53 +61,23 @@ steps:
- git clone $DRONE_REMOTE_URL .
- git checkout dev
- name: build dev
image: plugins/docker
depends_on: [clone]
depends_on: ["clone"]
image: registry.odit.services/library/drone-kaniko
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: registry.odit.services/lfk/backend
build_args:
- NPM_REGISTRY_DOMAIN:
from_secret: npmjs_domain
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/backend
tags:
- dev
cache: true
registry: registry.odit.services
mtu: 1000
- name: run changelog export
depends_on: ["clone"]
image: node:latest
commands:
- npx auto-changelog --commit-limit false -p -u --hide-credit
- name: push new changelog to repo
depends_on: ["run changelog export"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: true
commit_message: 🧾New changelog file version [CI SKIP] [skip ci]
author_email: bot@odit.services
remote: git@git.odit.services:lfk/backend.git
ssh_key:
from_secret: git_ssh
- name: run full license export
depends_on: ["clone"]
image: node:14.15.1-alpine3.12
commands:
- yarn
- yarn licenses:export
- name: push new licenses file to repo
depends_on: ["run full license export"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: true
commit_message: 📖New license file version [CI SKIP] [skip ci]
author_email: bot@odit.services
remote: git@git.odit.services:lfk/backend.git
skip_verify: true
ssh_key:
from_secret: git_ssh
trigger:
branch:
@ -132,17 +102,22 @@ steps:
- git checkout main
- name: build latest
depends_on: ["clone"]
image: plugins/docker
image: registry.odit.services/library/drone-kaniko
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: registry.odit.services/lfk/backend
build_args:
- NPM_REGISTRY_DOMAIN:
from_secret: npmjs_domain
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/backend
tags:
- latest
cache: true
registry: registry.odit.services
mtu: 1000
- name: push merge to repo
depends_on: ["clone"]
image: appleboy/drone-git-push
@ -166,18 +141,23 @@ name: build:tags
steps:
- name: build $DRONE_TAG
image: plugins/docker
depends_on: [clone]
depends_on: ["clone"]
image: registry.odit.services/library/drone-kaniko
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: registry.odit.services/lfk/backend
build_args:
- NPM_REGISTRY_DOMAIN:
from_secret: npmjs_domain
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/backend
tags:
- '${DRONE_TAG}'
- "${DRONE_TAG}"
cache: true
registry: registry.odit.services
mtu: 1000
- name: trigger node lib build
image: idcooldi/drone-webhook
settings:
@ -192,4 +172,4 @@ steps:
from_secret: ci_token
trigger:
event:
- tag
- tag

3
.gitignore vendored
View File

@ -135,4 +135,5 @@ build
/docs
lib
/oss-attribution
*.tmp
*.tmp
pnpm-lock.yaml

View File

@ -2,11 +2,56 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.13.1](https://git.odit.services/lfk/backend/compare/v0.13.0...v0.13.1)
- 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)
> 2 February 2023
- 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)
- 🚀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)
- 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)
- 🧾New changelog file version [CI SKIP] [skip ci] [`ae14d6c`](https://git.odit.services/lfk/backend/commit/ae14d6c74f9205440b41ca5fdbd052ca449148fc)
- Added selfservice runner create check to prevent duplicate email [`68cd746`](https://git.odit.services/lfk/backend/commit/68cd746a9f3360b3630a9ba570213d2aa62497b4)
- Updated tests for new login in selfservice [`39aa759`](https://git.odit.services/lfk/backend/commit/39aa7598b7cd0ecb0f077f50ebdd31c6e205f06d)
- 🧾New changelog file version [CI SKIP] [skip ci] [`9fa8b93`](https://git.odit.services/lfk/backend/commit/9fa8b93c08ee52335b18e743f9d205b19e6095c6)
- Moved changelog generation to package script [`a7297ff`](https://git.odit.services/lfk/backend/commit/a7297ff933ae1372a9d508cdae1a54d2ebbcc647)
- Merge pull request 'feature/197-duplicate_runner_mail' (#198) from feature/197-duplicate_runner_mail into dev [`4b676bc`](https://git.odit.services/lfk/backend/commit/4b676bc85336c2d494e9e74823d38deec5cc0400)
- Updated logo url [`4433ddb`](https://git.odit.services/lfk/backend/commit/4433ddb1e15a35481728670e22049200644bf337)
- depends_on: ["clone"] [`9cc66ee`](https://git.odit.services/lfk/backend/commit/9cc66eebdfe8e7a2888bbc97197d1756ff44de30)
- Fixed typo [`19a290c`](https://git.odit.services/lfk/backend/commit/19a290c3a931ead0d9ae9ebb0985bfbaac54df59)
- Rename selfservice forgot to login [`69651d9`](https://git.odit.services/lfk/backend/commit/69651d9f6cd826b6d4720f164897a2a72a57c851)
- 📖New license file version [CI SKIP] [skip ci] [`6fd246f`](https://git.odit.services/lfk/backend/commit/6fd246f43cb3f4d0ccb6e017ee699889ba17daac)
- Add git for changelog fun [`2fa56b8`](https://git.odit.services/lfk/backend/commit/2fa56b82d1e082a1deae943e5fca5101f24e3ef5)
#### [v0.12.0](https://git.odit.services/lfk/backend/compare/v0.11.1...v0.12.0)
> 2 February 2023
- Pinned versions [`a6d5693`](https://git.odit.services/lfk/backend/commit/a6d5693ccdeb25b15a09af8f7438142114268807)
- Drone -&gt; Kaniko based builds [`0e78951`](https://git.odit.services/lfk/backend/commit/0e789513008085d0db94fc3b2dd9e74a5e583049)
- Drone images to odit registry [`6ad56b3`](https://git.odit.services/lfk/backend/commit/6ad56b31269bf19a740c1b6b1a303a8a9d7d59d0)
- Bumped container base images [`d95c6d3`](https://git.odit.services/lfk/backend/commit/d95c6d33657f6aa977a8ebfefad7e199bb1cc9c3)
- Enabled tag via release script [`9217421`](https://git.odit.services/lfk/backend/commit/92174212213f874e41c9472a927bcf87b963ac94)
- Pinned pnpm for builds [`4570845`](https://git.odit.services/lfk/backend/commit/4570845b3e1bd00c228fe1b09b658c24e20aba7f)
- 🚀Bumped version to v0.12.0 [`4c10e20`](https://git.odit.services/lfk/backend/commit/4c10e20b91a8101ee37b230373ceb3e024582b41)
- Ignore pnpm lock [`1f2c8ab`](https://git.odit.services/lfk/backend/commit/1f2c8abb22f3ff1e61b7350b517bd699c3e315f6)
- 🧾New changelog file version [CI SKIP] [skip ci] [`31b258b`](https://git.odit.services/lfk/backend/commit/31b258b4ce82213144160a4233b7fd127e456776)
#### [v0.11.1](https://git.odit.services/lfk/backend/compare/v0.11.0...v0.11.1)
> 22 April 2021
- Merge pull request 'Release 0.11.1' (#196) from dev into main [`f19f280`](https://git.odit.services/lfk/backend/commit/f19f2808d88414f1877c01f10996dac68b6f9617)
- 🧾New changelog file version [CI SKIP] [skip ci] [`2229cdf`](https://git.odit.services/lfk/backend/commit/2229cdf20db1a98f9f76a99fa9d3f463cdf6d804)
- 🧾New changelog file version [CI SKIP] [skip ci] [`348fe52`](https://git.odit.services/lfk/backend/commit/348fe52c42cfa32239b703041820f725e147154e)
- Now prefixing runnercards with 2 [`8a82e05`](https://git.odit.services/lfk/backend/commit/8a82e059b74ceabf43c9cbfe9c9b89ef6ce15a28)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3b9cd2e`](https://git.odit.services/lfk/backend/commit/3b9cd2e1bbbe8e69c3883233a98f286d768c2b79)
- Added fix for the appended 2 [`eb526fb`](https://git.odit.services/lfk/backend/commit/eb526fb57faf631fd6e84af99af738ab1b3481c7)
- 🚀Bumped version to v0.11.1 [`95320ca`](https://git.odit.services/lfk/backend/commit/95320ca1bccc2886553accea6a428aadffda0a27)
- 🧾New changelog file version [CI SKIP] [skip ci] [`f2d127f`](https://git.odit.services/lfk/backend/commit/f2d127fc98d75ce658424624abd382c087737ca0)

View File

@ -1,16 +1,15 @@
# Typescript Build
FROM node:14.15.1-alpine3.12
FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16
WORKDIR /app
COPY package.json ./
RUN npm i -g pnpm
RUN pnpm i
RUN npx pnpm@7.26.3 i
COPY tsconfig.json ormconfig.js ./
COPY src ./src
RUN pnpm run build
RUN npm run build
# final image
FROM node:14.15.1-alpine3.12
FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16
COPY package.json ormconfig.js ./
RUN npm i -g pnpm
RUN pnpm i --prod
RUN npx pnpm@7.26.3 i --prod
COPY --from=0 /app/dist dist
ENTRYPOINT ["node", "dist/app.js"]

View File

@ -51,23 +51,23 @@ yarn docs
> You can provide them via .env file or docker env vars.
> You can use the `test:ci:generate_env` package script to generate a example env (uses bs data as test server and ignores the errors).
| Name | Type | Default | Description
| - | - | - | -
| APP_PORT | Number | 4010 | The port the backend server listens on. Is optional.
| DB_TYPE | String | N/A | The type of the db u want to use. It has to be supported by typeorm. Possible: `sqlite`, `mysql`, `postgresql`
| DB_HOST | String | N/A | The db's host's ip-address/fqdn or file path for sqlite
| DB_PORT | String | N/A | The db's port
| DB_USER | String | N/A | The user for accessing the db
| DB_PASSWORD | String | N/A | The user's password for accessing the db
| DB_NAME | String | N/A | The db's name
| NODE_ENV | String | dev | The apps env - influences debug info. Also when the env is set to "test", mailing errors get ignored.
| POSTALCODE_COUNTRYCODE | String/CountryCode | N/A | The countrycode used to validate address's postal codes
| PHONE_COUNTRYCODE | String/CountryCode | null (international) | The countrycode used to validate phone numers
| 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_KEY | String | N/A | The mailer's api key.
| 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)
| Name | Type | Default | Description |
| ---------------------- | ------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------- |
| APP_PORT | Number | 4010 | The port the backend server listens on. Is optional. |
| DB_TYPE | String | N/A | The type of the db u want to use. It has to be supported by typeorm. Possible: `sqlite`, `mysql`, `postgresql` |
| DB_HOST | String | N/A | The db's host's ip-address/fqdn or file path for sqlite |
| DB_PORT | String | N/A | The db's port |
| DB_USER | String | N/A | The user for accessing the db |
| DB_PASSWORD | String | N/A | The user's password for accessing the db |
| DB_NAME | String | N/A | The db's name |
| NODE_ENV | String | dev | The apps env - influences debug info. Also when the env is set to "test", mailing errors get ignored. |
| POSTALCODE_COUNTRYCODE | String/CountryCode | N/A | The countrycode used to validate address's postal codes |
| PHONE_COUNTRYCODE | String/CountryCode | null (international) | The countrycode used to validate phone numers |
| 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_KEY | String | N/A | The mailer's api key. |
| 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) |
## Recommended Editor
@ -85,8 +85,8 @@ yarn docs
* A new release tag automaticly triggers the release ci pipeline
* main: Protected "release" branch
* The latest tag of the docker image get's build from this
* New releases get created as tags from this
* dev: Current dev branch for merging the different feature branches and bugfixes
* New releases get created as tags from this
* The dev tag of the docker image get's build from this
* Only push minor changes to this branch!
* To merge a feature branch into this please create a pull request

View File

@ -444,6 +444,25 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**License**: MIT
**Description**: A node.js driver for mysql. It is written in JavaScript, does not require compiling, and is 100% MIT licensed.
## License Text
Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
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.
# pg
@ -454,7 +473,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## License Text
MIT License
Copyright (c) 2010 - 2021 Brian Carlson
Copyright (c) 2010 - 2020 Brian Carlson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -696,6 +715,75 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# @faker-js/faker
**Author**: undefined
**Repo**: [object Object]
**License**: MIT
**Description**: Generate massive amounts of fake contextual data
## License Text
Faker - Copyright (c) 2022
This software consists of voluntary contributions made by many individuals.
For exact contribution history, see the revision history
available at https://github.com/faker-js/faker
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.
===
From: https://github.com/faker-js/faker/commit/a9f98046c7d5eeaabe12fc587024c06d683800b8
To: https://github.com/faker-js/faker/commit/29234378807c4141588861f69421bf20b5ac635e
Based on faker.js, copyright Marak Squires and contributor, what follows below is the original license.
===
faker.js - Copyright (c) 2020
Marak Squires
http://github.com/marak/faker.js/
faker.js was inspired by and has used data definitions from:
* https://github.com/stympy/faker/ - Copyright (c) 2007-2010 Benjamin Curtis
* http://search.cpan.org/~jasonk/Data-Faker-0.07/ - Copyright 2004-2005 by Jason Kohles
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/license-exporter
**Author**: ODIT.Services
**Repo**: [object Object]
@ -926,6 +1014,35 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE
# auto-changelog
**Author**: Pete Cook <pete@cookpete.com> (https://github.com/cookpete)
**Repo**: [object Object]
**License**: MIT
**Description**: Command line tool for generating a changelog from git tags and commit history
## License Text
The MIT License
Copyright (c) 2017 Pete Cook https://cookpete.com
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.
# cp-cli
**Author**: undefined
**Repo**: [object Object]

View File

@ -1,106 +1,114 @@
{
"name": "@odit/lfk-backend",
"version": "0.11.1",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"author": {
"name": "ODIT.Services",
"email": "info@odit.services",
"url": "https://odit.services"
},
"contributors": [
{
"name": "Philipp Dormann",
"email": "philipp@philippdormann.de",
"url": "https://philippdormann.de"
},
{
"name": "Nicolai Ort",
"email": "info@nicolai-ort.com",
"url": "https://nicolai-ort.com"
}
],
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"@odit/class-validator-jsonschema": "2.1.1",
"argon2": "^0.27.1",
"axios": "^0.21.1",
"body-parser": "^1.19.0",
"check-password-strength": "^2.0.2",
"class-transformer": "0.3.1",
"class-validator": "^0.13.1",
"consola": "^2.15.0",
"cookie": "^0.4.1",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"csvtojson": "^2.0.10",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"libphonenumber-js": "^1.9.9",
"mysql": "^2.18.1",
"pg": "^8.5.1",
"reflect-metadata": "^0.1.13",
"routing-controllers": "0.9.0-alpha.6",
"routing-controllers-openapi": "^2.2.0",
"sqlite3": "5.0.0",
"typeorm": "^0.2.30",
"typeorm-routing-controllers-extensions": "^0.2.0",
"typeorm-seeding": "^1.6.1",
"uuid": "^8.3.2",
"validator": "^13.5.2"
},
"devDependencies": {
"@odit/license-exporter": "^0.0.9",
"@types/cors": "^2.8.9",
"@types/csvtojson": "^1.1.5",
"@types/express": "^4.17.11",
"@types/jest": "^26.0.20",
"@types/jsonwebtoken": "^8.5.0",
"@types/node": "^14.14.22",
"@types/uuid": "^8.3.0",
"cp-cli": "^2.0.0",
"jest": "^26.6.3",
"nodemon": "^2.0.7",
"release-it": "^14.2.2",
"rimraf": "^3.0.2",
"start-server-and-test": "^1.11.7",
"ts-jest": "^26.5.0",
"ts-node": "^9.1.1",
"typedoc": "^0.20.19",
"typescript": "^4.1.3"
},
"scripts": {
"dev": "nodemon src/app.ts",
"build": "rimraf ./dist && tsc && cp-cli ./src/static ./dist/static",
"docs": "typedoc --out docs src",
"test": "jest",
"test:watch": "jest --watchAll",
"test:ci:generate_env": "ts-node scripts/create_testenv.ts",
"test:ci:run": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test",
"test:ci": "npm run test:ci:generate_env && npm run test:ci:run",
"seed": "ts-node ./node_modules/typeorm/cli.js schema:sync && ts-node ./node_modules/typeorm-seeding/dist/cli.js seed",
"openapi:export": "ts-node scripts/openapi_export.ts",
"licenses:export": "license-exporter --markdown",
"release": "release-it --only-version"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀Bumped version to v${version}",
"requireBranch": "dev",
"push": false,
"tag": false
},
"npm": {
"publish": false
}
},
"nodemonConfig": {
"ignore": [
"src/tests/*",
"docs/*"
]
}
}
{
"name": "@odit/lfk-backend",
"version": "0.13.1",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"author": {
"name": "ODIT.Services",
"email": "info@odit.services",
"url": "https://odit.services"
},
"contributors": [
{
"name": "Philipp Dormann",
"email": "philipp@philippdormann.de",
"url": "https://philippdormann.de"
},
{
"name": "Nicolai Ort",
"email": "info@nicolai-ort.com",
"url": "https://nicolai-ort.com"
}
],
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"@odit/class-validator-jsonschema": "2.1.1",
"argon2": "0.27.1",
"axios": "0.21.1",
"body-parser": "1.19.0",
"check-password-strength": "2.0.2",
"class-transformer": "0.3.1",
"class-validator": "0.13.1",
"consola": "2.15.0",
"cookie": "0.4.1",
"cookie-parser": "1.4.5",
"cors": "2.8.5",
"csvtojson": "2.0.10",
"dotenv": "8.2.0",
"express": "4.17.1",
"jsonwebtoken": "8.5.1",
"libphonenumber-js": "1.9.9",
"mysql": "2.18.1",
"pg": "8.5.1",
"reflect-metadata": "0.1.13",
"routing-controllers": "0.9.0-alpha.6",
"routing-controllers-openapi": "2.2.0",
"sqlite3": "5.0.0",
"typeorm": "0.2.30",
"typeorm-routing-controllers-extensions": "0.2.0",
"typeorm-seeding": "1.6.1",
"uuid": "8.3.2",
"validator": "13.5.2"
},
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"@odit/license-exporter": "0.0.9",
"@types/cors": "2.8.9",
"@types/csvtojson": "1.1.5",
"@types/express": "4.17.11",
"@types/jest": "26.0.20",
"@types/jsonwebtoken": "8.5.0",
"@types/node": "14.14.22",
"@types/uuid": "8.3.0",
"auto-changelog": "^2.4.0",
"cp-cli": "2.0.0",
"jest": "26.6.3",
"nodemon": "2.0.7",
"release-it": "14.2.2",
"rimraf": "3.0.2",
"start-server-and-test": "1.11.7",
"ts-jest": "26.5.0",
"ts-node": "9.1.1",
"typedoc": "0.20.19",
"typescript": "4.1.3"
},
"scripts": {
"dev": "nodemon src/app.ts",
"build": "rimraf ./dist && tsc && cp-cli ./src/static ./dist/static",
"docs": "typedoc --out docs src",
"test": "jest",
"test:watch": "jest --watchAll",
"test:ci:generate_env": "ts-node scripts/create_testenv.ts",
"test:ci:run": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test",
"test:ci": "npm run test:ci:generate_env && npm run test:ci:run",
"seed": "ts-node ./node_modules/typeorm/cli.js schema:sync && ts-node ./node_modules/typeorm-seeding/dist/cli.js seed",
"openapi:export": "ts-node scripts/openapi_export.ts",
"licenses:export": "license-exporter --markdown",
"changelog:export": "auto-changelog --commit-limit false -p -u --hide-credit",
"release": "release-it --only-version"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀Bumped version to v${version}",
"requireBranch": "dev",
"push": true,
"tag": true,
"tagName": "v${version}",
"tagAnnotation": "v${version}"
},
"npm": {
"publish": false
},
"hooks": {
"after:bump": "npm run changelog:export && npm run licenses:export && git add CHANGELOG.md && git add licenses.md"
}
},
"nodemonConfig": {
"ignore": [
"src/tests/*",
"docs/*"
]
}
}

View File

@ -1,6 +1,6 @@
import { Request } from "express";
import * as jwt from "jsonwebtoken";
import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam, Req, UseBefore } from 'routing-controllers';
import { BadRequestError, Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam, Req, UseBefore } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { config } from '../config';
@ -116,10 +116,10 @@ export class RunnerSelfServiceController {
return scan.toResponse();
}
@Post('/runners/forgot')
@Post('/runners/login')
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
@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 24hrs).' })
async requestNewToken(@QueryParam('mail') mail: string, @QueryParam("locale") locale: string = "en") {
if (!mail) {
throw new RunnerNotFoundError();
@ -148,8 +148,11 @@ export class RunnerSelfServiceController {
@OpenAPI({ description: 'Create a new selfservice runner in the citizen org. <br> This endpoint shoud be used to allow "everyday citizen" to register themselves. <br> You have to provide a mail address, b/c the future we\'ll implement email verification.' })
async registerRunner(@Body({ validate: true }) createRunner: CreateSelfServiceCitizenRunner, @QueryParam("locale") locale: string = "en") {
let runner = await createRunner.toEntity();
if (await this.getRunnerExistsByMail(runner.email)) {
throw new BadRequestError("E-Mail already registered")
}
runner = await this.runnerRepository.save(runner);
let response = new ResponseSelfServiceRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] }));
response.token = JwtCreator.createSelfService(runner);
@ -170,6 +173,9 @@ export class RunnerSelfServiceController {
const org = await this.getOrgansisation(token);
let runner = await createRunner.toEntity(org);
if (await this.getRunnerExistsByMail(runner.email)) {
throw new BadRequestError("E-Mail already registered")
}
runner = await this.runnerRepository.save(runner);
let response = new ResponseSelfServiceRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] }));
@ -225,4 +231,14 @@ export class RunnerSelfServiceController {
return organization;
}
/**
* Checks if a runner already exists
* @param email The runner's email address
* @returns Boolean (true if exists, false if not)
*/
private async getRunnerExistsByMail(email: string): Promise<boolean> {
const runner = await this.runnerRepository.findOne({ email });
return runner != undefined
}
}

View File

@ -114,7 +114,7 @@ export class CreateUser {
newUser.groups = await this.getGroups();
newUser.enabled = this.enabled;
if (!this.profilePic) { newUser.profilePic = `https://dev.lauf-fuer-kaya.de/lfk-logo.png`; }
if (!this.profilePic) { newUser.profilePic = `https://lauf-fuer-kaya.de/lfk-logo.png`; }
else { newUser.profilePic = this.profilePic; }
return newUser;

View File

@ -124,7 +124,7 @@ export class UpdateUser {
user.phone = this.phone;
user.groups = await this.getGroups();
if (!this.profilePic) { user.profilePic = `https://dev.lauf-fuer-kaya.de/lfk-logo.png`; }
if (!this.profilePic) { user.profilePic = `https://lauf-fuer-kaya.de/lfk-logo.png`; }
else { user.profilePic = this.profilePic; }
return user;

View File

@ -1,5 +1,7 @@
import { faker } from '@faker-js/faker';
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
let access_token;
@ -21,7 +23,7 @@ describe('delete selfservice runner invalid', () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"lastname": "string",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
added_runner = res.data;
expect(res.status).toEqual(200);
@ -50,7 +52,7 @@ describe('delete selfservice runner valid', () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"lastname": "string",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
added_runner = res.data;
expect(res.status).toEqual(200);

View File

@ -15,20 +15,20 @@ beforeAll(async () => {
};
});
describe('POST /api/runners/me/forgot invalid syntax/mail should fail', () => {
describe('POST /api/runners/me/login invalid syntax/mail should fail', () => {
it('get without mail return 404', async () => {
const res = await axios.post(base + '/api/runners/forgot', null, axios_config);
const res = await axios.post(base + '/api/runners/login', null, axios_config);
expect(res.status).toEqual(404);
expect(res.headers['content-type']).toContain("application/json");
});
it('get without bs mail return 404', async () => {
const res = await axios.post(base + '/api/runners/forgot?mail=asdasdasdasdasd@tester.test.dev.lauf-fuer-kaya.de', null, axios_config);
const res = await axios.post(base + '/api/runners/login?mail=asdasdasdasdasd@tester.test.dev.lauf-fuer-kaya.de', null, axios_config);
expect(res.status).toEqual(404);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('POST /api/runners/me/forgot 2 times within timeout should fail', () => {
describe('POST /api/runners/me/login 2 times within timeout should fail', () => {
let added_runner;
it('registering as citizen should return 200', async () => {
const res = await axios.post(base + '/api/runners/register', {
@ -42,19 +42,19 @@ describe('POST /api/runners/me/forgot 2 times within timeout should fail', () =>
added_runner = res.data;
});
it('post with valid mail should return 200', async () => {
const res = await axios.post(base + '/api/runners/forgot?mail=' + added_runner.email, null, axios_config);
const res = await axios.post(base + '/api/runners/login?mail=' + added_runner.email, null, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('2nd post with valid mail should return 406', async () => {
const res = await axios.post(base + '/api/runners/forgot?mail=' + added_runner.email, null, axios_config);
const res = await axios.post(base + '/api/runners/login?mail=' + added_runner.email, null, axios_config);
expect(res.status).toEqual(406);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('POST /api/runners/me/forgot valid should return 200', () => {
describe('POST /api/runners/me/login valid should return 200', () => {
let added_runner;
let new_token;
it('registering as citizen should return 200', async () => {
@ -69,7 +69,7 @@ describe('POST /api/runners/me/forgot valid should return 200', () => {
added_runner = res.data;
});
it('post with valid mail should return 200', async () => {
const res = await axios.post(base + '/api/runners/forgot?mail=' + added_runner.email, null, axios_config);
const res = await axios.post(base + '/api/runners/login?mail=' + added_runner.email, null, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
new_token = res.data.token;

View File

@ -1,3 +1,4 @@
import { faker } from '@faker-js/faker';
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
@ -30,7 +31,7 @@ describe('register + get should return 200', () => {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");

View File

@ -1,3 +1,4 @@
import { faker } from '@faker-js/faker';
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
@ -39,7 +40,7 @@ describe('register invalid citizen', () => {
const res = await axios.post(base + '/api/runners/register', {
"middlename": "string",
"lastname": "string",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
@ -48,7 +49,7 @@ describe('register invalid citizen', () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
@ -59,7 +60,26 @@ describe('register invalid citizen', () => {
"middlename": "string",
"lastname": "string",
"phone": "peter",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering as citizen with duplicate mail should return 400', async () => {
const mail = faker.internet.exampleEmail();
await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"phone": "peter",
"email": mail,
}, axios_config);
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"phone": "peter",
"email": mail,
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
@ -71,7 +91,7 @@ describe('register citizen valid', () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"lastname": "string",
"email": "user@example.com"
"email": faker.internet.exampleEmail(),
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
@ -81,7 +101,7 @@ describe('register citizen valid', () => {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"email": faker.internet.exampleEmail(),
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
@ -187,7 +207,7 @@ describe('register valid company', () => {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"email": faker.internet.exampleEmail(),
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
@ -214,7 +234,7 @@ describe('register valid company', () => {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"email": faker.internet.exampleEmail(),
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
@ -232,7 +252,7 @@ describe('register valid company', () => {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"email": faker.internet.exampleEmail(),
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",