From 701207e100c7b7b71a4791a7594bd346a4618066 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 2 Dec 2020 18:46:40 +0100 Subject: [PATCH 01/22] Created basic runner controller ref #13 --- src/controllers/RunnerController.ts | 91 +++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/controllers/RunnerController.ts diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts new file mode 100644 index 0000000..89e5e8b --- /dev/null +++ b/src/controllers/RunnerController.ts @@ -0,0 +1,91 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError, Authorized } from 'routing-controllers'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { Runner } from '../models/Runner'; +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; +import {RunnerIdsNotMatchingError, RunnerNotFoundError} from "../errors/RunnerErrors"; + +class CreateRunner { + @IsString() + @IsNotEmpty() + name: string; + + @IsInt() + @IsPositive() + length: number; +} + +@JsonController('/runners') +@Authorized("RUNNERS:read") +export class RunnerController { + private runnerRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerRepository = getConnectionManager().get().getRepository(Runner); + } + + @Get() + @ResponseSchema(Runner, { isArray: true }) + @OpenAPI({ description: "Lists all runners." }) + getAll() { + return this.runnerRepository.find(); + } + + @Get('/:id') + @ResponseSchema(Runner) + @ResponseSchema(RunnerNotFoundError, {statusCode: 404}) + @OnUndefined(RunnerNotFoundError) + @OpenAPI({ description: "Returns a runner of a specified id (if it exists)" }) + getOne(@Param('id') id: number) { + return this.runnerRepository.findOne({ id: id }); + } + + @Post() + @ResponseSchema(Runner) + @OpenAPI({ description: "Create a new runner object (id will be generated automagicly)." }) + post( + @Body({ validate: true }) + runner: CreateRunner + ) { + return this.runnerRepository.save(runner); + } + + @Put('/:id') + @ResponseSchema(Runner) + @ResponseSchema(RunnerNotFoundError, {statusCode: 404}) + @ResponseSchema(RunnerIdsNotMatchingError, {statusCode: 406}) + @OpenAPI({description: "Update a runner object (id can't be changed)."}) + async put(@Param('id') id: number, @EntityFromBody() runner: Runner) { + let oldRunner = await this.runnerRepository.findOne({ id: id }); + + if (!oldRunner) { + throw new RunnerNotFoundError(); + } + + if(oldRunner.id != runner.id){ + throw new RunnerIdsNotMatchingError(); + } + + await this.runnerRepository.update(oldRunner, runner); + return runner; + } + + @Delete('/:id') + @ResponseSchema(Runner) + @ResponseSchema(RunnerNotFoundError, {statusCode: 404}) + @OpenAPI({description: "Delete a specified runner (if it exists)."}) + async remove(@Param('id') id: number) { + let runner = await this.runnerRepository.findOne({ id: id }); + + if (!runner) { + throw new RunnerNotFoundError(); + } + + await this.runnerRepository.delete(runner); + return runner; + } +} From 980ac646889690ae773de75b984dc9eec4e67bb1 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 2 Dec 2020 18:50:49 +0100 Subject: [PATCH 02/22] Added basic runner related errors --- src/errors/RunnerErrors.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/errors/RunnerErrors.ts diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts new file mode 100644 index 0000000..c725c03 --- /dev/null +++ b/src/errors/RunnerErrors.ts @@ -0,0 +1,27 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers'; +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; + +/** + * Error to throw when a runner couldn't be found. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerNotFoundError extends NotFoundError { + @IsString() + name = "RunnerNotFoundError" + + @IsString() + message = "Runner not found!" +} + +/** + * Error to throw when two runners' ids don't match. + * Usually occurs when a user tries to change a runner's id. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerIdsNotMatchingError extends NotAcceptableError { + @IsString() + name = "RunnerIdsNotMatchingError" + + @IsString() + message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" +} \ No newline at end of file From 7bbf769bddaa92ec263d06adb5ccd3199feb8bc4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 2 Dec 2020 19:05:58 +0100 Subject: [PATCH 03/22] Added basic creation class --- src/controllers/RunnerController.ts | 80 +++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 89e5e8b..5b38bf6 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -1,23 +1,69 @@ -import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError, Authorized } from 'routing-controllers'; +import { + JsonController, + Param, + Body, + Get, + Post, + Put, + Delete, + NotFoundError, + OnUndefined, + NotAcceptableError, + Authorized +} from 'routing-controllers'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Runner } from '../models/Runner'; -import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; -import {RunnerIdsNotMatchingError, RunnerNotFoundError} from "../errors/RunnerErrors"; +import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsPositive, IsString } from 'class-validator'; +import { RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; class CreateRunner { + /** + * The runners's first name. + */ + @IsNotEmpty() + @IsString() + firstname: string; + + /** + * The runners's middle name. + * Optional + */ + @IsOptional() + @IsString() + middlename?: string; + + /** + * The runers's last name. + */ @IsString() @IsNotEmpty() - name: string; + lastname: string; + + /** + * The runner's phone number. + * Optional + */ + @IsOptional() + @IsPhoneNumber('DE') + phone?: string; + + /** + * The runner's email address. + * Optional + */ + @IsOptional() + @IsEmail() + email?: string; @IsInt() - @IsPositive() - length: number; + @IsOptional() + groupId?: number; } @JsonController('/runners') -@Authorized("RUNNERS:read") +//@Authorized('RUNNERS:read') export class RunnerController { private runnerRepository: Repository; @@ -30,23 +76,23 @@ export class RunnerController { @Get() @ResponseSchema(Runner, { isArray: true }) - @OpenAPI({ description: "Lists all runners." }) + @OpenAPI({ description: 'Lists all runners.' }) getAll() { return this.runnerRepository.find(); } @Get('/:id') @ResponseSchema(Runner) - @ResponseSchema(RunnerNotFoundError, {statusCode: 404}) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) @OnUndefined(RunnerNotFoundError) - @OpenAPI({ description: "Returns a runner of a specified id (if it exists)" }) + @OpenAPI({ description: 'Returns a runner of a specified id (if it exists)' }) getOne(@Param('id') id: number) { return this.runnerRepository.findOne({ id: id }); } @Post() @ResponseSchema(Runner) - @OpenAPI({ description: "Create a new runner object (id will be generated automagicly)." }) + @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) post( @Body({ validate: true }) runner: CreateRunner @@ -56,9 +102,9 @@ export class RunnerController { @Put('/:id') @ResponseSchema(Runner) - @ResponseSchema(RunnerNotFoundError, {statusCode: 404}) - @ResponseSchema(RunnerIdsNotMatchingError, {statusCode: 406}) - @OpenAPI({description: "Update a runner object (id can't be changed)."}) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runner object (id can't be changed)." }) async put(@Param('id') id: number, @EntityFromBody() runner: Runner) { let oldRunner = await this.runnerRepository.findOne({ id: id }); @@ -66,7 +112,7 @@ export class RunnerController { throw new RunnerNotFoundError(); } - if(oldRunner.id != runner.id){ + if (oldRunner.id != runner.id) { throw new RunnerIdsNotMatchingError(); } @@ -76,8 +122,8 @@ export class RunnerController { @Delete('/:id') @ResponseSchema(Runner) - @ResponseSchema(RunnerNotFoundError, {statusCode: 404}) - @OpenAPI({description: "Delete a specified runner (if it exists)."}) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: 'Delete a specified runner (if it exists).' }) async remove(@Param('id') id: number) { let runner = await this.runnerRepository.findOne({ id: id }); From cb5d5e546d0232e771495a3c5d140ac9531b7743 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 2 Dec 2020 19:41:03 +0100 Subject: [PATCH 04/22] Added more runner errors ref #13 --- src/errors/RunnerErrors.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts index c725c03..0be6419 100644 --- a/src/errors/RunnerErrors.ts +++ b/src/errors/RunnerErrors.ts @@ -24,4 +24,29 @@ export class RunnerIdsNotMatchingError extends NotAcceptableError { @IsString() message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" +} + +export class RunnerOnlyOneGroupAllowedError extends NotAcceptableError { + @IsString() + name = "RunnerOnlyOneGroupAllowedError" + + @IsString() + message = "Runner's can only be part of one group (team or organisiation)! \n You provided an id for both." +} + +export class RunnerGroupNeededError extends NotAcceptableError { + @IsString() + name = "RunnerGroupNeededError" + + @IsString() + message = "Runner's need to be part of one group (team or organisiation)! \n You provided neither." +} + + +export class RunnerGroupNotFoundError extends NotFoundError { + @IsString() + name = "RunnerGroupNotFoundError" + + @IsString() + message = "The group you provided couldn't be located in the system. \n Please check your request." } \ No newline at end of file From 3ade01def931fbb7feb1a1fe8b8b8e29a22b0a58 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 2 Dec 2020 19:41:47 +0100 Subject: [PATCH 05/22] temp commit: added first part of create runner ref #13 --- src/controllers/RunnerController.ts | 40 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 5b38bf6..ea5a70d 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -16,7 +16,10 @@ import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Runner } from '../models/Runner'; import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsPositive, IsString } from 'class-validator'; -import { RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; +import { RunnerGroupNeededError, RunnerGroupNotFoundError, RunnerIdsNotMatchingError, RunnerNotFoundError, RunnerOnlyOneGroupAllowedError } from '../errors/RunnerErrors'; +import { RunnerGroup } from '../models/RunnerGroup'; +import { RunnerOrganisation } from '../models/RunnerOrganisation'; +import { RunnerTeam } from '../models/RunnerTeam'; class CreateRunner { /** @@ -59,7 +62,11 @@ class CreateRunner { @IsInt() @IsOptional() - groupId?: number; + teamId?: number; + + @IsInt() + @IsOptional() + orgId?: number; } @JsonController('/runners') @@ -93,10 +100,35 @@ export class RunnerController { @Post() @ResponseSchema(Runner) @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) - post( + async post( @Body({ validate: true }) - runner: CreateRunner + createRunner: CreateRunner ) { + let group: RunnerGroup; + + if(createRunner.teamId && createRunner.orgId){ + throw new RunnerOnlyOneGroupAllowedError(); + } + if(!createRunner.teamId && !createRunner.orgId){ + throw new RunnerGroupNeededError(); + } + + if(createRunner.teamId){ + group = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: createRunner.teamId }); + } + if(createRunner.orgId){ + group = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: createRunner.orgId }); + } + if(!group){ + throw new RunnerGroupNotFoundError(); + } + + delete createRunner.teamId; + delete createRunner.orgId; + let runner = createRunner; + runner.group=group; + console.log(runner) + return this.runnerRepository.save(runner); } From 684e7c4ddbb10e88ead1d33e93f97fc7dcb0db25 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Thu, 3 Dec 2020 17:12:27 +0100 Subject: [PATCH 06/22] =?UTF-8?q?=E2=9A=99=20settings=20-=20standard=20imp?= =?UTF-8?q?orts=20+=20quote=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 812953b..bc63ed0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,9 @@ "prettier.enable": false, "[typescript]": { "editor.defaultFormatter": "vscode.typescript-language-features" - } + }, + "javascript.preferences.quoteStyle": "single", + "javascript.preferences.importModuleSpecifierEnding": "minimal", + "typescript.preferences.importModuleSpecifierEnding": "minimal", + "typescript.preferences.includePackageJsonAutoImports": "on" } \ No newline at end of file From da4597fa62dd85b0496aaa6d9407a263b5291912 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 17:43:24 +0100 Subject: [PATCH 07/22] Moded track controller related models to a new file --- src/controllers/TrackController.ts | 31 +++++++++++------------------- src/models/CreateTrack.ts | 21 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 src/models/CreateTrack.ts diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index d0b3a0c..a448922 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -4,20 +4,11 @@ import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Track } from '../models/Track'; import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; -import {TrackIdsNotMatchingError, TrackNotFoundError} from "../errors/TrackErrors"; - -class CreateTrack { - @IsString() - @IsNotEmpty() - name: string; - - @IsInt() - @IsPositive() - length: number; -} +import { TrackIdsNotMatchingError, TrackNotFoundError } from "../errors/TrackErrors"; +import { CreateTrack } from '../models/CreateTrack'; @JsonController('/tracks') -@Authorized("TRACKS:read") +//@Authorized("TRACKS:read") export class TrackController { private trackRepository: Repository; @@ -37,7 +28,7 @@ export class TrackController { @Get('/:id') @ResponseSchema(Track) - @ResponseSchema(TrackNotFoundError, {statusCode: 404}) + @ResponseSchema(TrackNotFoundError, { statusCode: 404 }) @OnUndefined(TrackNotFoundError) @OpenAPI({ description: "Returns a track of a specified id (if it exists)" }) getOne(@Param('id') id: number) { @@ -51,14 +42,14 @@ export class TrackController { @Body({ validate: true }) track: CreateTrack ) { - return this.trackRepository.save(track); + return this.trackRepository.save(track.getTrack()); } @Put('/:id') @ResponseSchema(Track) - @ResponseSchema(TrackNotFoundError, {statusCode: 404}) - @ResponseSchema(TrackIdsNotMatchingError, {statusCode: 406}) - @OpenAPI({description: "Update a track object (id can't be changed)."}) + @ResponseSchema(TrackNotFoundError, { statusCode: 404 }) + @ResponseSchema(TrackIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a track object (id can't be changed)." }) async put(@Param('id') id: number, @EntityFromBody() track: Track) { let oldTrack = await this.trackRepository.findOne({ id: id }); @@ -66,7 +57,7 @@ export class TrackController { throw new TrackNotFoundError(); } - if(oldTrack.id != track.id){ + if (oldTrack.id != track.id) { throw new TrackIdsNotMatchingError(); } @@ -76,8 +67,8 @@ export class TrackController { @Delete('/:id') @ResponseSchema(Track) - @ResponseSchema(TrackNotFoundError, {statusCode: 404}) - @OpenAPI({description: "Delete a specified track (if it exists)."}) + @ResponseSchema(TrackNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: "Delete a specified track (if it exists)." }) async remove(@Param('id') id: number) { let track = await this.trackRepository.findOne({ id: id }); diff --git a/src/models/CreateTrack.ts b/src/models/CreateTrack.ts new file mode 100644 index 0000000..025d8a9 --- /dev/null +++ b/src/models/CreateTrack.ts @@ -0,0 +1,21 @@ +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; +import { Track } from './Track'; + +export class CreateTrack { + @IsString() + @IsNotEmpty() + name: string; + + @IsInt() + @IsPositive() + distance: number; + + public getTrack(): Track { + let newTrack: Track = new Track(); + + newTrack.name = this.name; + newTrack.distance = this.distance; + + return newTrack; + } +} \ No newline at end of file From 6d81fc13095b2d96b6cd864f952242749567bbab Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 17:46:32 +0100 Subject: [PATCH 08/22] Added Comments. ref #11 #13 --- src/controllers/TrackController.ts | 2 +- src/models/CreateTrack.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index a448922..7b22cc2 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -42,7 +42,7 @@ export class TrackController { @Body({ validate: true }) track: CreateTrack ) { - return this.trackRepository.save(track.getTrack()); + return this.trackRepository.save(track.toTrack()); } @Put('/:id') diff --git a/src/models/CreateTrack.ts b/src/models/CreateTrack.ts index 025d8a9..015a58f 100644 --- a/src/models/CreateTrack.ts +++ b/src/models/CreateTrack.ts @@ -2,15 +2,24 @@ import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; import { Track } from './Track'; export class CreateTrack { + /** + * The track's name. + */ @IsString() @IsNotEmpty() name: string; + /** + * The track's distance in meters (must be greater 0). + */ @IsInt() @IsPositive() distance: number; - public getTrack(): Track { + /** + * Converts a Track object based on this. + */ + public toTrack(): Track { let newTrack: Track = new Track(); newTrack.name = this.name; From 9e3ee433d2571110004d797381a872348075a317 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 18:03:43 +0100 Subject: [PATCH 09/22] Moved Create Runner to it's own file --- src/controllers/RunnerController.ts | 105 ++++------------------------ src/models/CreateRunner.ts | 56 +++++++++++++++ 2 files changed, 69 insertions(+), 92 deletions(-) create mode 100644 src/models/CreateRunner.ts diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index ea5a70d..29685a6 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -1,73 +1,11 @@ -import { - JsonController, - Param, - Body, - Get, - Post, - Put, - Delete, - NotFoundError, - OnUndefined, - NotAcceptableError, - Authorized -} from 'routing-controllers'; +import { JsonController, Param, Body, Get, Post, Put, Delete, OnUndefined } from 'routing-controllers'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Runner } from '../models/Runner'; -import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsPositive, IsString } from 'class-validator'; import { RunnerGroupNeededError, RunnerGroupNotFoundError, RunnerIdsNotMatchingError, RunnerNotFoundError, RunnerOnlyOneGroupAllowedError } from '../errors/RunnerErrors'; -import { RunnerGroup } from '../models/RunnerGroup'; -import { RunnerOrganisation } from '../models/RunnerOrganisation'; -import { RunnerTeam } from '../models/RunnerTeam'; +import { CreateRunner } from '../models/CreateRunner'; -class CreateRunner { - /** - * The runners's first name. - */ - @IsNotEmpty() - @IsString() - firstname: string; - - /** - * The runners's middle name. - * Optional - */ - @IsOptional() - @IsString() - middlename?: string; - - /** - * The runers's last name. - */ - @IsString() - @IsNotEmpty() - lastname: string; - - /** - * The runner's phone number. - * Optional - */ - @IsOptional() - @IsPhoneNumber('DE') - phone?: string; - - /** - * The runner's email address. - * Optional - */ - @IsOptional() - @IsEmail() - email?: string; - - @IsInt() - @IsOptional() - teamId?: number; - - @IsInt() - @IsOptional() - orgId?: number; -} @JsonController('/runners') //@Authorized('RUNNERS:read') @@ -99,37 +37,20 @@ export class RunnerController { @Post() @ResponseSchema(Runner) + @ResponseSchema(RunnerOnlyOneGroupAllowedError) + @ResponseSchema(RunnerGroupNeededError) + @ResponseSchema(RunnerGroupNotFoundError) @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) - async post( - @Body({ validate: true }) - createRunner: CreateRunner - ) { - let group: RunnerGroup; - - if(createRunner.teamId && createRunner.orgId){ - throw new RunnerOnlyOneGroupAllowedError(); - } - if(!createRunner.teamId && !createRunner.orgId){ - throw new RunnerGroupNeededError(); + async post(@Body({ validate: true }) createRunner: CreateRunner) { + let runner; + try { + runner = await createRunner.toRunner(); + } catch (error) { + return error; } - if(createRunner.teamId){ - group = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: createRunner.teamId }); - } - if(createRunner.orgId){ - group = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: createRunner.orgId }); - } - if(!group){ - throw new RunnerGroupNotFoundError(); - } - - delete createRunner.teamId; - delete createRunner.orgId; - let runner = createRunner; - runner.group=group; - console.log(runner) - - return this.runnerRepository.save(runner); + return runner; + //return this.runnerRepository.save(runner); } @Put('/:id') diff --git a/src/models/CreateRunner.ts b/src/models/CreateRunner.ts new file mode 100644 index 0000000..b35be10 --- /dev/null +++ b/src/models/CreateRunner.ts @@ -0,0 +1,56 @@ +import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsPositive, IsString } from 'class-validator'; +import { Runner } from '../models/Runner'; +import { getConnectionManager, Repository } from 'typeorm'; +import { group } from 'console'; +import { RunnerOnlyOneGroupAllowedError, RunnerGroupNeededError, RunnerGroupNotFoundError } from '../errors/RunnerErrors'; +import { RunnerOrganisation } from './RunnerOrganisation'; +import { RunnerTeam } from './RunnerTeam'; +import { RunnerGroup } from './RunnerGroup'; +import { Address } from 'cluster'; + +export class CreateRunner { + @IsString() + firstname: string; + @IsString() + middlename?: string; + @IsString() + lastname: string; + @IsString() + phone?: string; + @IsString() + email?: string; + @IsInt() + teamId?: number + @IsInt() + orgId?: number + + public async toRunner(): Promise { + let newRunner: Runner = new Runner(); + + if (this.teamId !== undefined && this.orgId !== undefined) { + throw new RunnerOnlyOneGroupAllowedError(); + } + if (this.teamId === undefined && this.orgId === undefined) { + throw new RunnerGroupNeededError(); + } + + if (this.teamId) { + newRunner.group = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: this.teamId }); + } + if (this.orgId) { + newRunner.group = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: this.orgId }); + } + if (!newRunner.group) { + throw new RunnerGroupNotFoundError(); + } + + newRunner.firstname = this.firstname; + newRunner.middlename = this.middlename; + newRunner.lastname = this.lastname; + newRunner.phone = this.phone; + newRunner.email = this.email; + + console.log(newRunner) + return newRunner; + } +} \ No newline at end of file From 098699e09a4b2c1399c471149a3379645710274a Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Thu, 3 Dec 2020 18:07:49 +0100 Subject: [PATCH 10/22] =?UTF-8?q?=F0=9F=90=9E=20CreateRunner=20-=20optiona?= =?UTF-8?q?l=20orgId=20&=20teamId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/models/CreateRunner.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/models/CreateRunner.ts b/src/models/CreateRunner.ts index b35be10..9eb15eb 100644 --- a/src/models/CreateRunner.ts +++ b/src/models/CreateRunner.ts @@ -20,8 +20,10 @@ export class CreateRunner { @IsString() email?: string; @IsInt() + @IsOptional() teamId?: number @IsInt() + @IsOptional() orgId?: number public async toRunner(): Promise { From 084691c294ff3bf4d09ef634ce2d0d81ef93c50d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 18:46:53 +0100 Subject: [PATCH 11/22] Now returning the saved runner ref #13 --- src/controllers/RunnerController.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 29685a6..da80b31 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -49,8 +49,7 @@ export class RunnerController { return error; } - return runner; - //return this.runnerRepository.save(runner); + return this.runnerRepository.save(runner); } @Put('/:id') From ee35da7342de601650052eae13bc773831ea9ad7 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 18:48:24 +0100 Subject: [PATCH 12/22] Fixxed dockerfile --- Dockerfile | 2 +- docker-compose.yml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index da54cd5..089c4de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:alpine WORKDIR /app COPY ./package.json ./ -RUN npm i +RUN yarn COPY ./ ./ ENTRYPOINT [ "yarn","dev" ] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 1efd5ba..7ca0bb8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,9 +12,12 @@ services: DB_USER: lfk DB_PASSWORD: changeme DB_NAME: lfk + NODE_ENV: production backend_db: image: postgres:11-alpine environment: POSTGRES_DB: lfk POSTGRES_PASSWORD: changeme - POSTGRES_USER: lfk \ No newline at end of file + POSTGRES_USER: lfk + ports: + - 5432:5432 \ No newline at end of file From 8ef6f933a745214ba02a12cf778eb36bc04a0891 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Thu, 3 Dec 2020 18:48:35 +0100 Subject: [PATCH 13/22] =?UTF-8?q?=E2=9A=99=20tsconfig=20-=20includes=20+?= =?UTF-8?q?=20excludes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tsconfig.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tsconfig.json b/tsconfig.json index 0f2192a..3f35579 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,4 +9,11 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true } + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.spec.ts" + ] } \ No newline at end of file From ffc31506e36b9c0b22cc7cc66e6ab5f06c4a64cf Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Thu, 3 Dec 2020 18:48:51 +0100 Subject: [PATCH 14/22] =?UTF-8?q?=E2=9A=99tsconfig=20-=20no=20sourcemaps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tsconfig.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 3f35579..573aa28 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,9 @@ "esModuleInterop": true, "strict": false, "experimentalDecorators": true, - "emitDecoratorMetadata": true - } + "emitDecoratorMetadata": true, + "sourceMap": false + }, "include": [ "src/**/*" ], From 9051b7565cf3506ddecfdc0abc05e7266be450dd Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Thu, 3 Dec 2020 18:49:21 +0100 Subject: [PATCH 15/22] =?UTF-8?q?=E2=9A=99target:=20es2017=20=E2=96=B6=20E?= =?UTF-8?q?S2020?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 573aa28..dfd4d15 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "ES2020", "module": "commonjs", "rootDir": "./src", "outDir": "./build", From a35e6d0a9f19dc7dbde3c867b840276416eac9f6 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 19:20:53 +0100 Subject: [PATCH 16/22] Added basics for runnerorg controller ref #13 --- .../RunnerOrganisationController.ts | 87 +++++++++++++++++++ src/errors/RunnerOrganisationErrors.ts | 27 ++++++ src/models/CreateRunnerOrganisation.ts | 15 ++++ 3 files changed, 129 insertions(+) create mode 100644 src/controllers/RunnerOrganisationController.ts create mode 100644 src/errors/RunnerOrganisationErrors.ts create mode 100644 src/models/CreateRunnerOrganisation.ts diff --git a/src/controllers/RunnerOrganisationController.ts b/src/controllers/RunnerOrganisationController.ts new file mode 100644 index 0000000..6297073 --- /dev/null +++ b/src/controllers/RunnerOrganisationController.ts @@ -0,0 +1,87 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, OnUndefined } from 'routing-controllers'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { RunnerOrganisation } from '../models/RunnerOrganisation'; +import { RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors'; +import { CreateRunnerOrganisation } from '../models/CreateRunnerOrganisation'; +import { RunnerGroup } from '../models/RunnerGroup'; + + +@JsonController('/organisations') +//@Authorized('RUNNERS:read') +export class RunnerOrganisationController { + private runnerOrganisationRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerGroup); + } + + @Get() + @ResponseSchema(RunnerOrganisation, { isArray: true }) + @OpenAPI({ description: 'Lists all runnerOrganisations.' }) + getAll() { + return this.runnerOrganisationRepository.find(); + } + + @Get('/:id') + @ResponseSchema(RunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @OnUndefined(RunnerOrganisationNotFoundError) + @OpenAPI({ description: 'Returns a runnerOrganisation of a specified id (if it exists)' }) + getOne(@Param('id') id: number) { + return this.runnerOrganisationRepository.findOne({ id: id }); + } + + @Post() + @ResponseSchema(RunnerOrganisation) + @OpenAPI({ description: 'Create a new runnerOrganisation object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createRunnerOrganisation: CreateRunnerOrganisation) { + let runnerOrganisation; + try { + runnerOrganisation = await createRunnerOrganisation.toRunnerOrganisation(); + } catch (error) { + return error; + } + + return this.runnerOrganisationRepository.save(runnerOrganisation); + } + + @Put('/:id') + @ResponseSchema(RunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runnerOrganisation object (id can't be changed)." }) + async put(@Param('id') id: number, @EntityFromBody() runnerOrganisation: RunnerOrganisation) { + let oldRunnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id }); + + if (!oldRunnerOrganisation) { + throw new RunnerOrganisationNotFoundError(); + } + + if (oldRunnerOrganisation.id != runnerOrganisation.id) { + throw new RunnerOrganisationIdsNotMatchingError(); + } + + await this.runnerOrganisationRepository.update(oldRunnerOrganisation, runnerOrganisation); + return runnerOrganisation; + } + + @Delete('/:id') + @ResponseSchema(RunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: 'Delete a specified runnerOrganisation (if it exists).' }) + async remove(@Param('id') id: number) { + let runnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id }); + + if (!runnerOrganisation) { + throw new RunnerOrganisationNotFoundError(); + } + + await this.runnerOrganisationRepository.delete(runnerOrganisation); + return runnerOrganisation; + } +} diff --git a/src/errors/RunnerOrganisationErrors.ts b/src/errors/RunnerOrganisationErrors.ts new file mode 100644 index 0000000..f846ffa --- /dev/null +++ b/src/errors/RunnerOrganisationErrors.ts @@ -0,0 +1,27 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers'; +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; + +/** + * Error to throw when a runner couldn't be found. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerOrganisationNotFoundError extends NotFoundError { + @IsString() + name = "RunnerOrganisationNotFoundError" + + @IsString() + message = "RunnerOrganisation not found!" +} + +/** + * Error to throw when two runners' ids don't match. + * Usually occurs when a user tries to change a runner's id. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerOrganisationIdsNotMatchingError extends NotAcceptableError { + @IsString() + name = "RunnerOrganisationIdsNotMatchingError" + + @IsString() + message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" +} \ No newline at end of file diff --git a/src/models/CreateRunnerOrganisation.ts b/src/models/CreateRunnerOrganisation.ts new file mode 100644 index 0000000..b7e5c71 --- /dev/null +++ b/src/models/CreateRunnerOrganisation.ts @@ -0,0 +1,15 @@ +import { IsString } from 'class-validator'; +import { RunnerOrganisation } from './RunnerOrganisation'; + +export class CreateRunnerOrganisation { + @IsString() + name: string; + + public async toRunnerOrganisation(): Promise { + let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation(); + + newRunnerOrganisation.name = this.name; + + return newRunnerOrganisation; + } +} \ No newline at end of file From af75d6cfec13131f2980cc83866eb3d6b024b9e0 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 19:22:32 +0100 Subject: [PATCH 17/22] Formatting --- src/models/RunnerOrganisation.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/models/RunnerOrganisation.ts b/src/models/RunnerOrganisation.ts index 4245fa0..f266599 100644 --- a/src/models/RunnerOrganisation.ts +++ b/src/models/RunnerOrganisation.ts @@ -1,5 +1,5 @@ import { Entity, Column, ManyToOne, OneToMany } from "typeorm"; -import { IsOptional,} from "class-validator"; +import { IsOptional, } from "class-validator"; import { RunnerGroup } from "./RunnerGroup"; import { Address } from "./Address"; import { RunnerTeam } from "./RunnerTeam"; @@ -18,9 +18,9 @@ export class RunnerOrganisation extends RunnerGroup { @ManyToOne(() => Address, address => address.groups, { nullable: true }) address?: Address; - /** - * Used to link teams to runner groups. - */ + /** + * Used to link teams to runner groups. + */ @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true }) teams: RunnerTeam[]; } \ No newline at end of file From ec2ff981b217e460e4547b57a1ad069059d13b7d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 19:25:02 +0100 Subject: [PATCH 18/22] Now creating runner orgs again ref #13 --- src/controllers/RunnerOrganisationController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/RunnerOrganisationController.ts b/src/controllers/RunnerOrganisationController.ts index 6297073..1575ef0 100644 --- a/src/controllers/RunnerOrganisationController.ts +++ b/src/controllers/RunnerOrganisationController.ts @@ -11,13 +11,13 @@ import { RunnerGroup } from '../models/RunnerGroup'; @JsonController('/organisations') //@Authorized('RUNNERS:read') export class RunnerOrganisationController { - private runnerOrganisationRepository: Repository; + private runnerOrganisationRepository: Repository; /** * Gets the repository of this controller's model/entity. */ constructor() { - this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerGroup); + this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerOrganisation); } @Get() From 32c4270dff0c3e1a9703e72b8b180a7289d413d4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 20:19:58 +0100 Subject: [PATCH 19/22] Attention: Broken --- src/models/RunnerGroup.ts | 3 ++- src/models/RunnerTeam.ts | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/models/RunnerGroup.ts b/src/models/RunnerGroup.ts index 2cd3694..8142754 100644 --- a/src/models/RunnerGroup.ts +++ b/src/models/RunnerGroup.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsInt, IsNotEmpty, @@ -13,6 +13,7 @@ import { RunnerTeam } from "./RunnerTeam"; * Defines the runnerGroup interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class RunnerGroup { /** * Autogenerated unique id (primary key). diff --git a/src/models/RunnerTeam.ts b/src/models/RunnerTeam.ts index 5adc60d..2a474ad 100644 --- a/src/models/RunnerTeam.ts +++ b/src/models/RunnerTeam.ts @@ -1,12 +1,12 @@ -import { Entity, Column, ManyToOne } from "typeorm"; -import { IsNotEmpty } from "class-validator"; +import { Entity, Column, ManyToOne, ChildEntity } from "typeorm"; +import { IsOptional } from "class-validator"; import { RunnerGroup } from "./RunnerGroup"; import { RunnerOrganisation } from "./RunnerOrganisation"; /** * Defines a runner team (class or deparment for example). */ -@Entity() +@ChildEntity() export class RunnerTeam extends RunnerGroup { /** From 5bbf522362a8985e93b16884369f5859ab72d32a Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 20:23:56 +0100 Subject: [PATCH 20/22] Fixed missing child declaration --- src/models/RunnerOrganisation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/RunnerOrganisation.ts b/src/models/RunnerOrganisation.ts index f266599..b0a7220 100644 --- a/src/models/RunnerOrganisation.ts +++ b/src/models/RunnerOrganisation.ts @@ -1,4 +1,4 @@ -import { Entity, Column, ManyToOne, OneToMany } from "typeorm"; +import { Entity, Column, ManyToOne, OneToMany, ChildEntity } from "typeorm"; import { IsOptional, } from "class-validator"; import { RunnerGroup } from "./RunnerGroup"; import { Address } from "./Address"; @@ -7,7 +7,7 @@ import { RunnerTeam } from "./RunnerTeam"; /** * Defines a runner organisation (business or school for example). */ -@Entity() +@ChildEntity() export class RunnerOrganisation extends RunnerGroup { /** From e3133e0d5eb70daf858a6b807970838db8fd0ef9 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 20:24:43 +0100 Subject: [PATCH 21/22] Added missing import --- src/models/RunnerTeam.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/RunnerTeam.ts b/src/models/RunnerTeam.ts index 2a474ad..a9fb2f0 100644 --- a/src/models/RunnerTeam.ts +++ b/src/models/RunnerTeam.ts @@ -1,5 +1,5 @@ import { Entity, Column, ManyToOne, ChildEntity } from "typeorm"; -import { IsOptional } from "class-validator"; +import { IsNotEmpty } from "class-validator"; import { RunnerGroup } from "./RunnerGroup"; import { RunnerOrganisation } from "./RunnerOrganisation"; From a8956223c2c70b810b4ec9dea09900b30b963a24 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Thu, 3 Dec 2020 20:28:07 +0100 Subject: [PATCH 22/22] Emergency fix: Switched to table inheritances ref #11 #13 --- src/models/DistanceDonation.ts | 6 +++--- src/models/Donation.ts | 3 ++- src/models/Donor.ts | 4 ++-- src/models/FixedDonation.ts | 6 +++--- src/models/Participant.ts | 9 +++++---- src/models/Runner.ts | 14 +++++++------- src/models/Scan.ts | 11 ++++++----- src/models/TrackScan.ts | 4 ++-- 8 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/models/DistanceDonation.ts b/src/models/DistanceDonation.ts index 79bf0b8..b54c642 100644 --- a/src/models/DistanceDonation.ts +++ b/src/models/DistanceDonation.ts @@ -1,5 +1,5 @@ -import { Entity, Column, ManyToOne } from "typeorm"; -import { IsInt, IsNotEmpty, IsPositive,} from "class-validator"; +import { Entity, Column, ManyToOne, ChildEntity } from "typeorm"; +import { IsInt, IsNotEmpty, IsPositive, } from "class-validator"; import { Donation } from "./Donation"; import { Runner } from "./Runner"; @@ -7,7 +7,7 @@ import { Runner } from "./Runner"; * Defines a distance based donation. * Here people donate a certain amout per kilometer */ -@Entity() +@ChildEntity() export class DistanceDonation extends Donation { /** * The runner associated. diff --git a/src/models/Donation.ts b/src/models/Donation.ts index b94e182..c4ab699 100644 --- a/src/models/Donation.ts +++ b/src/models/Donation.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsInt, IsNotEmpty, @@ -11,6 +11,7 @@ import { Participant } from "./Participant"; * Defines the donation interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Donation { /** * Autogenerated unique id (primary key). diff --git a/src/models/Donor.ts b/src/models/Donor.ts index 5d0af07..ca65afd 100644 --- a/src/models/Donor.ts +++ b/src/models/Donor.ts @@ -1,11 +1,11 @@ -import { Entity, Column } from "typeorm"; +import { Entity, Column, ChildEntity } from "typeorm"; import { IsBoolean } from "class-validator"; import { Participant } from "./Participant"; /** * Defines a donor. */ -@Entity() +@ChildEntity() export class Donor extends Participant { /** * Does this donor need a receipt?. diff --git a/src/models/FixedDonation.ts b/src/models/FixedDonation.ts index e429ddf..dd05c40 100644 --- a/src/models/FixedDonation.ts +++ b/src/models/FixedDonation.ts @@ -1,11 +1,11 @@ -import { Entity, Column } from "typeorm"; -import { IsInt, IsPositive,} from "class-validator"; +import { Entity, Column, ChildEntity } from "typeorm"; +import { IsInt, IsPositive, } from "class-validator"; import { Donation } from "./Donation"; /** * Defines a fixed donation. */ -@Entity() +@ChildEntity() export class FixedDonation extends Donation { /** diff --git a/src/models/Participant.ts b/src/models/Participant.ts index e80d348..53562a3 100644 --- a/src/models/Participant.ts +++ b/src/models/Participant.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsEmail, IsInt, @@ -15,6 +15,7 @@ import { Donation } from "./Donation"; * Defines the participant interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Participant { /** * Autogenerated unique id (primary key). @@ -36,7 +37,7 @@ export abstract class Participant { * The participant's middle name. * Optional */ - @Column({nullable: true}) + @Column({ nullable: true }) @IsOptional() @IsString() middlename?: string; @@ -60,7 +61,7 @@ export abstract class Participant { * The participant's phone number. * Optional */ - @Column({nullable: true}) + @Column({ nullable: true }) @IsOptional() @IsPhoneNumber("DE") phone?: string; @@ -69,7 +70,7 @@ export abstract class Participant { * The participant's email address. * Optional */ - @Column({nullable: true}) + @Column({ nullable: true }) @IsOptional() @IsEmail() email?: string; diff --git a/src/models/Runner.ts b/src/models/Runner.ts index 7423c22..e4d3ff7 100644 --- a/src/models/Runner.ts +++ b/src/models/Runner.ts @@ -1,5 +1,5 @@ -import { Entity, Column, OneToMany, ManyToOne } from "typeorm"; -import { IsInt, IsNotEmpty,} from "class-validator"; +import { Entity, Column, OneToMany, ManyToOne, ChildEntity } from "typeorm"; +import { IsInt, IsNotEmpty, } from "class-validator"; import { Participant } from "./Participant"; import { RunnerGroup } from "./RunnerGroup"; import { DistanceDonation } from "./DistanceDonation"; @@ -9,7 +9,7 @@ import { Scan } from "./Scan"; /** * Defines a runner. */ -@Entity() +@ChildEntity() export class Runner extends Participant { /** * The runner's associated group. @@ -17,7 +17,7 @@ export class Runner extends Participant { @IsNotEmpty() @ManyToOne(() => RunnerGroup, group => group.runners, { nullable: true }) group: RunnerGroup; - + /** * Used to link runners to donations. */ @@ -36,9 +36,9 @@ export class Runner extends Participant { @OneToMany(() => Scan, scan => scan.runner, { nullable: true }) scans: Scan[]; - @IsInt() - public get distance() : number { + @IsInt() + public get distance(): number { return this.scans.filter(scan => scan.valid === true).reduce((sum, current) => sum + current.distance, 0); } - + } diff --git a/src/models/Scan.ts b/src/models/Scan.ts index 3fd64ed..9911fec 100644 --- a/src/models/Scan.ts +++ b/src/models/Scan.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsBoolean, IsInt, @@ -12,6 +12,7 @@ import { Runner } from "./Runner"; * Defines the scan interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Scan { /** * Autogenerated unique id (primary key). @@ -35,10 +36,10 @@ export abstract class Scan { @IsPositive() abstract distance: number; - /** - * Is the scan valid (for fraud reasons). - * Default: true - */ + /** + * Is the scan valid (for fraud reasons). + * Default: true + */ @Column() @IsBoolean() valid: boolean = true; diff --git a/src/models/TrackScan.ts b/src/models/TrackScan.ts index ae0467c..f7bee32 100644 --- a/src/models/TrackScan.ts +++ b/src/models/TrackScan.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, ChildEntity } from "typeorm"; import { IsBoolean, IsDateString, @@ -16,7 +16,7 @@ import { ScanStation } from "./ScanStation"; /** * Defines the scan interface. */ -@Entity() +@ChildEntity() export class TrackScan extends Scan { /** * The associated track.