import { Authorized, BadRequestError, 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 { RunnerOrganizationHasRunnersError, RunnerOrganizationHasTeamsError, RunnerOrganizationIdsNotMatchingError, RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors'; import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization'; import { UpdateRunnerOrganization } from '../models/actions/update/UpdateRunnerOrganization'; import { Runner } from '../models/entities/Runner'; import { RunnerOrganization } from '../models/entities/RunnerOrganization'; import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseRunner } from '../models/responses/ResponseRunner'; import { ResponseRunnerOrganization } from '../models/responses/ResponseRunnerOrganization'; import { RunnerController } from './RunnerController'; import { RunnerTeamController } from './RunnerTeamController'; @JsonController('/organizations') @OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) export class RunnerOrganizationController { private runnerOrganizationRepository: Repository; /** * Gets the repository of this controller's model/entity. */ constructor() { this.runnerOrganizationRepository = getConnectionManager().get().getRepository(RunnerOrganization); } @Get() @Authorized("ORGANIZATION:GET") @ResponseSchema(ResponseRunnerOrganization, { isArray: true }) @OpenAPI({ description: 'Lists all organizations.
This includes their address, contact and teams (if existing/associated).' }) async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) { let responseOrgs: ResponseRunnerOrganization[] = new Array(); let orgs: Array; if (page) { orgs = await this.runnerOrganizationRepository.find({ relations: ['contact', 'teams'], skip: page * page_size, take: page_size }); } else { orgs = await this.runnerOrganizationRepository.find({ relations: ['contact', 'teams'] }); } orgs.forEach(org => { responseOrgs.push(new ResponseRunnerOrganization(org)); }); return responseOrgs; } @Get('/:id') @Authorized("ORGANIZATION:GET") @ResponseSchema(ResponseRunnerOrganization) @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 }) @OnUndefined(RunnerOrganizationNotFoundError) @OpenAPI({ description: 'Lists all information about the organization whose id got provided.' }) async getOne(@Param('id') id: number) { let runnerOrg = await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['contact', 'teams'] }); if (!runnerOrg) { throw new RunnerOrganizationNotFoundError(); } return new ResponseRunnerOrganization(runnerOrg); } @Get('/:id/runners') @Authorized(["RUNNER:GET", "SCAN:GET"]) @ResponseSchema(ResponseRunner, { isArray: true }) @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 }) @OpenAPI({ description: 'Lists all runners from this org and it\'s teams (if you don\'t provide the ?onlyDirect=true param).
This includes the runner\'s group and distance ran.' }) async getRunners(@Param('id') id: number, @QueryParam('onlyDirect') onlyDirect: boolean) { let responseRunners: ResponseRunner[] = new Array(); let runners: Runner[]; if (!onlyDirect) { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.group', 'teams.runners.group.parentGroup', 'teams.runners.scans', 'teams.runners.scans.track'] })).allRunners; } else { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners; } runners.forEach(runner => { responseRunners.push(new ResponseRunner(runner)); }); return responseRunners; } @Post() @Authorized("ORGANIZATION:CREATE") @ResponseSchema(ResponseRunnerOrganization) @OpenAPI({ description: 'Create a new organsisation.' }) async post(@Body({ validate: true }) createRunnerOrganization: CreateRunnerOrganization) { let runnerOrganization; try { runnerOrganization = await createRunnerOrganization.toEntity(); } catch (error) { throw error; } runnerOrganization = await this.runnerOrganizationRepository.save(runnerOrganization); return new ResponseRunnerOrganization(await this.runnerOrganizationRepository.findOne(runnerOrganization, { relations: ['contact', 'teams'] })); } @Put('/:id') @Authorized("ORGANIZATION:UPDATE") @ResponseSchema(ResponseRunnerOrganization) @ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerOrganizationIdsNotMatchingError, { statusCode: 406 }) @OpenAPI({ description: "Update the organization whose id you provided.
Please remember that ids can't be changed." }) async put(@Param('id') id: number, @Body({ validate: true }) updateOrganization: UpdateRunnerOrganization) { let oldRunnerOrganization = await this.runnerOrganizationRepository.findOne({ id: id }); if (!oldRunnerOrganization) { throw new RunnerOrganizationNotFoundError(); } if (oldRunnerOrganization.id != updateOrganization.id) { throw new RunnerOrganizationIdsNotMatchingError(); } await this.runnerOrganizationRepository.save(await updateOrganization.update(oldRunnerOrganization)); return new ResponseRunnerOrganization(await this.runnerOrganizationRepository.findOne(id, { relations: ['contact', 'teams'] })); } @Delete('/:id') @Authorized("ORGANIZATION:DELETE") @ResponseSchema(ResponseRunnerOrganization) @ResponseSchema(ResponseEmpty, { statusCode: 204 }) @ResponseSchema(RunnerOrganizationHasTeamsError, { statusCode: 406 }) @ResponseSchema(RunnerOrganizationHasRunnersError, { statusCode: 406 }) @OnUndefined(204) @OpenAPI({ description: 'Delete the organsisation whose id you provided.
If the organization still has runners and/or teams associated this will fail.
To delete the organization with all associated runners and teams set the force QueryParam to true (cascading deletion might take a while).
This won\'t delete the associated contact.
If no organization with this id exists it will just return 204(no content).' }) async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { if (id == 1) { throw new BadRequestError("You can't delete the citizen runner org."); } let organization = await this.runnerOrganizationRepository.findOne({ id: id }); if (!organization) { return null; } let runnerOrganization = await this.runnerOrganizationRepository.findOne(organization, { relations: ['contact', 'runners', 'teams'] }); if (!force) { if (runnerOrganization.teams.length != 0) { throw new RunnerOrganizationHasTeamsError(); } } const teamController = new RunnerTeamController() for (let team of runnerOrganization.teams) { await teamController.remove(team.id, true); } if (!force) { if (runnerOrganization.runners.length != 0) { throw new RunnerOrganizationHasRunnersError(); } } const runnerController = new RunnerController() for (let runner of runnerOrganization.runners) { await runnerController.remove(runner.id, true); } const responseOrganization = new ResponseRunnerOrganization(runnerOrganization); await this.runnerOrganizationRepository.delete(organization); return responseOrganization; } }