diff --git a/CHANGELOG.md b/CHANGELOG.md
index 68fab58..32df7de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,16 +2,30 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
+#### [v0.7.1](https://git.odit.services/lfk/backend/compare/v0.7.1...v0.7.1)
+
+- Merge pull request 'Selfservice deletion feature/174-selfservice_deletion' (#175) from feature/174-selfservice_deletion into dev [`e702118`](https://git.odit.services/lfk/backend/commit/e702118d4d80e362e41bb88c74343d50530d1338)
+- Added tests for the new endpoint [`20aeed8`](https://git.odit.services/lfk/backend/commit/20aeed87780247dc6401bba725801fc1874e50b5)
+- Removed param from test [`97159dd`](https://git.odit.services/lfk/backend/commit/97159dd9f81aed080c174a3eb8da9e66dfea9b10)
+- Added selfservice deletion endpoint [`dcb12b0`](https://git.odit.services/lfk/backend/commit/dcb12b0ac289f8df148ba10ae6389727c16f53fd)
+- 🧾New changelog file version [CI SKIP] [skip ci] [`88844e1`](https://git.odit.services/lfk/backend/commit/88844e1a44d87a7dc253bf9aedf2fb3f6cdd1cfe)
+- Fixed response bug [`ccb7ae2`](https://git.odit.services/lfk/backend/commit/ccb7ae29a39387c0f2762861565dc22996a2493a)
+- Updated old hint [`dd12583`](https://git.odit.services/lfk/backend/commit/dd1258333ef67243f8a8df97c176ec5a054a5e3b)
+
#### [v0.7.1](https://git.odit.services/lfk/backend/compare/v0.7.0...v0.7.1)
+> 26 March 2021
+
+- Merge pull request 'Release 0.7.1' (#173) from dev into main [`e76a9ce`](https://git.odit.services/lfk/backend/commit/e76a9cef956b00de7bbb11b6d863d4f33e3d5a34)
- Revert "Set timeout even higher b/c sqlite just kills itself during these tests" [`f159252`](https://git.odit.services/lfk/backend/commit/f159252651942e442026dbcaae09b242e05d8204)
- Set timeout even higher b/c sqlite just kills itself during these tests [`6ab6099`](https://git.odit.services/lfk/backend/commit/6ab60998d4f716aded93bb3b5d15594fc5e0434a)
- Adjusted jest timeout to mitigate sqlite from invalidateing all tests⏱ [`30d220b`](https://git.odit.services/lfk/backend/commit/30d220bc36a28f224406e49ed27ff3f6b4f409e9)
- 🧾New changelog file version [CI SKIP] [skip ci] [`963253c`](https://git.odit.services/lfk/backend/commit/963253cbc84ed07af13ed0925952ec1b7dcc53ad)
-- Now resolveing runnercards [`24aff3b`](https://git.odit.services/lfk/backend/commit/24aff3bac458a9886ca40163484bc72733dc766a)
-- Tests now keep the group [`f3d73d5`](https://git.odit.services/lfk/backend/commit/f3d73d53467a4d00011d280c24e1e12fbb8e443d)
+- 🧾New changelog file version [CI SKIP] [skip ci] [`3ef3a94`](https://git.odit.services/lfk/backend/commit/3ef3a94b20c1abf6fd2f19472e5f448b4c72bd7f)
- 🚀Bumped version to v0.7.1 [`135852e`](https://git.odit.services/lfk/backend/commit/135852eb9a91010a4ab972ba9efc7b71dfe4d68f)
- Merge pull request 'RESPONSERUNNERCARD fix bugfix/171-responserunnercards' (#172) from bugfix/171-responserunnercards into dev [`539a650`](https://git.odit.services/lfk/backend/commit/539a6509b17cfd373eef8e443eaa7d41168ac7a9)
+- Now resolveing runnercards [`24aff3b`](https://git.odit.services/lfk/backend/commit/24aff3bac458a9886ca40163484bc72733dc766a)
+- Tests now keep the group [`f3d73d5`](https://git.odit.services/lfk/backend/commit/f3d73d53467a4d00011d280c24e1e12fbb8e443d)
- 🧾New changelog file version [CI SKIP] [skip ci] [`ce63043`](https://git.odit.services/lfk/backend/commit/ce63043887769e1f92a8c064d6647e0deb81b7fa)
#### [v0.7.0](https://git.odit.services/lfk/backend/compare/v0.6.4...v0.7.0)
diff --git a/src/controllers/RunnerSelfServiceController.ts b/src/controllers/RunnerSelfServiceController.ts
index 03e0ec3..8f5509e 100644
--- a/src/controllers/RunnerSelfServiceController.ts
+++ b/src/controllers/RunnerSelfServiceController.ts
@@ -1,12 +1,12 @@
import { Request } from "express";
import * as jwt from "jsonwebtoken";
-import { Body, Get, JsonController, OnUndefined, Param, Post, QueryParam, Req, UseBefore } from 'routing-controllers';
+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, RunnerNotFoundError, RunnerSelfserviceTimeoutError } from '../errors/RunnerErrors';
+import { RunnerEmailNeededError, RunnerHasDistanceDonationsError, RunnerNotFoundError, RunnerSelfserviceTimeoutError } from '../errors/RunnerErrors';
import { RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
import { ScanStationNotFoundError } from '../errors/ScanStationErrors';
import { JwtCreator } from '../jwtcreator';
@@ -23,6 +23,9 @@ 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 {
@@ -43,11 +46,50 @@ export class RunnerSelfServiceController {
@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 contact support.' })
+ @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 })
diff --git a/src/tests/selfservice/selfservice_delete.spec.ts b/src/tests/selfservice/selfservice_delete.spec.ts
new file mode 100644
index 0000000..9add148
--- /dev/null
+++ b/src/tests/selfservice/selfservice_delete.spec.ts
@@ -0,0 +1,66 @@
+import axios from 'axios';
+import { config } from '../../config';
+const base = "http://localhost:" + config.internal_port
+
+let access_token;
+let axios_config;
+
+beforeAll(async () => {
+ jest.setTimeout(20000);
+ const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
+ access_token = res.data["access_token"];
+ axios_config = {
+ headers: { "authorization": "Bearer " + access_token },
+ validateStatus: undefined
+ };
+});
+// ---------------
+describe('delete selfservice runner invalid', () => {
+ let added_runner;
+ it('registering as citizen with minimal params should return 200', async () => {
+ const res = await axios.post(base + '/api/runners/register', {
+ "firstname": "string",
+ "lastname": "string",
+ "email": "user@example.com"
+ }, axios_config);
+ added_runner = res.data;
+ expect(res.status).toEqual(200);
+ expect(res.headers['content-type']).toContain("application/json");
+ });
+ it('delete with valid jwt should return 200', async () => {
+ const res = await axios.delete(base + '/api/runners/me/' + added_runner.token, axios_config);
+ expect(res.status).toEqual(200);
+ expect(res.headers['content-type']).toContain("application/json");
+ });
+ it('delete with valid jwt but non-existant runner should return 200', async () => {
+ const res = await axios.delete(base + '/api/runners/me/' + added_runner.token, axios_config);
+ expect(res.status).toEqual(404);
+ expect(res.headers['content-type']).toContain("application/json");
+ });
+ it('delete with invalid jwt should return 401', async () => {
+ const res = await axios.delete(base + '/api/runners/me/123.123', axios_config);
+ expect(res.status).toEqual(401);
+ expect(res.headers['content-type']).toContain("application/json");
+ });
+});
+// ---------------
+describe('delete selfservice runner valid', () => {
+ let added_runner;
+ it('registering as citizen with minimal params should return 200', async () => {
+ const res = await axios.post(base + '/api/runners/register', {
+ "firstname": "string",
+ "lastname": "string",
+ "email": "user@example.com"
+ }, axios_config);
+ added_runner = res.data;
+ expect(res.status).toEqual(200);
+ expect(res.headers['content-type']).toContain("application/json");
+ });
+ it('delete with valid jwt should return 200', async () => {
+ const res = await axios.delete(base + '/api/runners/me/' + added_runner.token, axios_config);
+ expect(res.status).toEqual(200);
+ expect(res.headers['content-type']).toContain("application/json");
+ delete added_runner.token;
+ expect(res.data).toEqual(added_runner);
+ });
+});
\ No newline at end of file