diff --git a/package.json b/package.json
index 4dd13c9..9823b61 100644
--- a/package.json
+++ b/package.json
@@ -1,108 +1,109 @@
-{
- "name": "@odit/lfk-backend",
- "version": "0.12.0",
- "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": true,
- "tag": true,
- "tagName": "v${version}",
- "tagAnnotation": "v${version}"
- },
- "npm": {
- "publish": false
- }
- },
- "nodemonConfig": {
- "ignore": [
- "src/tests/*",
- "docs/*"
- ]
- }
-}
+{
+ "name": "@odit/lfk-backend",
+ "version": "0.12.0",
+ "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",
+ "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": true,
+ "tag": true,
+ "tagName": "v${version}",
+ "tagAnnotation": "v${version}"
+ },
+ "npm": {
+ "publish": false
+ }
+ },
+ "nodemonConfig": {
+ "ignore": [
+ "src/tests/*",
+ "docs/*"
+ ]
+ }
+}
diff --git a/src/controllers/RunnerSelfServiceController.ts b/src/controllers/RunnerSelfServiceController.ts
index 9563975..41655ca 100644
--- a/src/controllers/RunnerSelfServiceController.ts
+++ b/src/controllers/RunnerSelfServiceController.ts
@@ -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,7 +116,7 @@ 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).' })
@@ -148,8 +148,11 @@ export class RunnerSelfServiceController {
@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, @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 {
+ const runner = await this.runnerRepository.findOne({ email });
+ return runner != undefined
+ }
}
\ No newline at end of file
diff --git a/src/models/actions/create/CreateUser.ts b/src/models/actions/create/CreateUser.ts
index a29fb62..d85a8ba 100644
--- a/src/models/actions/create/CreateUser.ts
+++ b/src/models/actions/create/CreateUser.ts
@@ -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;
diff --git a/src/models/actions/update/UpdateUser.ts b/src/models/actions/update/UpdateUser.ts
index e5685eb..88f36c6 100644
--- a/src/models/actions/update/UpdateUser.ts
+++ b/src/models/actions/update/UpdateUser.ts
@@ -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;
diff --git a/src/tests/selfservice/selfservice_delete.spec.ts b/src/tests/selfservice/selfservice_delete.spec.ts
index 9add148..423d93e 100644
--- a/src/tests/selfservice/selfservice_delete.spec.ts
+++ b/src/tests/selfservice/selfservice_delete.spec.ts
@@ -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);
diff --git a/src/tests/selfservice/selfservice_forgotten.spec.ts b/src/tests/selfservice/selfservice_forgotten.spec.ts
index c67ef7e..9eb865e 100644
--- a/src/tests/selfservice/selfservice_forgotten.spec.ts
+++ b/src/tests/selfservice/selfservice_forgotten.spec.ts
@@ -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;
diff --git a/src/tests/selfservice/selfservice_get.spec.ts b/src/tests/selfservice/selfservice_get.spec.ts
index 7867127..201cc08 100644
--- a/src/tests/selfservice/selfservice_get.spec.ts
+++ b/src/tests/selfservice/selfservice_get.spec.ts
@@ -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");
diff --git a/src/tests/selfservice/selfservice_register.spec.ts b/src/tests/selfservice/selfservice_register.spec.ts
index 36dc7fa..724857a 100644
--- a/src/tests/selfservice/selfservice_register.spec.ts
+++ b/src/tests/selfservice/selfservice_register.spec.ts
@@ -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",