diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea6d19a..7a849b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,22 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
+#### [v0.10.0](https://git.odit.services/lfk/backend/compare/v0.9.2...v0.10.0)
+
+- 🚀Bumped version to v0.10.0 [`dc3071f`](https://git.odit.services/lfk/backend/commit/dc3071f7d2be298f0bb02d86ec67ed1125cd3b49)
+- 🧾New changelog file version [CI SKIP] [skip ci] [`5fb355f`](https://git.odit.services/lfk/backend/commit/5fb355f450f19e96d3671b1a46e94d564495942b)
+- Merge pull request 'Mail locales feature/184-mail_locales' (#185) from feature/184-mail_locales into dev [`33c13de`](https://git.odit.services/lfk/backend/commit/33c13de32c68a3d9e87e4fd9ad12a815ed8c9fde)
+- Added locale to mail related runner endpoints [`7af883f`](https://git.odit.services/lfk/backend/commit/7af883f27198206af542bcaff4686221d3788e87)
+- Added locale to mail related runner endpoints [`f543307`](https://git.odit.services/lfk/backend/commit/f5433076b01c743ed9af085fccadb8f1edc26419)
+- Added locale to mail related user endpoints [`1be073a`](https://git.odit.services/lfk/backend/commit/1be073a4fa39f0332a46f567ee6af10a9137844c)
+- 🧾New changelog file version [CI SKIP] [skip ci] [`6aafe4a`](https://git.odit.services/lfk/backend/commit/6aafe4a6ae7d253ab39220e551c52ae067cc481a)
+
#### [v0.9.2](https://git.odit.services/lfk/backend/compare/v0.9.1...v0.9.2)
+> 29 March 2021
+
+- Merge pull request 'Release 0.9.2' (#183) from dev into main [`bdeeb03`](https://git.odit.services/lfk/backend/commit/bdeeb036459c2a2131e843d8a5a6b338e0ba46ea)
+- 🧾New changelog file version [CI SKIP] [skip ci] [`675c876`](https://git.odit.services/lfk/backend/commit/675c8762e8e4cf28d2f334d5ab2e1cb6b594e33c)
- Fixed bug in return creation [`6c9b91d`](https://git.odit.services/lfk/backend/commit/6c9b91d75a0d08fc4ab0e72c7a09bd0133566368)
- 🧾New changelog file version [CI SKIP] [skip ci] [`8c00aef`](https://git.odit.services/lfk/backend/commit/8c00aefd6ce3723d9f83d1c94e6491d5d597391f)
- 🚀Bumped version to v0.9.2 [`89e3924`](https://git.odit.services/lfk/backend/commit/89e392473c52a3f328545699a0f4df89be33ba89)
diff --git a/package.json b/package.json
index 754a604..a3a6521 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@odit/lfk-backend",
- "version": "0.9.2",
+ "version": "0.10.0",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"author": {
diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts
index eebbd79..be55ee7 100644
--- a/src/controllers/AuthController.ts
+++ b/src/controllers/AuthController.ts
@@ -87,7 +87,7 @@ export class AuthController {
@ResponseSchema(UserNotFoundError, { statusCode: 404 })
@ResponseSchema(UsernameOrEmailNeededError, { statusCode: 406 })
@ResponseSchema(MailSendingError, { statusCode: 500 })
- @OpenAPI({ description: "Request a password reset token.
This will provide you with a reset token that you can use by posting to /api/auth/reset/{token}." })
+ @OpenAPI({ description: "Request a password reset token.
This will provide you with a reset token that you can use by posting to /api/auth/reset/{token}.", parameters: [{ in: "query", name: "locale", schema: { type: "string", enum: ["de", "en"] } }] })
async getResetToken(@Body({ validate: true }) passwordReset: CreateResetToken, @QueryParam("locale") locale: string = "en") {
const reset_token: string = await passwordReset.toResetToken();
await Mailer.sendResetMail(passwordReset.email, reset_token, locale);
diff --git a/src/controllers/RunnerSelfServiceController.ts b/src/controllers/RunnerSelfServiceController.ts
index 8f5509e..afa9379 100644
--- a/src/controllers/RunnerSelfServiceController.ts
+++ b/src/controllers/RunnerSelfServiceController.ts
@@ -1,228 +1,228 @@
-import { Request } from "express";
-import * as jwt from "jsonwebtoken";
-import { 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';
-import { InvalidCredentialsError, JwtNotProvidedError } from '../errors/AuthError';
-import { MailSendingError } from '../errors/MailErrors';
-import { RunnerEmailNeededError, RunnerHasDistanceDonationsError, RunnerNotFoundError, RunnerSelfserviceTimeoutError } from '../errors/RunnerErrors';
-import { RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
-import { ScanStationNotFoundError } from '../errors/ScanStationErrors';
-import { JwtCreator } from '../jwtcreator';
-import { Mailer } from '../mailer';
-import ScanAuth from '../middlewares/ScanAuth';
-import { CreateSelfServiceCitizenRunner } from '../models/actions/create/CreateSelfServiceCitizenRunner';
-import { CreateSelfServiceRunner } from '../models/actions/create/CreateSelfServiceRunner';
-import { Runner } from '../models/entities/Runner';
-import { RunnerGroup } from '../models/entities/RunnerGroup';
-import { RunnerOrganization } from '../models/entities/RunnerOrganization';
-import { ScanStation } from '../models/entities/ScanStation';
-import { ResponseEmpty } from '../models/responses/ResponseEmpty';
-import { ResponseScanStation } from '../models/responses/ResponseScanStation';
-import { ResponseSelfServiceOrganisation } from '../models/responses/ResponseSelfServiceOrganisation';
-import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner';
-import { ResponseSelfServiceScan } from '../models/responses/ResponseSelfServiceScan';
-import { DonationController } from './DonationController';
-import { RunnerCardController } from './RunnerCardController';
-import { ScanController } from './ScanController';
-
-@JsonController()
-export class RunnerSelfServiceController {
- private runnerRepository: Repository;
- private orgRepository: Repository;
- private stationRepository: Repository;
-
- /**
- * Gets the repository of this controller's model/entity.
- */
- constructor() {
- this.runnerRepository = getConnectionManager().get().getRepository(Runner);
- this.orgRepository = getConnectionManager().get().getRepository(RunnerOrganization);
- this.stationRepository = getConnectionManager().get().getRepository(ScanStation);
- }
-
- @Get('/runners/me/:jwt')
- @ResponseSchema(ResponseSelfServiceRunner)
- @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
- @OnUndefined(RunnerNotFoundError)
- @OpenAPI({ description: 'Lists all information about yourself.
Please provide your runner jwt(that code we gave you during registration) for auth.
If you lost your jwt/personalized link please use the forgot endpoint.' })
- async get(@Param('jwt') token: string) {
- return (new ResponseSelfServiceRunner(await this.getRunner(token)));
- }
-
- @Delete('/runners/me/:jwt')
- @ResponseSchema(ResponseSelfServiceRunner)
- @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
- @OnUndefined(RunnerNotFoundError)
- @OpenAPI({ description: 'Deletes all information about yourself.
Please provide your runner jwt(that code we gave you during registration) for auth.
If you lost your jwt/personalized link please use the forgot endpoint.' })
- async remove(@Param('jwt') token: string, @QueryParam("force") force: boolean) {
- const responseRunner = await this.getRunner(token);
- let runner = await this.runnerRepository.findOne({ id: responseRunner.id });
-
- if (!runner) { return null; }
- if (!runner) {
- throw new RunnerNotFoundError();
- }
-
- const runnerDonations = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["distanceDonations"] })).distanceDonations;
- if (runnerDonations.length > 0 && !force) {
- throw new RunnerHasDistanceDonationsError();
- }
- const donationController = new DonationController();
- for (let donation of runnerDonations) {
- await donationController.remove(donation.id, force);
- }
-
- const runnerCards = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["cards"] })).cards;
- const cardController = new RunnerCardController;
- for (let card of runnerCards) {
- await cardController.remove(card.id, force);
- }
-
- const runnerScans = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["scans"] })).scans;
- const scanController = new ScanController;
- for (let scan of runnerScans) {
- await scanController.remove(scan.id, force);
- }
-
- await this.runnerRepository.delete(runner);
- return new ResponseSelfServiceRunner(responseRunner);
- }
-
- @Get('/runners/me/:jwt/scans')
- @ResponseSchema(ResponseSelfServiceScan, { isArray: true })
- @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
- @OnUndefined(RunnerNotFoundError)
- @OpenAPI({ description: 'Lists all your (runner) scans.
Please provide your runner jwt(that code we gave you during registration) for auth.
If you lost your jwt/personalized link please contact support.' })
- async getScans(@Param('jwt') token: string) {
- const scans = (await this.getRunner(token)).scans;
- let responseScans = new Array()
- for (let scan of scans) {
- responseScans.push(new ResponseSelfServiceScan(scan));
- }
- return responseScans;
- }
-
- @Get('/stations/me')
- @UseBefore(ScanAuth)
- @ResponseSchema(ResponseScanStation)
- @ResponseSchema(ScanStationNotFoundError, { statusCode: 404 })
- @OnUndefined(ScanStationNotFoundError)
- @OpenAPI({ description: 'Lists basic information about the station whose token got provided.
This includes it\'s associated track.', security: [{ "StationApiToken": [] }] })
- async getStationMe(@Req() req: Request) {
- let scan = await this.stationRepository.findOne({ id: parseInt(req.headers["station_id"].toString()) }, { relations: ['track'] })
- if (!scan) { throw new ScanStationNotFoundError(); }
- return scan.toResponse();
- }
-
- @Post('/runners/forgot')
- @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).' })
- async requestNewToken(@QueryParam('mail') mail: string) {
- if (!mail) {
- throw new RunnerNotFoundError();
- }
- const runner = await this.runnerRepository.findOne({ email: mail });
- if (!runner) { throw new RunnerNotFoundError(); }
-
- if (runner.resetRequestedTimestamp > (Math.floor(Date.now() / 1000) - 60 * 60 * 24)) { throw new RunnerSelfserviceTimeoutError(); }
- const token = JwtCreator.createSelfService(runner);
-
- try {
- await Mailer.sendSelfserviceForgottenMail(runner.email, token, "en")
- } catch (error) {
- throw new MailSendingError();
- }
-
- runner.resetRequestedTimestamp = Math.floor(Date.now() / 1000);
- await this.runnerRepository.save(runner);
-
- return { token };
- }
-
- @Post('/runners/register')
- @ResponseSchema(ResponseSelfServiceRunner)
- @ResponseSchema(RunnerEmailNeededError, { statusCode: 406 })
- @OpenAPI({ description: 'Create a new selfservice runner in the citizen org.
This endpoint shoud be used to allow "everyday citizen" to register themselves.
You have to provide a mail address, b/c the future we\'ll implement email verification.' })
- async registerRunner(@Body({ validate: true }) createRunner: CreateSelfServiceCitizenRunner) {
- let runner = await createRunner.toEntity();
-
- 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);
-
- try {
- await Mailer.sendSelfserviceWelcomeMail(runner.email, response.token, "en")
- } catch (error) {
- throw new MailSendingError();
- }
-
- return response;
- }
-
- @Post('/runners/register/:token')
- @ResponseSchema(ResponseSelfServiceRunner)
- @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
- @OpenAPI({ description: 'Create a new selfservice runner in a provided org.
The orgs get provided and authorized via api tokens that can be optained via the /organizations endpoint.' })
- async registerOrganizationRunner(@Param('token') token: string, @Body({ validate: true }) createRunner: CreateSelfServiceRunner) {
- const org = await this.getOrgansisation(token);
-
- let runner = await createRunner.toEntity(org);
- 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);
-
- try {
- await Mailer.sendSelfserviceWelcomeMail(runner.email, response.token, "en")
- } catch (error) {
- throw new MailSendingError();
- }
-
- return response;
- }
-
- @Get('/organizations/selfservice/:token')
- @ResponseSchema(ResponseSelfServiceOrganisation, { isArray: false })
- @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
- @OpenAPI({ description: 'Get the basic info and teams for a org.' })
- async getSelfserviceOrg(@Param('token') token: string) {
- const orgid = (await this.getOrgansisation(token)).id;
- const org = await this.orgRepository.findOne({ id: orgid }, { relations: ['teams'] })
-
- return new ResponseSelfServiceOrganisation(org);
- }
-
- /**
- * Get's a runner by a provided jwt token.
- * @param token The runner jwt provided by the runner to identitfy themselves.
- */
- private async getRunner(token: string): Promise {
- if (token == "") { throw new JwtNotProvidedError(); }
- let jwtPayload = undefined
- try {
- jwtPayload = jwt.verify(token, config.jwt_secret);
- } catch (error) {
- throw new InvalidCredentialsError();
- }
-
- const runner = await this.runnerRepository.findOne({ id: jwtPayload["id"] }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] });
- if (!runner) { throw new RunnerNotFoundError() }
- return runner;
- }
-
- /**
- * Get's a runner org by a provided registration api key.
- * @param token The organization's registration api token.
- */
- private async getOrgansisation(token: string): Promise {
- token = Buffer.from(token, 'base64').toString('utf8');
-
- const organization = await this.orgRepository.findOne({ key: token });
- if (!organization) { throw new RunnerOrganizationNotFoundError; }
-
- return organization;
- }
+import { Request } from "express";
+import * as jwt from "jsonwebtoken";
+import { 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';
+import { InvalidCredentialsError, JwtNotProvidedError } from '../errors/AuthError';
+import { MailSendingError } from '../errors/MailErrors';
+import { RunnerEmailNeededError, RunnerHasDistanceDonationsError, RunnerNotFoundError, RunnerSelfserviceTimeoutError } from '../errors/RunnerErrors';
+import { RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
+import { ScanStationNotFoundError } from '../errors/ScanStationErrors';
+import { JwtCreator } from '../jwtcreator';
+import { Mailer } from '../mailer';
+import ScanAuth from '../middlewares/ScanAuth';
+import { CreateSelfServiceCitizenRunner } from '../models/actions/create/CreateSelfServiceCitizenRunner';
+import { CreateSelfServiceRunner } from '../models/actions/create/CreateSelfServiceRunner';
+import { Runner } from '../models/entities/Runner';
+import { RunnerGroup } from '../models/entities/RunnerGroup';
+import { RunnerOrganization } from '../models/entities/RunnerOrganization';
+import { ScanStation } from '../models/entities/ScanStation';
+import { ResponseEmpty } from '../models/responses/ResponseEmpty';
+import { ResponseScanStation } from '../models/responses/ResponseScanStation';
+import { ResponseSelfServiceOrganisation } from '../models/responses/ResponseSelfServiceOrganisation';
+import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner';
+import { ResponseSelfServiceScan } from '../models/responses/ResponseSelfServiceScan';
+import { DonationController } from './DonationController';
+import { RunnerCardController } from './RunnerCardController';
+import { ScanController } from './ScanController';
+
+@JsonController()
+export class RunnerSelfServiceController {
+ private runnerRepository: Repository;
+ private orgRepository: Repository;
+ private stationRepository: Repository;
+
+ /**
+ * Gets the repository of this controller's model/entity.
+ */
+ constructor() {
+ this.runnerRepository = getConnectionManager().get().getRepository(Runner);
+ this.orgRepository = getConnectionManager().get().getRepository(RunnerOrganization);
+ this.stationRepository = getConnectionManager().get().getRepository(ScanStation);
+ }
+
+ @Get('/runners/me/:jwt')
+ @ResponseSchema(ResponseSelfServiceRunner)
+ @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
+ @OnUndefined(RunnerNotFoundError)
+ @OpenAPI({ description: 'Lists all information about yourself.
Please provide your runner jwt(that code we gave you during registration) for auth.
If you lost your jwt/personalized link please use the forgot endpoint.' })
+ async get(@Param('jwt') token: string) {
+ return (new ResponseSelfServiceRunner(await this.getRunner(token)));
+ }
+
+ @Delete('/runners/me/:jwt')
+ @ResponseSchema(ResponseSelfServiceRunner)
+ @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
+ @OnUndefined(RunnerNotFoundError)
+ @OpenAPI({ description: 'Deletes all information about yourself.
Please provide your runner jwt(that code we gave you during registration) for auth.
If you lost your jwt/personalized link please use the forgot endpoint.' })
+ async remove(@Param('jwt') token: string, @QueryParam("force") force: boolean) {
+ const responseRunner = await this.getRunner(token);
+ let runner = await this.runnerRepository.findOne({ id: responseRunner.id });
+
+ if (!runner) { return null; }
+ if (!runner) {
+ throw new RunnerNotFoundError();
+ }
+
+ const runnerDonations = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["distanceDonations"] })).distanceDonations;
+ if (runnerDonations.length > 0 && !force) {
+ throw new RunnerHasDistanceDonationsError();
+ }
+ const donationController = new DonationController();
+ for (let donation of runnerDonations) {
+ await donationController.remove(donation.id, force);
+ }
+
+ const runnerCards = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["cards"] })).cards;
+ const cardController = new RunnerCardController;
+ for (let card of runnerCards) {
+ await cardController.remove(card.id, force);
+ }
+
+ const runnerScans = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["scans"] })).scans;
+ const scanController = new ScanController;
+ for (let scan of runnerScans) {
+ await scanController.remove(scan.id, force);
+ }
+
+ await this.runnerRepository.delete(runner);
+ return new ResponseSelfServiceRunner(responseRunner);
+ }
+
+ @Get('/runners/me/:jwt/scans')
+ @ResponseSchema(ResponseSelfServiceScan, { isArray: true })
+ @ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
+ @OnUndefined(RunnerNotFoundError)
+ @OpenAPI({ description: 'Lists all your (runner) scans.
Please provide your runner jwt(that code we gave you during registration) for auth.
If you lost your jwt/personalized link please contact support.' })
+ async getScans(@Param('jwt') token: string) {
+ const scans = (await this.getRunner(token)).scans;
+ let responseScans = new Array()
+ for (let scan of scans) {
+ responseScans.push(new ResponseSelfServiceScan(scan));
+ }
+ return responseScans;
+ }
+
+ @Get('/stations/me')
+ @UseBefore(ScanAuth)
+ @ResponseSchema(ResponseScanStation)
+ @ResponseSchema(ScanStationNotFoundError, { statusCode: 404 })
+ @OnUndefined(ScanStationNotFoundError)
+ @OpenAPI({ description: 'Lists basic information about the station whose token got provided.
This includes it\'s associated track.', security: [{ "StationApiToken": [] }] })
+ async getStationMe(@Req() req: Request) {
+ let scan = await this.stationRepository.findOne({ id: parseInt(req.headers["station_id"].toString()) }, { relations: ['track'] })
+ if (!scan) { throw new ScanStationNotFoundError(); }
+ return scan.toResponse();
+ }
+
+ @Post('/runners/forgot')
+ @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).', parameters: [{ in: "query", name: "locale", schema: { type: "string", enum: ["de", "en"] } }] })
+ async requestNewToken(@QueryParam('mail') mail: string, @QueryParam("locale") locale: string = "en") {
+ if (!mail) {
+ throw new RunnerNotFoundError();
+ }
+ const runner = await this.runnerRepository.findOne({ email: mail });
+ if (!runner) { throw new RunnerNotFoundError(); }
+
+ if (runner.resetRequestedTimestamp > (Math.floor(Date.now() / 1000) - 60 * 60 * 24)) { throw new RunnerSelfserviceTimeoutError(); }
+ const token = JwtCreator.createSelfService(runner);
+
+ try {
+ await Mailer.sendSelfserviceForgottenMail(runner.email, token, locale)
+ } catch (error) {
+ throw new MailSendingError();
+ }
+
+ runner.resetRequestedTimestamp = Math.floor(Date.now() / 1000);
+ await this.runnerRepository.save(runner);
+
+ return { token };
+ }
+
+ @Post('/runners/register')
+ @ResponseSchema(ResponseSelfServiceRunner)
+ @ResponseSchema(RunnerEmailNeededError, { statusCode: 406 })
+ @OpenAPI({ description: 'Create a new selfservice runner in the citizen org.
This endpoint shoud be used to allow "everyday citizen" to register themselves.
You have to provide a mail address, b/c the future we\'ll implement email verification.', parameters: [{ in: "query", name: "locale", schema: { type: "string", enum: ["de", "en"] } }] })
+ async registerRunner(@Body({ validate: true }) createRunner: CreateSelfServiceCitizenRunner, @QueryParam("locale") locale: string = "en") {
+ let runner = await createRunner.toEntity();
+
+ 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);
+
+ try {
+ await Mailer.sendSelfserviceWelcomeMail(runner.email, response.token, locale)
+ } catch (error) {
+ throw new MailSendingError();
+ }
+
+ return response;
+ }
+
+ @Post('/runners/register/:token')
+ @ResponseSchema(ResponseSelfServiceRunner)
+ @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
+ @OpenAPI({ description: 'Create a new selfservice runner in a provided org.
The orgs get provided and authorized via api tokens that can be optained via the /organizations endpoint.', parameters: [{ in: "query", name: "locale", schema: { type: "string", enum: ["de", "en"] } }] })
+ async registerOrganizationRunner(@Param('token') token: string, @Body({ validate: true }) createRunner: CreateSelfServiceRunner, @QueryParam("locale") locale: string = "en") {
+ const org = await this.getOrgansisation(token);
+
+ let runner = await createRunner.toEntity(org);
+ 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);
+
+ try {
+ await Mailer.sendSelfserviceWelcomeMail(runner.email, response.token, locale)
+ } catch (error) {
+ throw new MailSendingError();
+ }
+
+ return response;
+ }
+
+ @Get('/organizations/selfservice/:token')
+ @ResponseSchema(ResponseSelfServiceOrganisation, { isArray: false })
+ @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
+ @OpenAPI({ description: 'Get the basic info and teams for a org.' })
+ async getSelfserviceOrg(@Param('token') token: string) {
+ const orgid = (await this.getOrgansisation(token)).id;
+ const org = await this.orgRepository.findOne({ id: orgid }, { relations: ['teams'] })
+
+ return new ResponseSelfServiceOrganisation(org);
+ }
+
+ /**
+ * Get's a runner by a provided jwt token.
+ * @param token The runner jwt provided by the runner to identitfy themselves.
+ */
+ private async getRunner(token: string): Promise {
+ if (token == "") { throw new JwtNotProvidedError(); }
+ let jwtPayload = undefined
+ try {
+ jwtPayload = jwt.verify(token, config.jwt_secret);
+ } catch (error) {
+ throw new InvalidCredentialsError();
+ }
+
+ const runner = await this.runnerRepository.findOne({ id: jwtPayload["id"] }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] });
+ if (!runner) { throw new RunnerNotFoundError() }
+ return runner;
+ }
+
+ /**
+ * Get's a runner org by a provided registration api key.
+ * @param token The organization's registration api token.
+ */
+ private async getOrgansisation(token: string): Promise {
+ token = Buffer.from(token, 'base64').toString('utf8');
+
+ const organization = await this.orgRepository.findOne({ key: token });
+ if (!organization) { throw new RunnerOrganizationNotFoundError; }
+
+ return organization;
+ }
}
\ No newline at end of file