From 36ecae7e6e1eda637bafbc260d3dfa5815a472ff Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 9 Jan 2021 11:48:13 +0100 Subject: [PATCH] Added card creation #17 --- src/controllers/RunnerCardController.ts | 25 ++++++------ src/models/actions/CreateRunnerCard.ts | 45 ++++++++++++++++++++++ src/models/entities/RunnerCard.ts | 26 ++++++------- src/models/responses/ResponseRunnerCard.ts | 5 ++- 4 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 src/models/actions/CreateRunnerCard.ts diff --git a/src/controllers/RunnerCardController.ts b/src/controllers/RunnerCardController.ts index a11b626..a1eee62 100644 --- a/src/controllers/RunnerCardController.ts +++ b/src/controllers/RunnerCardController.ts @@ -1,7 +1,9 @@ -import { Authorized, Delete, Get, JsonController, OnUndefined, Param, QueryParam } from 'routing-controllers'; +import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, QueryParam } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { RunnerCardHasScansError, RunnerCardNotFoundError } from '../errors/RunnerCardErrors'; +import { RunnerNotFoundError } from '../errors/RunnerErrors'; +import { CreateRunnerCard } from '../models/actions/CreateRunnerCard'; import { RunnerCard } from '../models/entities/RunnerCard'; import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseRunnerCard } from '../models/responses/ResponseRunnerCard'; @@ -44,17 +46,16 @@ export class RunnerCardController { return card.toResponse(); } - // @Post() - // @Authorized("CARD:CREATE") - // @ResponseSchema(ResponseTrack) - // @ResponseSchema(TrackLapTimeCantBeNegativeError, { statusCode: 406 }) - // @OpenAPI({ description: "Create a new track.
Please remember that the track\'s distance must be greater than 0." }) - // async post( - // @Body({ validate: true }) - // track: CreateTrack - // ) { - // return new ResponseTrack(await this.trackRepository.save(track.toTrack())); - // } + @Post() + @Authorized("CARD:CREATE") + @ResponseSchema(ResponseRunnerCard) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: "Create a new card.
You can provide a associated runner by id but you don't have to." }) + async post(@Body({ validate: true }) createCard: CreateRunnerCard) { + let card = await createCard.toEntity(); + card = await this.cardRepository.save(card); + return (await this.cardRepository.findOne({ id: card.id }, { relations: ['runner'] })).toResponse(); + } // @Put('/:id') // @Authorized("CARD:UPDATE") diff --git a/src/models/actions/CreateRunnerCard.ts b/src/models/actions/CreateRunnerCard.ts new file mode 100644 index 0000000..2baf1e9 --- /dev/null +++ b/src/models/actions/CreateRunnerCard.ts @@ -0,0 +1,45 @@ +import { IsBoolean, IsInt, IsOptional } from 'class-validator'; +import { getConnection } from 'typeorm'; +import { RunnerNotFoundError } from '../../errors/RunnerErrors'; +import { Runner } from '../entities/Runner'; +import { RunnerCard } from '../entities/RunnerCard'; + +/** + * This classed is used to create a new RunnerCard entity from a json body (post request). + */ +export class CreateRunnerCard { + /** + * The card's associated runner. + */ + @IsInt() + @IsOptional() + runner?: number; + + /** + * Is the new card enabled (for fraud reasons)? + * Default: true + */ + @IsBoolean() + enabled: boolean = true; + + /** + * Creates a new RunnerCard entity from this. + */ + public async toEntity(): Promise { + let newCard: RunnerCard = new RunnerCard(); + + newCard.enabled = this.enabled; + newCard.runner = await this.getRunner(); + + return newCard; + } + + public async getRunner(): Promise { + if (!this.runner) { return null; } + const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner }); + if (!runner) { + throw new RunnerNotFoundError(); + } + return runner; + } +} \ No newline at end of file diff --git a/src/models/entities/RunnerCard.ts b/src/models/entities/RunnerCard.ts index 25ce61c..0517008 100644 --- a/src/models/entities/RunnerCard.ts +++ b/src/models/entities/RunnerCard.ts @@ -1,10 +1,9 @@ import { IsBoolean, - IsEAN, + IsInt, - IsNotEmpty, - IsOptional, - IsString + + IsOptional } from "class-validator"; import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import { ResponseRunnerCard } from '../responses/ResponseRunnerCard'; @@ -33,17 +32,6 @@ export class RunnerCard { @ManyToOne(() => Runner, runner => runner.cards, { nullable: true }) runner: Runner; - /** - * The card's code. - * This has to be able to being converted to something barcode compatible. - * Will get automaticlly generated (not implemented yet). - */ - @Column() - @IsEAN() - @IsString() - @IsNotEmpty() - code: string; - /** * Is the card enabled (for fraud reasons)? * Default: true @@ -59,6 +47,14 @@ export class RunnerCard { @OneToMany(() => TrackScan, scan => scan.track, { nullable: true }) scans: TrackScan[]; + /** + * Generates a ean-13 compliant string for barcode generation. + */ + public get code(): string { + //TODO: Implement the real deal + return '0000000000000' + } + /** * Turns this entity into it's response class. */ diff --git a/src/models/responses/ResponseRunnerCard.ts b/src/models/responses/ResponseRunnerCard.ts index 94c7148..97b9435 100644 --- a/src/models/responses/ResponseRunnerCard.ts +++ b/src/models/responses/ResponseRunnerCard.ts @@ -17,7 +17,7 @@ export class ResponseRunnerCard { * This is important to link scans to runners. */ @IsObject() - runner: ResponseRunner; + runner: ResponseRunner | null; /** * The card's code. @@ -40,7 +40,8 @@ export class ResponseRunnerCard { */ public constructor(card: RunnerCard) { this.id = card.id; - this.runner = card.runner.toResponse() || null; + if (!card.runner) { this.runner = null } + else { this.runner = card.runner.toResponse(); } this.code = card.code; this.enabled = card.enabled; }