From 72b5ca415340d96649ecce943d19f0e0b2b82fda Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Wed, 6 Jan 2021 19:44:20 +0100 Subject: [PATCH] Added basics for scan creation (to be tested after scanstations got added) ref #67 --- src/controllers/ScanController.ts | 29 ++++----- src/models/actions/CreateScan.ts | 11 ++++ src/models/actions/CreateTrackScan.ts | 84 +++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 src/models/actions/CreateScan.ts create mode 100644 src/models/actions/CreateTrackScan.ts diff --git a/src/controllers/ScanController.ts b/src/controllers/ScanController.ts index 6127e8a..fb99d3a 100644 --- a/src/controllers/ScanController.ts +++ b/src/controllers/ScanController.ts @@ -1,7 +1,8 @@ -import { Authorized, Get, JsonController, OnUndefined, Param } from 'routing-controllers'; +import { Authorized, Body, Get, JsonController, OnUndefined, Param, Post } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { ScanNotFoundError } from '../errors/ScanErrors'; +import { CreateScan } from '../models/actions/CreateScan'; import { Scan } from '../models/entities/Scan'; import { ResponseScan } from '../models/responses/ResponseScan'; import { ResponseTrackScan } from '../models/responses/ResponseTrackScan'; @@ -33,7 +34,7 @@ export class ScanController { } @Get('/:id') - @Authorized("DONOR:GET") + @Authorized("SCAN:GET") @ResponseSchema(ResponseScan) @ResponseSchema(ResponseTrackScan) @ResponseSchema(ScanNotFoundError, { statusCode: 404 }) @@ -45,21 +46,15 @@ export class ScanController { return scan; } - // @Post() - // @Authorized("DONOR:CREATE") - // @ResponseSchema(ResponseDonor) - // @OpenAPI({ description: 'Create a new runner.
Please remeber to provide the runner\'s group\'s id.' }) - // async post(@Body({ validate: true }) createRunner: CreateDonor) { - // let donor; - // try { - // donor = await createRunner.toDonor(); - // } catch (error) { - // throw error; - // } - - // donor = await this.donorRepository.save(donor) - // return new ResponseDonor(await this.donorRepository.findOne(donor)); - // } + @Post() + @Authorized("SCAN:CREATE") + @ResponseSchema(ResponseScan) + @OpenAPI({ description: 'Create a new runner.
Please remeber to provide the runner\'s group\'s id.' }) + async post(@Body({ validate: true }) createScan: CreateScan) { + let scan = await createScan.toScan(); + scan = await this.scanRepository.save(scan) + return (await this.scanRepository.findOne(scan)).toResponse(); + } // @Put('/:id') // @Authorized("DONOR:UPDATE") diff --git a/src/models/actions/CreateScan.ts b/src/models/actions/CreateScan.ts new file mode 100644 index 0000000..170703b --- /dev/null +++ b/src/models/actions/CreateScan.ts @@ -0,0 +1,11 @@ +import { Scan } from '../entities/Scan'; + +/** + * This classed is used to create a new Scan entity from a json body (post request). + */ +export abstract class CreateScan { + /** + * Creates a new Scan entity from this. + */ + public abstract toScan(): Promise; +} \ No newline at end of file diff --git a/src/models/actions/CreateTrackScan.ts b/src/models/actions/CreateTrackScan.ts new file mode 100644 index 0000000..2303352 --- /dev/null +++ b/src/models/actions/CreateTrackScan.ts @@ -0,0 +1,84 @@ +import { IsNotEmpty } from 'class-validator'; +import { getConnection } from 'typeorm'; +import { RunnerNotFoundError } from '../../errors/RunnerErrors'; +import { RunnerCard } from '../entities/RunnerCard'; +import { ScanStation } from '../entities/ScanStation'; +import { TrackScan } from '../entities/TrackScan'; +import { CreateScan } from './CreateScan'; + +/** + * This classed is used to create a new Scan entity from a json body (post request). + */ +export class CreateTrackScan extends CreateScan { + + /** + * The scan's associated track. + * This is used to determine the scan's distance. + */ + @IsNotEmpty() + track: number; + + /** + * The runnerCard associated with the scan. + * This get's saved for documentation and management purposes. + */ + @IsNotEmpty() + card: number; + + /** + * The scanning station that created the scan. + * Mainly used for logging and traceing back scans (or errors) + */ + @IsNotEmpty() + station: number; + + /** + * Creates a new Track entity from this. + */ + public async toScan(): Promise { + let newScan: TrackScan = new TrackScan(); + + newScan.station = await this.getStation(); + newScan.card = await this.getCard(); + + newScan.track = newScan.station.track; + newScan.runner = newScan.card.runner; + + if (!newScan.runner) { + throw new RunnerNotFoundError(); + } + + newScan.timestamp = new Date(Date.now()).toString(); + newScan.valid = await this.validateScan(newScan); + + return newScan; + } + + public async getCard(): Promise { + const track = await getConnection().getRepository(RunnerCard).findOne({ id: this.card }, { relations: ["runner"] }); + if (!track) { + throw new Error(); + } + return track; + } + + public async getStation(): Promise { + const track = await getConnection().getRepository(ScanStation).findOne({ id: this.card }, { relations: ["track"] }); + if (!track) { + throw new Error(); + } + return track; + } + + public async validateScan(scan: TrackScan): Promise { + const scans = await getConnection().getRepository(TrackScan).find({ where: { runner: scan.runner }, relations: ["track"] }); + if (scans.length == 0) { return true; } + + const newestScan = scans[0]; + if ((new Date(scan.timestamp).getTime() - new Date(newestScan.timestamp).getTime()) > scan.track.minimumLapTime) { + return true; + } + + return false; + } +} \ No newline at end of file