import { IsInt, IsOptional, IsPositive } from 'class-validator'; import { BadRequestError } from 'routing-controllers'; import { getConnection } from 'typeorm'; import { RunnerCardNotFoundError } from '../../../errors/RunnerCardErrors'; import { RunnerNotFoundError } from '../../../errors/RunnerErrors'; import { ScanStationNotFoundError } from '../../../errors/ScanStationErrors'; import { RunnerCard } from '../../entities/RunnerCard'; import { ScanStation } from '../../entities/ScanStation'; import { TrackScan } from '../../entities/TrackScan'; /** * This classed is used to create a new Scan entity from a json body (post request). */ export class CreateTrackScan { /** * The id of the runnerCard associated with the scan. * This get's saved for documentation and management purposes. */ @IsInt() @IsPositive() card: number; /** * The scanning station's id that created the scan. * Mainly used for logging and traceing back scans (or errors). * You don't have to provide the station if you're authenticateing via a scanstation token (The server takes care of it for you). */ @IsInt() @IsPositive() @IsOptional() station?: number; /** * Creates a new Track entity from this. */ public async toEntity(): 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 = Math.round(new Date().getTime() / 1000); newScan = await this.validateScan(newScan); return newScan; } /** * Get's a runnerCard entity via the provided id. * @returns The runnerCard whom's id you provided. */ public async getCard(): Promise { const id = this.card % 200000000000; const runnerCard = await getConnection().getRepository(RunnerCard).findOne({ id: id }, { relations: ["runner"] }); if (!runnerCard) { throw new RunnerCardNotFoundError(); } return runnerCard; } /** * Get's a scanstation entity via the provided id. * @returns The scanstation whom's id you provided. */ public async getStation(): Promise { if (!this.station) { throw new BadRequestError("You are missing the station's id!") } const station = await getConnection().getRepository(ScanStation).findOne({ id: this.station }, { relations: ["track"] }); if (!station) { throw new ScanStationNotFoundError(); } return station; } /** * Validates the scan and sets it's lap time; * @param scan The scan you want to validate * @returns The validated scan with it's laptime set. */ public async validateScan(scan: TrackScan): Promise { const latestScan = await getConnection().getRepository(TrackScan).findOne({ where: { runner: scan.runner, valid: true }, relations: ["track"], order: { id: 'DESC' } }); if (!latestScan) { scan.lapTime = 0; scan.valid = true; } else { scan.lapTime = scan.timestamp - latestScan.timestamp; scan.valid = (scan.lapTime > scan.track.minimumLapTime); } return scan; } }