import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Repository, getConnectionManager } from 'typeorm'; import { RunnerGroupNeededError, RunnerHasDistanceDonationsError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; import { CreateRunner } from '../models/actions/create/CreateRunner'; import { UpdateRunner } from '../models/actions/update/UpdateRunner'; import { Runner } from '../models/entities/Runner'; import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseRunner } from '../models/responses/ResponseRunner'; import { ResponseScan } from '../models/responses/ResponseScan'; import { ResponseTrackScan } from '../models/responses/ResponseTrackScan'; import { DonationController } from './DonationController'; import { RunnerCardController } from './RunnerCardController'; import { ScanController } from './ScanController'; @JsonController('/runners') @OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) export class RunnerController { private runnerRepository: Repository; /** * Gets the repository of this controller's model/entity. */ constructor() { this.runnerRepository = getConnectionManager().get().getRepository(Runner); } @Get() @Authorized("RUNNER:GET") @ResponseSchema(ResponseRunner, { isArray: true }) @OpenAPI({ description: 'Lists all runners from all teams/orgs.
This includes the runner\'s group and distance ran.' }) async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) { let responseRunners: ResponseRunner[] = new Array(); let runners: Array; if (page != undefined) { runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track'], skip: page * page_size, take: page_size }); } else { runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track'] }); } runners.forEach(runner => { responseRunners.push(new ResponseRunner(runner)); }); return responseRunners; } @Get('/:id') @Authorized("RUNNER:GET") @ResponseSchema(ResponseRunner) @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) @OnUndefined(RunnerNotFoundError) @OpenAPI({ description: 'Lists all information about the runner whose id got provided.' }) async getOne(@Param('id') id: number) { let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }) if (!runner) { throw new RunnerNotFoundError(); } return new ResponseRunner(runner); } @Get('/:id/scans') @Authorized(["RUNNER:GET", "SCAN:GET"]) @ResponseSchema(ResponseScan, { isArray: true }) @ResponseSchema(ResponseTrackScan, { isArray: true }) @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) @OpenAPI({ description: 'Lists all scans of the runner whose id got provided.
If you only want the valid scans just add the ?onlyValid=true query param.' }) async getScans(@Param('id') id: number, onlyValid?: boolean) { let responseScans: ResponseScan[] = new Array(); let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'scans.track', 'scans.station', 'scans.runner'] }) if (!runner) { throw new RunnerNotFoundError(); } if (!onlyValid) { for (let scan of runner.scans) { responseScans.push(scan.toResponse()); } } else { for (let scan of runner.validScans) { responseScans.push(scan.toResponse()); } } return responseScans; } @Post() @Authorized("RUNNER:CREATE") @ResponseSchema(ResponseRunner) @ResponseSchema(RunnerGroupNeededError) @ResponseSchema(RunnerGroupNotFoundError) @OpenAPI({ description: 'Create a new runner.
Please remeber to provide the runner\'s group\'s id.' }) async post(@Body({ validate: true }) createRunner: CreateRunner) { let runner; try { runner = await createRunner.toEntity(); } catch (error) { throw error; } runner = await this.runnerRepository.save(runner) return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] })); } @Put('/:id') @Authorized("RUNNER:UPDATE") @ResponseSchema(ResponseRunner) @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerIdsNotMatchingError, { statusCode: 406 }) @OpenAPI({ description: "Update the runner whose id you provided.
Please remember that ids can't be changed." }) async put(@Param('id') id: number, @Body({ validate: true }) runner: UpdateRunner) { let oldRunner = await this.runnerRepository.findOne({ id: id }, { relations: ['group'] }); if (!oldRunner) { throw new RunnerNotFoundError(); } if (oldRunner.id != runner.id) { throw new RunnerIdsNotMatchingError(); } await this.runnerRepository.save(await runner.update(oldRunner)); return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] })); } @Delete('/:id') @Authorized("RUNNER:DELETE") @ResponseSchema(ResponseRunner) @ResponseSchema(ResponseEmpty, { statusCode: 204 }) @ResponseSchema(RunnerHasDistanceDonationsError, { statusCode: 406 }) @OnUndefined(204) @OpenAPI({ description: 'Delete the runner whose id you provided.
This will also delete all scans and cards associated with the runner.
If no runner with this id exists it will just return 204(no content).' }) async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { let runner = await this.runnerRepository.findOne({ id: id }); if (!runner) { return null; } const responseRunner = await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }); if (!runner) { throw new RunnerNotFoundError(); } const runnerDonations = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["distanceDonations"] })).distanceDonations; if (runnerDonations.length > 0 && !force) { throw new RunnerHasDistanceDonationsError(); } const donationController = new DonationController(); for (let donation of runnerDonations) { await donationController.remove(donation.id, force); } const runnerCards = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["cards"] })).cards; const cardController = new RunnerCardController; for (let card of runnerCards) { await cardController.remove(card.id, force); } const runnerScans = (await this.runnerRepository.findOne({ id: runner.id }, { relations: ["scans"] })).scans; const scanController = new ScanController; for (let scan of runnerScans) { await scanController.remove(scan.id, force); } await this.runnerRepository.delete(runner); return new ResponseRunner(responseRunner); } }