diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..91a2d2c --- /dev/null +++ b/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; \ No newline at end of file diff --git a/ormconfig.ts b/ormconfig.ts index bf9be07..377a7e8 100644 --- a/ormconfig.ts +++ b/ormconfig.ts @@ -1,12 +1,12 @@ -import { config } from 'dotenv'; -config(); - -export default { - type: process.env.DB_TYPE, - host: process.env.DB_HOST, - port: process.env.DB_PORT, - username: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_NAME, - entities: ["src/models/entities/*.ts"] -}; +import { config } from 'dotenv'; +config(); + +export default { + type: process.env.DB_TYPE, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + username: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + entities: ["src/models/entities/*.ts"] +}; diff --git a/package.json b/package.json index baae298..b59be18 100644 --- a/package.json +++ b/package.json @@ -1,67 +1,81 @@ -{ - "name": "@lfk/backend", - "version": "1.0.0", - "main": "src/app.ts", - "repository": "https://git.odit.services/lfk/backend", - "author": { - "name": "ODIT.Services", - "email": "info@odit.services", - "url": "https://odit.services" - }, - "contributors": [ - { - "name": "Philipp Dormann", - "email": "philipp@philippdormann.de", - "url": "https://philippdormann.de" - }, - { - "name": "Nicolai Ort", - "email": "info@nicolai-ort.com", - "url": "https://nicolai-ort.com" - } - ], - "license": "CC-BY-NC-SA-4.0", - "dependencies": { - "argon2": "^0.27.0", - "body-parser": "^1.19.0", - "class-transformer": "^0.3.1", - "class-validator": "^0.12.2", - "class-validator-jsonschema": "^2.0.3", - "consola": "^2.15.0", - "cors": "^2.8.5", - "dotenv": "^8.2.0", - "express": "^4.17.1", - "helmet": "^4.2.0", - "jsonwebtoken": "^8.5.1", - "multer": "^1.4.2", - "mysql": "^2.18.1", - "pg": "^8.5.1", - "reflect-metadata": "^0.1.13", - "routing-controllers": "^0.9.0-alpha.6", - "routing-controllers-openapi": "^2.1.0", - "swagger-ui-express": "^4.1.5", - "typeorm": "^0.2.29", - "typeorm-routing-controllers-extensions": "^0.2.0", - "uuid": "^8.3.1" - }, - "devDependencies": { - "@types/cors": "^2.8.8", - "@types/dotenv": "^8.2.0", - "@types/express": "^4.17.9", - "@types/jsonwebtoken": "^8.5.0", - "@types/multer": "^1.4.4", - "@types/node": "^14.14.9", - "@types/swagger-ui-express": "^4.1.2", - "@types/uuid": "^8.3.0", - "nodemon": "^2.0.6", - "sqlite3": "^5.0.0", - "ts-node": "^9.0.0", - "typedoc": "^0.19.2", - "typescript": "^4.1.2" - }, - "scripts": { - "dev": "nodemon src/app.ts", - "build": "tsc", - "docs": "typedoc --out docs src" - } +{ + "name": "@lfk/backend", + "version": "1.0.0", + "main": "src/app.ts", + "repository": "https://git.odit.services/lfk/backend", + "author": { + "name": "ODIT.Services", + "email": "info@odit.services", + "url": "https://odit.services" + }, + "contributors": [ + { + "name": "Philipp Dormann", + "email": "philipp@philippdormann.de", + "url": "https://philippdormann.de" + }, + { + "name": "Nicolai Ort", + "email": "info@nicolai-ort.com", + "url": "https://nicolai-ort.com" + } + ], + "license": "CC-BY-NC-SA-4.0", + "dependencies": { + "argon2": "^0.27.0", + "body-parser": "^1.19.0", + "class-transformer": "^0.3.1", + "class-validator": "^0.12.2", + "class-validator-jsonschema": "^2.0.3", + "consola": "^2.15.0", + "cors": "^2.8.5", + "dotenv": "^8.2.0", + "express": "^4.17.1", + "helmet": "^4.2.0", + "jsonwebtoken": "^8.5.1", + "multer": "^1.4.2", + "mysql": "^2.18.1", + "pg": "^8.5.1", + "reflect-metadata": "^0.1.13", + "routing-controllers": "^0.9.0-alpha.6", + "routing-controllers-openapi": "^2.1.0", + "swagger-ui-express": "^4.1.5", + "typeorm": "^0.2.29", + "typeorm-routing-controllers-extensions": "^0.2.0", + "uuid": "^8.3.1" + }, + "devDependencies": { + "@types/cors": "^2.8.8", + "@types/dotenv": "^8.2.0", + "@types/express": "^4.17.9", + "@types/jest": "^26.0.16", + "@types/jsonwebtoken": "^8.5.0", + "@types/multer": "^1.4.4", + "@types/node": "^14.14.9", + "@types/swagger-ui-express": "^4.1.2", + "@types/uuid": "^8.3.0", + "axios": "^0.21.0", + "dotenv-safe": "^8.2.0", + "jest": "^26.6.3", + "nodemon": "^2.0.6", + "sqlite3": "^5.0.0", + "ts-jest": "^26.4.4", + "ts-node": "^9.0.0", + "typedoc": "^0.19.2", + "typescript": "^4.1.2" + }, + "scripts": { + "dev": "nodemon src/app.ts", + "build": "tsc", + "docs": "typedoc --out docs src", + "test": "jest", + "test:watch": "jest --watchAll" + }, + "nodemonConfig": { + "ignore": [ + "src/tests/*", + "docs/*" + ], + "delay": "2500" + } } \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 567e35b..c530ec1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,22 +1,22 @@ -import { config as configDotenv } from 'dotenv'; -configDotenv(); -export const config = { - internal_port: parseInt(process.env.APP_PORT) || 4010, - development: process.env.NODE_ENV === "production", - jwt_secret: process.env.JWT_SECRET || "secretjwtsecret", - phone_validation_countrycode: process.env.PHONE_COUNTRYCODE || "ZZ" -} -let errors = 0 -if (typeof config.internal_port !== "number") { - errors++ -} -if (typeof config.phone_validation_countrycode !== "string") { - errors++ -} -if (config.phone_validation_countrycode.length !== 2) { - errors++ -} -if (typeof config.development !== "boolean") { - errors++ -} +import { config as configDotenv } from 'dotenv'; +configDotenv(); +export const config = { + internal_port: parseInt(process.env.APP_PORT) || 4010, + development: process.env.NODE_ENV === "production", + jwt_secret: process.env.JWT_SECRET || "secretjwtsecret", + phone_validation_countrycode: process.env.PHONE_COUNTRYCODE || "ZZ" +} +let errors = 0 +if (typeof config.internal_port !== "number") { + errors++ +} +if (typeof config.phone_validation_countrycode !== "string") { + errors++ +} +if (config.phone_validation_countrycode.length !== 2) { + errors++ +} +if (typeof config.development !== "boolean") { + errors++ +} export let e = errors \ No newline at end of file diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index b5a29f9..a8bf93f 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -1,101 +1,101 @@ -import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; -import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { getConnectionManager, Repository } from 'typeorm'; -import { RunnerGroupNeededError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; -import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; -import { CreateRunner } from '../models/actions/CreateRunner'; -import { UpdateRunner } from '../models/actions/UpdateRunner'; -import { Runner } from '../models/entities/Runner'; -import { ResponseEmpty } from '../models/responses/ResponseEmpty'; -import { ResponseRunner } from '../models/responses/ResponseRunner'; - -@JsonController('/runners') -//@Authorized('RUNNERS:read') -export class RunnerController { - private runnerRepository: Repository; - - /** - * Gets the repository of this controller's model/entity. - */ - constructor() { - this.runnerRepository = getConnectionManager().get().getRepository(Runner); - } - - @Get() - @ResponseSchema(ResponseRunner, { isArray: true }) - @OpenAPI({ description: 'Lists all runners.' }) - async getAll() { - let responseRunners: ResponseRunner[] = new Array(); - const runners = await this.runnerRepository.find({ relations: ['scans', 'group'] }); - runners.forEach(runner => { - responseRunners.push(new ResponseRunner(runner)); - }); - return responseRunners; - } - - @Get('/:id') - @ResponseSchema(ResponseRunner) - @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) - @OnUndefined(RunnerNotFoundError) - @OpenAPI({ description: 'Returns a runner of a specified id (if it exists)' }) - async getOne(@Param('id') id: number) { - let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group'] }) - if (!runner) { throw new RunnerNotFoundError(); } - return new ResponseRunner(runner); - } - - @Post() - @ResponseSchema(ResponseRunner) - @ResponseSchema(RunnerGroupNeededError) - @ResponseSchema(RunnerGroupNotFoundError) - @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) - async post(@Body({ validate: true }) createRunner: CreateRunner) { - let runner; - try { - runner = await createRunner.toRunner(); - } catch (error) { - throw error; - } - - runner = await this.runnerRepository.save(runner) - return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group'] })); - } - - @Put('/:id') - @ResponseSchema(ResponseRunner) - @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) - @ResponseSchema(RunnerIdsNotMatchingError, { statusCode: 406 }) - @OpenAPI({ description: "Update a runner object (id 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.update(oldRunner, await runner.toRunner()); - return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group'] })); - } - - @Delete('/:id') - @ResponseSchema(ResponseRunner) - @ResponseSchema(ResponseEmpty, { statusCode: 204 }) - @OnUndefined(204) - @OpenAPI({ description: 'Delete a specified runner (if it exists).' }) - 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'] }); - - if (!runner) { - throw new RunnerNotFoundError(); - } - - await this.runnerRepository.delete(runner); - return new ResponseRunner(responseRunner); - } -} +import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { getConnectionManager, Repository } from 'typeorm'; +import { RunnerGroupNeededError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; +import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; +import { CreateRunner } from '../models/actions/CreateRunner'; +import { UpdateRunner } from '../models/actions/UpdateRunner'; +import { Runner } from '../models/entities/Runner'; +import { ResponseEmpty } from '../models/responses/ResponseEmpty'; +import { ResponseRunner } from '../models/responses/ResponseRunner'; + +@JsonController('/runners') +//@Authorized('RUNNERS:read') +export class RunnerController { + private runnerRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerRepository = getConnectionManager().get().getRepository(Runner); + } + + @Get() + @ResponseSchema(ResponseRunner, { isArray: true }) + @OpenAPI({ description: 'Lists all runners.' }) + async getAll() { + let responseRunners: ResponseRunner[] = new Array(); + const runners = await this.runnerRepository.find({ relations: ['scans', 'group'] }); + runners.forEach(runner => { + responseRunners.push(new ResponseRunner(runner)); + }); + return responseRunners; + } + + @Get('/:id') + @ResponseSchema(ResponseRunner) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @OnUndefined(RunnerNotFoundError) + @OpenAPI({ description: 'Returns a runner of a specified id (if it exists)' }) + async getOne(@Param('id') id: number) { + let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group'] }) + if (!runner) { throw new RunnerNotFoundError(); } + return new ResponseRunner(runner); + } + + @Post() + @ResponseSchema(ResponseRunner) + @ResponseSchema(RunnerGroupNeededError) + @ResponseSchema(RunnerGroupNotFoundError) + @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createRunner: CreateRunner) { + let runner; + try { + runner = await createRunner.toRunner(); + } catch (error) { + throw error; + } + + runner = await this.runnerRepository.save(runner) + return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group'] })); + } + + @Put('/:id') + @ResponseSchema(ResponseRunner) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runner object (id 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.update(oldRunner, await runner.toRunner()); + return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group'] })); + } + + @Delete('/:id') + @ResponseSchema(ResponseRunner) + @ResponseSchema(ResponseEmpty, { statusCode: 204 }) + @OnUndefined(204) + @OpenAPI({ description: 'Delete a specified runner (if it exists).' }) + 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'] }); + + if (!runner) { + throw new RunnerNotFoundError(); + } + + await this.runnerRepository.delete(runner); + return new ResponseRunner(responseRunner); + } +} diff --git a/src/controllers/RunnerOrganisationController.ts b/src/controllers/RunnerOrganisationController.ts index d72eaea..8c48496 100644 --- a/src/controllers/RunnerOrganisationController.ts +++ b/src/controllers/RunnerOrganisationController.ts @@ -1,123 +1,123 @@ -import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; -import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { getConnectionManager, Repository } from 'typeorm'; -import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; -import { RunnerOrganisationHasRunnersError, RunnerOrganisationHasTeamsError, RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors'; -import { CreateRunnerOrganisation } from '../models/actions/CreateRunnerOrganisation'; -import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; -import { ResponseEmpty } from '../models/responses/ResponseEmpty'; -import { ResponseRunnerOrganisation } from '../models/responses/ResponseRunnerOrganisation'; -import { RunnerController } from './RunnerController'; -import { RunnerTeamController } from './RunnerTeamController'; - - -@JsonController('/organisations') -//@Authorized('RUNNERS:read') -export class RunnerOrganisationController { - private runnerOrganisationRepository: Repository; - - /** - * Gets the repository of this controller's model/entity. - */ - constructor() { - this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerOrganisation); - } - - @Get() - @ResponseSchema(ResponseRunnerOrganisation, { isArray: true }) - @OpenAPI({ description: 'Lists all runnerOrganisations.' }) - async getAll() { - let responseTeams: ResponseRunnerOrganisation[] = new Array(); - const runners = await this.runnerOrganisationRepository.find({ relations: ['address', 'contact', 'teams'] }); - runners.forEach(runner => { - responseTeams.push(new ResponseRunnerOrganisation(runner)); - }); - return responseTeams; - } - - @Get('/:id') - @ResponseSchema(ResponseRunnerOrganisation) - @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) - @OnUndefined(RunnerOrganisationNotFoundError) - @OpenAPI({ description: 'Returns a runnerOrganisation of a specified id (if it exists)' }) - async getOne(@Param('id') id: number) { - let runnerOrg = await this.runnerOrganisationRepository.findOne({ id: id }, { relations: ['address', 'contact', 'teams'] }); - if (!runnerOrg) { throw new RunnerOrganisationNotFoundError(); } - return new ResponseRunnerOrganisation(runnerOrg); - } - - @Post() - @ResponseSchema(ResponseRunnerOrganisation) - @OpenAPI({ description: 'Create a new runnerOrganisation object (id will be generated automagicly).' }) - async post(@Body({ validate: true }) createRunnerOrganisation: CreateRunnerOrganisation) { - let runnerOrganisation; - try { - runnerOrganisation = await createRunnerOrganisation.toRunnerOrganisation(); - } catch (error) { - throw error; - } - - runnerOrganisation = await this.runnerOrganisationRepository.save(runnerOrganisation); - - return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['address', 'contact', 'teams'] })); - } - - @Put('/:id') - @ResponseSchema(ResponseRunnerOrganisation) - @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) - @ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 }) - @OpenAPI({ description: "Update a runnerOrganisation object (id can't be changed)." }) - async put(@Param('id') id: number, @EntityFromBody() runnerOrganisation: RunnerOrganisation) { - let oldRunnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id }); - - if (!oldRunnerOrganisation) { - throw new RunnerOrganisationNotFoundError(); - } - - if (oldRunnerOrganisation.id != runnerOrganisation.id) { - throw new RunnerOrganisationIdsNotMatchingError(); - } - - await this.runnerOrganisationRepository.update(oldRunnerOrganisation, runnerOrganisation); - - runnerOrganisation = await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['address', 'contact', 'teams'] }); - return new ResponseRunnerOrganisation(runnerOrganisation); - } - - @Delete('/:id') - @ResponseSchema(ResponseRunnerOrganisation) - @ResponseSchema(ResponseEmpty, { statusCode: 204 }) - @ResponseSchema(RunnerOrganisationHasTeamsError, { statusCode: 406 }) - @ResponseSchema(RunnerOrganisationHasRunnersError, { statusCode: 406 }) - @OnUndefined(204) - @OpenAPI({ description: 'Delete a specified runnerOrganisation (if it exists).' }) - async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { - let organisation = await this.runnerOrganisationRepository.findOne({ id: id }); - if (!organisation) { return null; } - let runnerOrganisation = await this.runnerOrganisationRepository.findOne(organisation, { relations: ['address', 'contact', 'runners', 'teams'] }); - - if (!force) { - if (runnerOrganisation.teams.length != 0) { - throw new RunnerOrganisationHasTeamsError(); - } - } - const teamController = new RunnerTeamController() - for (let team of runnerOrganisation.teams) { - await teamController.remove(team.id, true); - } - - if (!force) { - if (runnerOrganisation.runners.length != 0) { - throw new RunnerOrganisationHasRunnersError(); - } - } - const runnerController = new RunnerController() - for (let runner of runnerOrganisation.runners) { - await runnerController.remove(runner.id, true); - } - - const responseOrganisation = new ResponseRunnerOrganisation(runnerOrganisation); - await this.runnerOrganisationRepository.delete(organisation); - return responseOrganisation; - } -} +import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { RunnerOrganisationHasRunnersError, RunnerOrganisationHasTeamsError, RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors'; +import { CreateRunnerOrganisation } from '../models/actions/CreateRunnerOrganisation'; +import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; +import { ResponseEmpty } from '../models/responses/ResponseEmpty'; +import { ResponseRunnerOrganisation } from '../models/responses/ResponseRunnerOrganisation'; +import { RunnerController } from './RunnerController'; +import { RunnerTeamController } from './RunnerTeamController'; + + +@JsonController('/organisations') +//@Authorized('RUNNERS:read') +export class RunnerOrganisationController { + private runnerOrganisationRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerOrganisation); + } + + @Get() + @ResponseSchema(ResponseRunnerOrganisation, { isArray: true }) + @OpenAPI({ description: 'Lists all runnerOrganisations.' }) + async getAll() { + let responseTeams: ResponseRunnerOrganisation[] = new Array(); + const runners = await this.runnerOrganisationRepository.find({ relations: ['address', 'contact', 'teams'] }); + runners.forEach(runner => { + responseTeams.push(new ResponseRunnerOrganisation(runner)); + }); + return responseTeams; + } + + @Get('/:id') + @ResponseSchema(ResponseRunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @OnUndefined(RunnerOrganisationNotFoundError) + @OpenAPI({ description: 'Returns a runnerOrganisation of a specified id (if it exists)' }) + async getOne(@Param('id') id: number) { + let runnerOrg = await this.runnerOrganisationRepository.findOne({ id: id }, { relations: ['address', 'contact', 'teams'] }); + if (!runnerOrg) { throw new RunnerOrganisationNotFoundError(); } + return new ResponseRunnerOrganisation(runnerOrg); + } + + @Post() + @ResponseSchema(ResponseRunnerOrganisation) + @OpenAPI({ description: 'Create a new runnerOrganisation object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createRunnerOrganisation: CreateRunnerOrganisation) { + let runnerOrganisation; + try { + runnerOrganisation = await createRunnerOrganisation.toRunnerOrganisation(); + } catch (error) { + throw error; + } + + runnerOrganisation = await this.runnerOrganisationRepository.save(runnerOrganisation); + + return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['address', 'contact', 'teams'] })); + } + + @Put('/:id') + @ResponseSchema(ResponseRunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runnerOrganisation object (id can't be changed)." }) + async put(@Param('id') id: number, @EntityFromBody() runnerOrganisation: RunnerOrganisation) { + let oldRunnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id }); + + if (!oldRunnerOrganisation) { + throw new RunnerOrganisationNotFoundError(); + } + + if (oldRunnerOrganisation.id != runnerOrganisation.id) { + throw new RunnerOrganisationIdsNotMatchingError(); + } + + await this.runnerOrganisationRepository.update(oldRunnerOrganisation, runnerOrganisation); + + runnerOrganisation = await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['address', 'contact', 'teams'] }); + return new ResponseRunnerOrganisation(runnerOrganisation); + } + + @Delete('/:id') + @ResponseSchema(ResponseRunnerOrganisation) + @ResponseSchema(ResponseEmpty, { statusCode: 204 }) + @ResponseSchema(RunnerOrganisationHasTeamsError, { statusCode: 406 }) + @ResponseSchema(RunnerOrganisationHasRunnersError, { statusCode: 406 }) + @OnUndefined(204) + @OpenAPI({ description: 'Delete a specified runnerOrganisation (if it exists).' }) + async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { + let organisation = await this.runnerOrganisationRepository.findOne({ id: id }); + if (!organisation) { return null; } + let runnerOrganisation = await this.runnerOrganisationRepository.findOne(organisation, { relations: ['address', 'contact', 'runners', 'teams'] }); + + if (!force) { + if (runnerOrganisation.teams.length != 0) { + throw new RunnerOrganisationHasTeamsError(); + } + } + const teamController = new RunnerTeamController() + for (let team of runnerOrganisation.teams) { + await teamController.remove(team.id, true); + } + + if (!force) { + if (runnerOrganisation.runners.length != 0) { + throw new RunnerOrganisationHasRunnersError(); + } + } + const runnerController = new RunnerController() + for (let runner of runnerOrganisation.runners) { + await runnerController.remove(runner.id, true); + } + + const responseOrganisation = new ResponseRunnerOrganisation(runnerOrganisation); + await this.runnerOrganisationRepository.delete(organisation); + return responseOrganisation; + } +} diff --git a/src/controllers/RunnerTeamController.ts b/src/controllers/RunnerTeamController.ts index 1c9ca0a..c9c4d5c 100644 --- a/src/controllers/RunnerTeamController.ts +++ b/src/controllers/RunnerTeamController.ts @@ -1,111 +1,111 @@ -import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; -import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { getConnectionManager, Repository } from 'typeorm'; -import { RunnerTeamHasRunnersError, RunnerTeamIdsNotMatchingError, RunnerTeamNotFoundError } from '../errors/RunnerTeamErrors'; -import { CreateRunnerTeam } from '../models/actions/CreateRunnerTeam'; -import { UpdateRunnerTeam } from '../models/actions/UpdateRunnerTeam'; -import { RunnerTeam } from '../models/entities/RunnerTeam'; -import { ResponseEmpty } from '../models/responses/ResponseEmpty'; -import { ResponseRunnerTeam } from '../models/responses/ResponseRunnerTeam'; -import { RunnerController } from './RunnerController'; - - -@JsonController('/teams') -//@Authorized('RUNNERS:read') -export class RunnerTeamController { - private runnerTeamRepository: Repository; - - /** - * Gets the repository of this controller's model/entity. - */ - constructor() { - this.runnerTeamRepository = getConnectionManager().get().getRepository(RunnerTeam); - } - - @Get() - @ResponseSchema(ResponseRunnerTeam, { isArray: true }) - @OpenAPI({ description: 'Lists all runnerTeams.' }) - async getAll() { - let responseTeams: ResponseRunnerTeam[] = new Array(); - const runners = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] }); - runners.forEach(runner => { - responseTeams.push(new ResponseRunnerTeam(runner)); - }); - return responseTeams; - } - - @Get('/:id') - @ResponseSchema(ResponseRunnerTeam) - @ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 }) - @OnUndefined(RunnerTeamNotFoundError) - @OpenAPI({ description: 'Returns a runnerTeam of a specified id (if it exists)' }) - async getOne(@Param('id') id: number) { - let runnerTeam = await this.runnerTeamRepository.findOne({ id: id }, { relations: ['parentGroup', 'contact'] }); - if (!runnerTeam) { throw new RunnerTeamNotFoundError(); } - return new ResponseRunnerTeam(runnerTeam); - } - - @Post() - @ResponseSchema(ResponseRunnerTeam) - @OpenAPI({ description: 'Create a new runnerTeam object (id will be generated automagicly).' }) - async post(@Body({ validate: true }) createRunnerTeam: CreateRunnerTeam) { - let runnerTeam; - try { - runnerTeam = await createRunnerTeam.toRunnerTeam(); - } catch (error) { - throw error; - } - - runnerTeam = await this.runnerTeamRepository.save(runnerTeam); - runnerTeam = await this.runnerTeamRepository.findOne(runnerTeam, { relations: ['parentGroup', 'contact'] }); - - return new ResponseRunnerTeam(runnerTeam); - } - - @Put('/:id') - @ResponseSchema(ResponseRunnerTeam) - @ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 }) - @ResponseSchema(RunnerTeamIdsNotMatchingError, { statusCode: 406 }) - @OpenAPI({ description: "Update a runnerTeam object (id can't be changed)." }) - async put(@Param('id') id: number, @Body({ validate: true }) runnerTeam: UpdateRunnerTeam) { - let oldRunnerTeam = await this.runnerTeamRepository.findOne({ id: id }, { relations: ['parentGroup', 'contact'] }); - - if (!oldRunnerTeam) { - throw new RunnerTeamNotFoundError(); - } - - if (oldRunnerTeam.id != runnerTeam.id) { - throw new RunnerTeamIdsNotMatchingError(); - } - - await this.runnerTeamRepository.update(oldRunnerTeam, await runnerTeam.toRunnerTeam()); - - return new ResponseRunnerTeam(await this.runnerTeamRepository.findOne({ id: runnerTeam.id }, { relations: ['parentGroup', 'contact'] })); - } - - @Delete('/:id') - @ResponseSchema(ResponseRunnerTeam) - @ResponseSchema(ResponseEmpty, { statusCode: 204 }) - @ResponseSchema(RunnerTeamHasRunnersError, { statusCode: 406 }) - @OnUndefined(204) - @OpenAPI({ description: 'Delete a specified runnerTeam (if it exists).' }) - async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { - let team = await this.runnerTeamRepository.findOne({ id: id }); - if (!team) { return null; } - let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['parentGroup', 'contact', 'runners'] }); - - if (!force) { - if (runnerTeam.runners.length != 0) { - throw new RunnerTeamHasRunnersError(); - } - } - const runnerController = new RunnerController() - for (let runner of runnerTeam.runners) { - await runnerController.remove(runner.id, true); - } - - const responseTeam = new ResponseRunnerTeam(runnerTeam); - await this.runnerTeamRepository.delete(team); - return responseTeam; - } -} +import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { getConnectionManager, Repository } from 'typeorm'; +import { RunnerTeamHasRunnersError, RunnerTeamIdsNotMatchingError, RunnerTeamNotFoundError } from '../errors/RunnerTeamErrors'; +import { CreateRunnerTeam } from '../models/actions/CreateRunnerTeam'; +import { UpdateRunnerTeam } from '../models/actions/UpdateRunnerTeam'; +import { RunnerTeam } from '../models/entities/RunnerTeam'; +import { ResponseEmpty } from '../models/responses/ResponseEmpty'; +import { ResponseRunnerTeam } from '../models/responses/ResponseRunnerTeam'; +import { RunnerController } from './RunnerController'; + + +@JsonController('/teams') +//@Authorized('RUNNERS:read') +export class RunnerTeamController { + private runnerTeamRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerTeamRepository = getConnectionManager().get().getRepository(RunnerTeam); + } + + @Get() + @ResponseSchema(ResponseRunnerTeam, { isArray: true }) + @OpenAPI({ description: 'Lists all runnerTeams.' }) + async getAll() { + let responseTeams: ResponseRunnerTeam[] = new Array(); + const runners = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] }); + runners.forEach(runner => { + responseTeams.push(new ResponseRunnerTeam(runner)); + }); + return responseTeams; + } + + @Get('/:id') + @ResponseSchema(ResponseRunnerTeam) + @ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 }) + @OnUndefined(RunnerTeamNotFoundError) + @OpenAPI({ description: 'Returns a runnerTeam of a specified id (if it exists)' }) + async getOne(@Param('id') id: number) { + let runnerTeam = await this.runnerTeamRepository.findOne({ id: id }, { relations: ['parentGroup', 'contact'] }); + if (!runnerTeam) { throw new RunnerTeamNotFoundError(); } + return new ResponseRunnerTeam(runnerTeam); + } + + @Post() + @ResponseSchema(ResponseRunnerTeam) + @OpenAPI({ description: 'Create a new runnerTeam object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createRunnerTeam: CreateRunnerTeam) { + let runnerTeam; + try { + runnerTeam = await createRunnerTeam.toRunnerTeam(); + } catch (error) { + throw error; + } + + runnerTeam = await this.runnerTeamRepository.save(runnerTeam); + runnerTeam = await this.runnerTeamRepository.findOne(runnerTeam, { relations: ['parentGroup', 'contact'] }); + + return new ResponseRunnerTeam(runnerTeam); + } + + @Put('/:id') + @ResponseSchema(ResponseRunnerTeam) + @ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerTeamIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runnerTeam object (id can't be changed)." }) + async put(@Param('id') id: number, @Body({ validate: true }) runnerTeam: UpdateRunnerTeam) { + let oldRunnerTeam = await this.runnerTeamRepository.findOne({ id: id }, { relations: ['parentGroup', 'contact'] }); + + if (!oldRunnerTeam) { + throw new RunnerTeamNotFoundError(); + } + + if (oldRunnerTeam.id != runnerTeam.id) { + throw new RunnerTeamIdsNotMatchingError(); + } + + await this.runnerTeamRepository.update(oldRunnerTeam, await runnerTeam.toRunnerTeam()); + + return new ResponseRunnerTeam(await this.runnerTeamRepository.findOne({ id: runnerTeam.id }, { relations: ['parentGroup', 'contact'] })); + } + + @Delete('/:id') + @ResponseSchema(ResponseRunnerTeam) + @ResponseSchema(ResponseEmpty, { statusCode: 204 }) + @ResponseSchema(RunnerTeamHasRunnersError, { statusCode: 406 }) + @OnUndefined(204) + @OpenAPI({ description: 'Delete a specified runnerTeam (if it exists).' }) + async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { + let team = await this.runnerTeamRepository.findOne({ id: id }); + if (!team) { return null; } + let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['parentGroup', 'contact', 'runners'] }); + + if (!force) { + if (runnerTeam.runners.length != 0) { + throw new RunnerTeamHasRunnersError(); + } + } + const runnerController = new RunnerController() + for (let runner of runnerTeam.runners) { + await runnerController.remove(runner.id, true); + } + + const responseTeam = new ResponseRunnerTeam(runnerTeam); + await this.runnerTeamRepository.delete(team); + return responseTeam; + } +} diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index f71fd60..a94ac71 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -1,88 +1,88 @@ -import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put } from 'routing-controllers'; -import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { getConnectionManager, Repository } from 'typeorm'; -import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; -import { UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; -import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; -import { CreateUser } from '../models/actions/CreateUser'; -import { User } from '../models/entities/User'; -import { ResponseEmpty } from '../models/responses/ResponseEmpty'; - - -@JsonController('/users') -export class UserController { - private userRepository: Repository; - - /** - * Gets the repository of this controller's model/entity. - */ - constructor() { - this.userRepository = getConnectionManager().get().getRepository(User); - } - - @Get() - @ResponseSchema(User, { isArray: true }) - @OpenAPI({ description: 'Lists all users.' }) - getAll() { - return this.userRepository.find(); - } - - @Get('/:id') - @ResponseSchema(User) - @ResponseSchema(UserNotFoundError, { statusCode: 404 }) - @OnUndefined(UserNotFoundError) - @OpenAPI({ description: 'Returns a user of a specified id (if it exists)' }) - getOne(@Param('id') id: number) { - return this.userRepository.findOne({ id: id }); - } - - @Post() - @ResponseSchema(User) - @ResponseSchema(UserGroupNotFoundError) - @OpenAPI({ description: 'Create a new user object (id will be generated automagicly).' }) - async post(@Body({ validate: true }) createUser: CreateUser) { - let user; - try { - user = await createUser.toUser(); - } catch (error) { - throw error; - } - - return this.userRepository.save(user); - } - - @Put('/:id') - @ResponseSchema(User) - @ResponseSchema(UserNotFoundError, { statusCode: 404 }) - @ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 }) - @OpenAPI({ description: "Update a user object (id can't be changed)." }) - async put(@Param('id') id: number, @EntityFromBody() user: User) { - let oldUser = await this.userRepository.findOne({ id: id }); - - if (!oldUser) { - throw new UserNotFoundError(); - } - - if (oldUser.id != user.id) { - throw new UserIdsNotMatchingError(); - } - - await this.userRepository.update(oldUser, user); - return user; - } - - @Delete('/:id') - @ResponseSchema(User) - @ResponseSchema(ResponseEmpty, { statusCode: 204 }) - @OnUndefined(204) - @OpenAPI({ description: 'Delete a specified runner (if it exists).' }) - async remove(@Param("id") id: number) { - let user = await this.userRepository.findOne({ id: id }); - if (!user) { - return null; - } - - await this.userRepository.delete(user); - return user; - } -} +import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put } from 'routing-controllers'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; +import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; +import { CreateUser } from '../models/actions/CreateUser'; +import { User } from '../models/entities/User'; +import { ResponseEmpty } from '../models/responses/ResponseEmpty'; + + +@JsonController('/users') +export class UserController { + private userRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.userRepository = getConnectionManager().get().getRepository(User); + } + + @Get() + @ResponseSchema(User, { isArray: true }) + @OpenAPI({ description: 'Lists all users.' }) + getAll() { + return this.userRepository.find(); + } + + @Get('/:id') + @ResponseSchema(User) + @ResponseSchema(UserNotFoundError, { statusCode: 404 }) + @OnUndefined(UserNotFoundError) + @OpenAPI({ description: 'Returns a user of a specified id (if it exists)' }) + getOne(@Param('id') id: number) { + return this.userRepository.findOne({ id: id }); + } + + @Post() + @ResponseSchema(User) + @ResponseSchema(UserGroupNotFoundError) + @OpenAPI({ description: 'Create a new user object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createUser: CreateUser) { + let user; + try { + user = await createUser.toUser(); + } catch (error) { + throw error; + } + + return this.userRepository.save(user); + } + + @Put('/:id') + @ResponseSchema(User) + @ResponseSchema(UserNotFoundError, { statusCode: 404 }) + @ResponseSchema(UserIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a user object (id can't be changed)." }) + async put(@Param('id') id: number, @EntityFromBody() user: User) { + let oldUser = await this.userRepository.findOne({ id: id }); + + if (!oldUser) { + throw new UserNotFoundError(); + } + + if (oldUser.id != user.id) { + throw new UserIdsNotMatchingError(); + } + + await this.userRepository.update(oldUser, user); + return user; + } + + @Delete('/:id') + @ResponseSchema(User) + @ResponseSchema(ResponseEmpty, { statusCode: 204 }) + @OnUndefined(204) + @OpenAPI({ description: 'Delete a specified runner (if it exists).' }) + async remove(@Param("id") id: number) { + let user = await this.userRepository.findOne({ id: id }); + if (!user) { + return null; + } + + await this.userRepository.delete(user); + return user; + } +} diff --git a/src/controllers/UserGroupController.ts b/src/controllers/UserGroupController.ts index a317366..8a90d94 100644 --- a/src/controllers/UserGroupController.ts +++ b/src/controllers/UserGroupController.ts @@ -1,87 +1,87 @@ -import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put } from 'routing-controllers'; -import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { getConnectionManager, Repository } from 'typeorm'; -import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; -import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors'; -import { CreateUserGroup } from '../models/actions/CreateUserGroup'; -import { UserGroup } from '../models/entities/UserGroup'; -import { ResponseEmpty } from '../models/responses/ResponseEmpty'; - - -@JsonController('/usergroups') -export class UserGroupController { - private userGroupsRepository: Repository; - - /** - * Gets the repository of this controller's model/entity. - */ - constructor() { - this.userGroupsRepository = getConnectionManager().get().getRepository(UserGroup); - } - - @Get() - @ResponseSchema(UserGroup, { isArray: true }) - @OpenAPI({ description: 'Lists all usergroups.' }) - getAll() { - return this.userGroupsRepository.find(); - } - - @Get('/:id') - @ResponseSchema(UserGroup) - @ResponseSchema(UserGroupNotFoundError, { statusCode: 404 }) - @OnUndefined(UserGroupNotFoundError) - @OpenAPI({ description: 'Returns a usergroup of a specified id (if it exists)' }) - getOne(@Param('id') id: number) { - return this.userGroupsRepository.findOne({ id: id }); - } - - @Post() - @ResponseSchema(UserGroup) - @ResponseSchema(UserGroupNotFoundError) - @OpenAPI({ description: 'Create a new usergroup object (id will be generated automagicly).' }) - async post(@Body({ validate: true }) createUserGroup: CreateUserGroup) { - let userGroup; - try { - userGroup = await createUserGroup.toUserGroup(); - } catch (error) { - throw error; - } - - return this.userGroupsRepository.save(userGroup); - } - - @Put('/:id') - @ResponseSchema(UserGroup) - @ResponseSchema(UserGroupNotFoundError, { statusCode: 404 }) - @ResponseSchema(UserGroupIdsNotMatchingError, { statusCode: 406 }) - @OpenAPI({ description: "Update a usergroup object (id can't be changed)." }) - async put(@Param('id') id: number, @EntityFromBody() userGroup: UserGroup) { - let oldUserGroup = await this.userGroupsRepository.findOne({ id: id }); - - if (!oldUserGroup) { - throw new UserGroupNotFoundError() - } - - if (oldUserGroup.id != userGroup.id) { - throw new UserGroupIdsNotMatchingError(); - } - - await this.userGroupsRepository.update(oldUserGroup, userGroup); - return userGroup; - } - - @Delete('/:id') - @ResponseSchema(UserGroup) - @ResponseSchema(ResponseEmpty, { statusCode: 204 }) - @OnUndefined(204) - @OpenAPI({ description: 'Delete a specified usergroup (if it exists).' }) - async remove(@Param("id") id: number) { - let group = await this.userGroupsRepository.findOne({ id: id }); - if (!group) { - return null; - } - - await this.userGroupsRepository.delete(group); - return group; - } -} +import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put } from 'routing-controllers'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors'; +import { CreateUserGroup } from '../models/actions/CreateUserGroup'; +import { UserGroup } from '../models/entities/UserGroup'; +import { ResponseEmpty } from '../models/responses/ResponseEmpty'; + + +@JsonController('/usergroups') +export class UserGroupController { + private userGroupsRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.userGroupsRepository = getConnectionManager().get().getRepository(UserGroup); + } + + @Get() + @ResponseSchema(UserGroup, { isArray: true }) + @OpenAPI({ description: 'Lists all usergroups.' }) + getAll() { + return this.userGroupsRepository.find(); + } + + @Get('/:id') + @ResponseSchema(UserGroup) + @ResponseSchema(UserGroupNotFoundError, { statusCode: 404 }) + @OnUndefined(UserGroupNotFoundError) + @OpenAPI({ description: 'Returns a usergroup of a specified id (if it exists)' }) + getOne(@Param('id') id: number) { + return this.userGroupsRepository.findOne({ id: id }); + } + + @Post() + @ResponseSchema(UserGroup) + @ResponseSchema(UserGroupNotFoundError) + @OpenAPI({ description: 'Create a new usergroup object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createUserGroup: CreateUserGroup) { + let userGroup; + try { + userGroup = await createUserGroup.toUserGroup(); + } catch (error) { + throw error; + } + + return this.userGroupsRepository.save(userGroup); + } + + @Put('/:id') + @ResponseSchema(UserGroup) + @ResponseSchema(UserGroupNotFoundError, { statusCode: 404 }) + @ResponseSchema(UserGroupIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a usergroup object (id can't be changed)." }) + async put(@Param('id') id: number, @EntityFromBody() userGroup: UserGroup) { + let oldUserGroup = await this.userGroupsRepository.findOne({ id: id }); + + if (!oldUserGroup) { + throw new UserGroupNotFoundError() + } + + if (oldUserGroup.id != userGroup.id) { + throw new UserGroupIdsNotMatchingError(); + } + + await this.userGroupsRepository.update(oldUserGroup, userGroup); + return userGroup; + } + + @Delete('/:id') + @ResponseSchema(UserGroup) + @ResponseSchema(ResponseEmpty, { statusCode: 204 }) + @OnUndefined(204) + @OpenAPI({ description: 'Delete a specified usergroup (if it exists).' }) + async remove(@Param("id") id: number) { + let group = await this.userGroupsRepository.findOne({ id: id }); + if (!group) { + return null; + } + + await this.userGroupsRepository.delete(group); + return group; + } +} diff --git a/src/models/actions/CreateGroupContact.ts b/src/models/actions/CreateGroupContact.ts index d8aa815..5f49879 100644 --- a/src/models/actions/CreateGroupContact.ts +++ b/src/models/actions/CreateGroupContact.ts @@ -1,84 +1,84 @@ -import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; -import { getConnectionManager } from 'typeorm'; -import { config } from '../../config'; -import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; -import { Address } from '../entities/Address'; -import { GroupContact } from '../entities/GroupContact'; - -export class CreateGroupContact { - /** - * The contact's first name. - */ - @IsNotEmpty() - @IsString() - firstname: string; - - /** - * The contact's middle name. - * Optional - */ - @IsOptional() - @IsString() - middlename?: string; - - /** - * The contact's last name. - */ - @IsNotEmpty() - @IsString() - lastname: string; - - /** - * The contact's address. - * Optional - */ - @IsInt() - @IsOptional() - address?: number; - - /** - * The contact's phone number. - * Optional - */ - @IsOptional() - @IsPhoneNumber(config.phone_validation_countrycode) - phone?: string; - - /** - * The contact's email address. - * Optional - */ - @IsOptional() - @IsEmail() - email?: string; - - /** - * Get's this participant's address from this.address. - */ - public async getAddress(): Promise
{ - if (this.address === undefined) { - return null; - } - if (!isNaN(this.address)) { - let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); - if (!address) { throw new AddressNotFoundError; } - return address; - } - - throw new AddressWrongTypeError; - } - - /** - * Creates a Address object based on this. - */ - public async toGroupContact(): Promise { - let contact: GroupContact = new GroupContact(); - contact.firstname = this.firstname; - contact.middlename = this.middlename; - contact.lastname = this.lastname; - contact.email = this.email; - contact.phone = this.phone; - contact.address = await this.getAddress(); - return null; - } +import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; +import { getConnectionManager } from 'typeorm'; +import { config } from '../../config'; +import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; +import { Address } from '../entities/Address'; +import { GroupContact } from '../entities/GroupContact'; + +export class CreateGroupContact { + /** + * The contact's first name. + */ + @IsNotEmpty() + @IsString() + firstname: string; + + /** + * The contact's middle name. + * Optional + */ + @IsOptional() + @IsString() + middlename?: string; + + /** + * The contact's last name. + */ + @IsNotEmpty() + @IsString() + lastname: string; + + /** + * The contact's address. + * Optional + */ + @IsInt() + @IsOptional() + address?: number; + + /** + * The contact's phone number. + * Optional + */ + @IsOptional() + @IsPhoneNumber(config.phone_validation_countrycode) + phone?: string; + + /** + * The contact's email address. + * Optional + */ + @IsOptional() + @IsEmail() + email?: string; + + /** + * Get's this participant's address from this.address. + */ + public async getAddress(): Promise
{ + if (this.address === undefined) { + return null; + } + if (!isNaN(this.address)) { + let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); + if (!address) { throw new AddressNotFoundError; } + return address; + } + + throw new AddressWrongTypeError; + } + + /** + * Creates a Address object based on this. + */ + public async toGroupContact(): Promise { + let contact: GroupContact = new GroupContact(); + contact.firstname = this.firstname; + contact.middlename = this.middlename; + contact.lastname = this.lastname; + contact.email = this.email; + contact.phone = this.phone; + contact.address = await this.getAddress(); + return null; + } } \ No newline at end of file diff --git a/src/models/actions/CreateParticipant.ts b/src/models/actions/CreateParticipant.ts index 808d3c2..b3827d1 100644 --- a/src/models/actions/CreateParticipant.ts +++ b/src/models/actions/CreateParticipant.ts @@ -1,72 +1,72 @@ -import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; -import { getConnectionManager } from 'typeorm'; -import { config } from '../../config'; -import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; -import { Address } from '../entities/Address'; - -export abstract class CreateParticipant { - /** - * The new participant's first name. - */ - @IsString() - @IsNotEmpty() - firstname: string; - - /** - * The new participant's middle name. - * Optional. - */ - @IsString() - @IsOptional() - middlename?: string; - - /** - * The new participant's last name. - */ - @IsString() - @IsNotEmpty() - lastname: string; - - /** - * The new participant's phone number. - * Optional. - */ - @IsString() - @IsOptional() - @IsPhoneNumber(config.phone_validation_countrycode) - phone?: string; - - /** - * The new participant's e-mail address. - * Optional. - */ - @IsString() - @IsOptional() - @IsEmail() - email?: string; - - /** - * The new participant's address. - * Must be of type number (address id). - * Optional. - */ - @IsInt() - @IsOptional() - address?: number; - - /** - * Get's this participant's address from this.address. - */ - public async getAddress(): Promise
{ - if (this.address === undefined) { - return null; - } - if (!isNaN(this.address)) { - let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); - if (!address) { throw new AddressNotFoundError; } - return address; - } - - throw new AddressWrongTypeError; - } +import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; +import { getConnectionManager } from 'typeorm'; +import { config } from '../../config'; +import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; +import { Address } from '../entities/Address'; + +export abstract class CreateParticipant { + /** + * The new participant's first name. + */ + @IsString() + @IsNotEmpty() + firstname: string; + + /** + * The new participant's middle name. + * Optional. + */ + @IsString() + @IsOptional() + middlename?: string; + + /** + * The new participant's last name. + */ + @IsString() + @IsNotEmpty() + lastname: string; + + /** + * The new participant's phone number. + * Optional. + */ + @IsString() + @IsOptional() + @IsPhoneNumber(config.phone_validation_countrycode) + phone?: string; + + /** + * The new participant's e-mail address. + * Optional. + */ + @IsString() + @IsOptional() + @IsEmail() + email?: string; + + /** + * The new participant's address. + * Must be of type number (address id). + * Optional. + */ + @IsInt() + @IsOptional() + address?: number; + + /** + * Get's this participant's address from this.address. + */ + public async getAddress(): Promise
{ + if (this.address === undefined) { + return null; + } + if (!isNaN(this.address)) { + let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); + if (!address) { throw new AddressNotFoundError; } + return address; + } + + throw new AddressWrongTypeError; + } } \ No newline at end of file diff --git a/src/models/actions/CreateUser.ts b/src/models/actions/CreateUser.ts index d3c6ef6..48858f4 100644 --- a/src/models/actions/CreateUser.ts +++ b/src/models/actions/CreateUser.ts @@ -1,120 +1,120 @@ -import * as argon2 from "argon2"; -import { IsEmail, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; -import { getConnectionManager } from 'typeorm'; -import * as uuid from 'uuid'; -import { config } from '../../config'; -import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; -import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; -import { User } from '../entities/User'; -import { UserGroup } from '../entities/UserGroup'; - -export class CreateUser { - /** - * The new user's first name. - */ - @IsString() - firstname: string; - - /** - * The new user's middle name. - * Optinal. - */ - @IsString() - @IsOptional() - middlename?: string; - - /** - * The new user's last name. - */ - @IsString() - lastname: string; - - /** - * The new user's username. - * You have to provide at least one of: {email, username}. - */ - @IsOptional() - @IsString() - username?: string; - - /** - * The new user's email address. - * You have to provide at least one of: {email, username}. - */ - @IsEmail() - @IsString() - @IsOptional() - email?: string; - - /** - * The new user's phone number. - * Optional - */ - @IsPhoneNumber(config.phone_validation_countrycode) - @IsOptional() - phone?: string; - - /** - * The new user's password. - * This will of course not be saved in plaintext :) - */ - @IsString() - password: string; - - /** - * The new user's groups' id(s). - * You can provide either one groupId or an array of groupIDs. - * Optional. - */ - @IsOptional() - groupId?: number[] | number - - //TODO: ProfilePics - - /** - * Converts this to a User Entity. - */ - public async toUser(): Promise { - let newUser: User = new User(); - - if (this.email === undefined && this.username === undefined) { - throw new UsernameOrEmailNeededError(); - } - - if (this.groupId) { - if (!Array.isArray(this.groupId)) { - this.groupId = [this.groupId] - } - const groupIDs: number[] = this.groupId - let errors = 0 - const validateusergroups = async () => { - let foundgroups = [] - for (const g of groupIDs) { - const found = await getConnectionManager().get().getRepository(UserGroup).find({ id: g }); - if (found.length === 0) { - errors++ - } else { - foundgroups.push(found[0]) - } - } - newUser.groups = foundgroups - } - await validateusergroups() - if (errors !== 0) { - throw new UserGroupNotFoundError(); - } - } - - newUser.email = this.email - newUser.username = this.username - newUser.firstname = this.firstname - newUser.middlename = this.middlename - newUser.lastname = this.lastname - newUser.uuid = uuid.v4() - newUser.phone = this.phone - newUser.password = await argon2.hash(this.password + newUser.uuid); - //TODO: ProfilePics - - return newUser; - } +import * as argon2 from "argon2"; +import { IsEmail, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; +import { getConnectionManager } from 'typeorm'; +import * as uuid from 'uuid'; +import { config } from '../../config'; +import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; +import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; +import { User } from '../entities/User'; +import { UserGroup } from '../entities/UserGroup'; + +export class CreateUser { + /** + * The new user's first name. + */ + @IsString() + firstname: string; + + /** + * The new user's middle name. + * Optinal. + */ + @IsString() + @IsOptional() + middlename?: string; + + /** + * The new user's last name. + */ + @IsString() + lastname: string; + + /** + * The new user's username. + * You have to provide at least one of: {email, username}. + */ + @IsOptional() + @IsString() + username?: string; + + /** + * The new user's email address. + * You have to provide at least one of: {email, username}. + */ + @IsEmail() + @IsString() + @IsOptional() + email?: string; + + /** + * The new user's phone number. + * Optional + */ + @IsPhoneNumber(config.phone_validation_countrycode) + @IsOptional() + phone?: string; + + /** + * The new user's password. + * This will of course not be saved in plaintext :) + */ + @IsString() + password: string; + + /** + * The new user's groups' id(s). + * You can provide either one groupId or an array of groupIDs. + * Optional. + */ + @IsOptional() + groupId?: number[] | number + + //TODO: ProfilePics + + /** + * Converts this to a User Entity. + */ + public async toUser(): Promise { + let newUser: User = new User(); + + if (this.email === undefined && this.username === undefined) { + throw new UsernameOrEmailNeededError(); + } + + if (this.groupId) { + if (!Array.isArray(this.groupId)) { + this.groupId = [this.groupId] + } + const groupIDs: number[] = this.groupId + let errors = 0 + const validateusergroups = async () => { + let foundgroups = [] + for (const g of groupIDs) { + const found = await getConnectionManager().get().getRepository(UserGroup).find({ id: g }); + if (found.length === 0) { + errors++ + } else { + foundgroups.push(found[0]) + } + } + newUser.groups = foundgroups + } + await validateusergroups() + if (errors !== 0) { + throw new UserGroupNotFoundError(); + } + } + + newUser.email = this.email + newUser.username = this.username + newUser.firstname = this.firstname + newUser.middlename = this.middlename + newUser.lastname = this.lastname + newUser.uuid = uuid.v4() + newUser.phone = this.phone + newUser.password = await argon2.hash(this.password + newUser.uuid); + //TODO: ProfilePics + + return newUser; + } } \ No newline at end of file diff --git a/src/models/entities/GroupContact.ts b/src/models/entities/GroupContact.ts index 08c5db3..d2dd367 100644 --- a/src/models/entities/GroupContact.ts +++ b/src/models/entities/GroupContact.ts @@ -1,83 +1,83 @@ -import { - IsEmail, - IsInt, - IsNotEmpty, - IsOptional, - IsPhoneNumber, - - IsString -} from "class-validator"; -import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; -import { config } from '../../config'; -import { Address } from "./Address"; -import { RunnerGroup } from "./RunnerGroup"; - -/** - * Defines a group's contact. -*/ -@Entity() -export class GroupContact { - /** - * Autogenerated unique id (primary key). - */ - @PrimaryGeneratedColumn() - @IsInt() - id: number; - - /** - * The contact's first name. - */ - @Column() - @IsNotEmpty() - @IsString() - firstname: string; - - /** - * The contact's middle name. - * Optional - */ - @Column({ nullable: true }) - @IsOptional() - @IsString() - middlename?: string; - - /** - * The contact's last name. - */ - @Column() - @IsNotEmpty() - @IsString() - lastname: string; - - /** - * The contact's address. - * Optional - */ - @IsOptional() - @ManyToOne(() => Address, address => address.participants, { nullable: true }) - address?: Address; - - /** - * The contact's phone number. - * Optional - */ - @Column({ nullable: true }) - @IsOptional() - @IsPhoneNumber(config.phone_validation_countrycode) - phone?: string; - - /** - * The contact's email address. - * Optional - */ - @Column({ nullable: true }) - @IsOptional() - @IsEmail() - email?: string; - - /** - * Used to link contacts to groups. - */ - @OneToMany(() => RunnerGroup, group => group.contact, { nullable: true }) - groups: RunnerGroup[]; +import { + IsEmail, + IsInt, + IsNotEmpty, + IsOptional, + IsPhoneNumber, + + IsString +} from "class-validator"; +import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; +import { config } from '../../config'; +import { Address } from "./Address"; +import { RunnerGroup } from "./RunnerGroup"; + +/** + * Defines a group's contact. +*/ +@Entity() +export class GroupContact { + /** + * Autogenerated unique id (primary key). + */ + @PrimaryGeneratedColumn() + @IsInt() + id: number; + + /** + * The contact's first name. + */ + @Column() + @IsNotEmpty() + @IsString() + firstname: string; + + /** + * The contact's middle name. + * Optional + */ + @Column({ nullable: true }) + @IsOptional() + @IsString() + middlename?: string; + + /** + * The contact's last name. + */ + @Column() + @IsNotEmpty() + @IsString() + lastname: string; + + /** + * The contact's address. + * Optional + */ + @IsOptional() + @ManyToOne(() => Address, address => address.participants, { nullable: true }) + address?: Address; + + /** + * The contact's phone number. + * Optional + */ + @Column({ nullable: true }) + @IsOptional() + @IsPhoneNumber(config.phone_validation_countrycode) + phone?: string; + + /** + * The contact's email address. + * Optional + */ + @Column({ nullable: true }) + @IsOptional() + @IsEmail() + email?: string; + + /** + * Used to link contacts to groups. + */ + @OneToMany(() => RunnerGroup, group => group.contact, { nullable: true }) + groups: RunnerGroup[]; } \ No newline at end of file diff --git a/src/models/entities/Participant.ts b/src/models/entities/Participant.ts index 791b30d..6f3554a 100644 --- a/src/models/entities/Participant.ts +++ b/src/models/entities/Participant.ts @@ -1,83 +1,83 @@ -import { - IsEmail, - IsInt, - IsNotEmpty, - IsOptional, - IsPhoneNumber, - - IsString -} from "class-validator"; -import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance } from "typeorm"; -import { config } from '../../config'; -import { Address } from "./Address"; -import { Donation } from "./Donation"; - -/** - * Defines the participant interface. -*/ -@Entity() -@TableInheritance({ column: { name: "type", type: "varchar" } }) -export abstract class Participant { - /** - * Autogenerated unique id (primary key). - */ - @PrimaryGeneratedColumn() - @IsInt() - id: number; - - /** - * The participant's first name. - */ - @Column() - @IsNotEmpty() - @IsString() - firstname: string; - - /** - * The participant's middle name. - * Optional - */ - @Column({ nullable: true }) - @IsOptional() - @IsString() - middlename?: string; - - /** - * The participant's last name. - */ - @Column() - @IsNotEmpty() - @IsString() - lastname: string; - - /** - * The participant's address. - * Optional - */ - @ManyToOne(() => Address, address => address.participants, { nullable: true }) - address?: Address; - - /** - * The participant's phone number. - * Optional - */ - @Column({ nullable: true }) - @IsOptional() - @IsPhoneNumber(config.phone_validation_countrycode) - phone?: string; - - /** - * The participant's email address. - * Optional - */ - @Column({ nullable: true }) - @IsOptional() - @IsEmail() - email?: string; - - /** - * Used to link the participant as the donor of a donation. - */ - @OneToMany(() => Donation, donation => donation.donor, { nullable: true }) - donations: Donation[]; +import { + IsEmail, + IsInt, + IsNotEmpty, + IsOptional, + IsPhoneNumber, + + IsString +} from "class-validator"; +import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance } from "typeorm"; +import { config } from '../../config'; +import { Address } from "./Address"; +import { Donation } from "./Donation"; + +/** + * Defines the participant interface. +*/ +@Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) +export abstract class Participant { + /** + * Autogenerated unique id (primary key). + */ + @PrimaryGeneratedColumn() + @IsInt() + id: number; + + /** + * The participant's first name. + */ + @Column() + @IsNotEmpty() + @IsString() + firstname: string; + + /** + * The participant's middle name. + * Optional + */ + @Column({ nullable: true }) + @IsOptional() + @IsString() + middlename?: string; + + /** + * The participant's last name. + */ + @Column() + @IsNotEmpty() + @IsString() + lastname: string; + + /** + * The participant's address. + * Optional + */ + @ManyToOne(() => Address, address => address.participants, { nullable: true }) + address?: Address; + + /** + * The participant's phone number. + * Optional + */ + @Column({ nullable: true }) + @IsOptional() + @IsPhoneNumber(config.phone_validation_countrycode) + phone?: string; + + /** + * The participant's email address. + * Optional + */ + @Column({ nullable: true }) + @IsOptional() + @IsEmail() + email?: string; + + /** + * Used to link the participant as the donor of a donation. + */ + @OneToMany(() => Donation, donation => donation.donor, { nullable: true }) + donations: Donation[]; } \ No newline at end of file diff --git a/src/models/responses/ResponseEmpty.ts b/src/models/responses/ResponseEmpty.ts index 1866cdf..7787b2a 100644 --- a/src/models/responses/ResponseEmpty.ts +++ b/src/models/responses/ResponseEmpty.ts @@ -1,9 +1,9 @@ -import { IsString } from 'class-validator'; - -/** - * Defines a empty response object -*/ -export class ResponseEmpty { - @IsString() - response: string = "nothing here" -} +import { IsString } from 'class-validator'; + +/** + * Defines a empty response object +*/ +export class ResponseEmpty { + @IsString() + response: string = "nothing here" +} diff --git a/src/tests/firsttest.spec.ts b/src/tests/firsttest.spec.ts new file mode 100644 index 0000000..27c84d3 --- /dev/null +++ b/src/tests/firsttest.spec.ts @@ -0,0 +1,23 @@ +import axios from 'axios'; +import { config } from '../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/openapi.json', () => { + it('is http 200', async () => { + const res = await axios.get(base + '/api/openapi.json'); + expect(res.status).toEqual(200); + }); +}); +describe('GET /', () => { + it('is http 404', async () => { + const res = await axios.get(base + '/', { validateStatus: undefined }); + expect(res.status).toEqual(404); + }); +}); +describe('GET /api/teams', () => { + it('is http 200 && is json', async () => { + const res = await axios.get(base + '/api/teams', { validateStatus: undefined }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); diff --git a/src/tests/runnerOrgs/org_add.spec.ts b/src/tests/runnerOrgs/org_add.spec.ts new file mode 100644 index 0000000..fb28b62 --- /dev/null +++ b/src/tests/runnerOrgs/org_add.spec.ts @@ -0,0 +1,78 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/organisations', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/organisations'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/organisations', () => { + it('creating a new org with just a name should return 200', async () => { + const res = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); + it('creating a new org with without a name should return 400', async () => { + const res = await axios.post(base + '/api/organisations', { + "name": null + }, { validateStatus: undefined }); + expect(res.status).toEqual(400); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('adding + getting from all orgs', () => { + it('creating a new org with just a name should return 200', async () => { + const res = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); + it('check if org was added', async () => { + const res = await axios.get(base + '/api/organisations'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + let added_org = res.data[res.data.length - 1] + delete added_org.id + expect(added_org).toEqual({ + "name": "test123", + "contact": null, + "address": null, + "teams": [] + }) + }); +}); +// --------------- +describe('adding + getting explicitly', () => { + let added_org_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('check if org was added', async () => { + const res2 = await axios.get(base + '/api/organisations/' + added_org_id); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + let added_org2 = res2.data + added_org_id = added_org2.id; + delete added_org2.id + expect(added_org2).toEqual({ + "name": "test123", + "contact": null, + "address": null, + "teams": [] + }) + }); +}); \ No newline at end of file diff --git a/src/tests/runnerOrgs/org_delete.spec.ts b/src/tests/runnerOrgs/org_delete.spec.ts new file mode 100644 index 0000000..f8d5824 --- /dev/null +++ b/src/tests/runnerOrgs/org_delete.spec.ts @@ -0,0 +1,120 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +// --------------- +describe('adding + deletion (non-existant)', () => { + it('delete', async () => { + const res2 = await axios.delete(base + '/api/organisations/0', { validateStatus: undefined }); + expect(res2.status).toEqual(204); + }); +}); +// --------------- +describe('adding + deletion (successfull)', () => { + let added_org_id + let added_org + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('delete', async () => { + const res2 = await axios.delete(base + '/api/organisations/' + added_org_id); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + let added_org2 = res2.data + added_org_id = added_org2.id; + delete added_org2.id + expect(added_org2).toEqual({ + "name": "test123", + "contact": null, + "address": null, + "teams": [] + }); + }); + it('check if org really was deleted', async () => { + const res3 = await axios.get(base + '/api/organisations/' + added_org_id, { validateStatus: undefined }); + expect(res3.status).toEqual(404); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('adding + deletion with teams still existing (without force)', () => { + let added_org; + let added_org_id; + let added_team; + let added_team_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data; + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a valid org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test123", + "parentGroup": added_org_id + }); + added_team = res2.data; + added_team_id = added_team.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('delete org - this should fail with a 406', async () => { + const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, { validateStatus: undefined }); + expect(res2.status).toEqual(406); + expect(res2.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('adding + deletion with teams still existing (with force)', () => { + let added_org; + let added_org_id; + let added_team; + let added_team_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data; + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a valid org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test123", + "parentGroup": added_org_id + }); + added_team = res2.data; + added_team_id = added_team.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('delete', async () => { + const res2 = await axios.delete(base + '/api/organisations/' + added_org_id + '?force=true'); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + let added_org2 = res2.data + added_org_id = added_org2.id; + delete added_org2.id; + delete added_org2.teams; + expect(added_org2).toEqual({ + "name": "test123", + "contact": null, + "address": null + }); + }); + it('check if org really was deleted', async () => { + const res3 = await axios.get(base + '/api/organisations/' + added_org_id, { validateStatus: undefined }); + expect(res3.status).toEqual(404); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runnerOrgs/org_get.spec.ts b/src/tests/runnerOrgs/org_get.spec.ts new file mode 100644 index 0000000..3e899f7 --- /dev/null +++ b/src/tests/runnerOrgs/org_get.spec.ts @@ -0,0 +1,19 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/organisations', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/organisations'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('GET /api/organisations/0', () => { + it('basic get should return 404', async () => { + const res = await axios.get(base + '/api/runners/0', { validateStatus: undefined }); + expect(res.status).toEqual(404); + expect(res.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runnerOrgs/org_update.spec.ts b/src/tests/runnerOrgs/org_update.spec.ts new file mode 100644 index 0000000..06a35f6 --- /dev/null +++ b/src/tests/runnerOrgs/org_update.spec.ts @@ -0,0 +1,61 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +// --------------- +describe('adding + updating name', () => { + let added_org_id + let added_org + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('update org', async () => { + const res2 = await axios.put(base + '/api/organisations/' + added_org_id, { + "id": added_org_id, + "name": "testlelele", + "contact": null, + "address": null, + }); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + let added_org2 = res2.data + added_org_id = added_org2.id; + delete added_org2.id + expect(added_org2).toEqual({ + "name": "testlelele", + "contact": null, + "address": null, + "teams": [] + }) + }); +}); +// --------------- +describe('adding + try updating id (should return 406)', () => { + let added_org_id + let added_org + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('update org', async () => { + const res2 = await axios.put(base + '/api/organisations/' + added_org_id, { + "id": added_org_id + 1, + "name": "testlelele", + "contact": null, + "address": null, + }, { validateStatus: undefined }); + expect(res2.status).toEqual(406); + expect(res2.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runnerTeams/team_add.spec.ts b/src/tests/runnerTeams/team_add.spec.ts new file mode 100644 index 0000000..5ce61d3 --- /dev/null +++ b/src/tests/runnerTeams/team_add.spec.ts @@ -0,0 +1,65 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/teams', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/teams'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('GET /api/teams/0', () => { + it('basic get should return 404', async () => { + const res = await axios.get(base + '/api/teams/0', { validateStatus: undefined }); + expect(res.status).toEqual(404); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/teams with errors', () => { + it('creating a new team without a name should return 400', async () => { + const res1 = await axios.post(base + '/api/teams', { + "name": null + }, { validateStatus: undefined }); + expect(res1.status).toEqual(400); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team without a org should return 400', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test_team" + }, { validateStatus: undefined }); + expect(res2.status).toEqual(400); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new team without a valid org should return 404', async () => { + const res3 = await axios.post(base + '/api/teams', { + "name": "test_team", + "parentGroup": -1 + }, { validateStatus: undefined }); + expect(res3.status).toEqual(404); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/teams working', () => { + let added_org_id; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a parent org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test_team", + "parentGroup": added_org_id + }); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runnerTeams/team_delete.spec.ts b/src/tests/runnerTeams/team_delete.spec.ts new file mode 100644 index 0000000..9210789 --- /dev/null +++ b/src/tests/runnerTeams/team_delete.spec.ts @@ -0,0 +1,54 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +// --------------- +describe('adding org', () => { + let added_org; + let added_org_id; + let added_team; + let added_team_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data; + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a valid org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test123", + "parentGroup": added_org_id + }); + added_team = res2.data; + added_team_id = added_team.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('delete team', async () => { + const res2 = await axios.delete(base + '/api/teams/' + added_team_id); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + let deleted_team = res2.data + delete deleted_team.id; + delete deleted_team.parentGroup; + expect(deleted_team).toEqual({ + "name": "test123", + "contact": null + }); + }); + it('check if team really was deleted', async () => { + const res3 = await axios.get(base + '/api/teams/' + added_team_id, { validateStatus: undefined }); + expect(res3.status).toEqual(404); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('adding + deletion (non-existant)', () => { + it('delete', async () => { + const res2 = await axios.delete(base + '/api/teams/0', { validateStatus: undefined }); + expect(res2.status).toEqual(204); + }); +}); diff --git a/src/tests/runnerTeams/team_get.spec.ts b/src/tests/runnerTeams/team_get.spec.ts new file mode 100644 index 0000000..f30b230 --- /dev/null +++ b/src/tests/runnerTeams/team_get.spec.ts @@ -0,0 +1,19 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/teams', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/teams'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('GET /api/teams/0', () => { + it('basic get should return 404', async () => { + const res = await axios.get(base + '/api/teams/0', { validateStatus: undefined }); + expect(res.status).toEqual(404); + expect(res.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runnerTeams/team_update.spec.ts b/src/tests/runnerTeams/team_update.spec.ts new file mode 100644 index 0000000..10b6c0c --- /dev/null +++ b/src/tests/runnerTeams/team_update.spec.ts @@ -0,0 +1,119 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +// --------------- +describe('adding + updating name', () => { + let added_org; + let added_org_id; + let added_team; + let added_team_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data; + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a valid org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test123", + "parentGroup": added_org_id + }); + added_team = res2.data; + added_team_id = added_team.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('update name', async () => { + const res3 = await axios.put(base + '/api/teams/' + added_team_id, { + "id": added_team_id, + "name": "testlelele", + "contact": null, + "parentGroup": added_org + }); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + let updated_team = res3.data; + added_team.name = "testlelele"; + expect(updated_team).toEqual(added_team) + }); +}); +// --------------- +describe('adding + try updating id (should return 406)', () => { + let added_org; + let added_org_id; + let added_team; + let added_team_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data; + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a valid org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test123", + "parentGroup": added_org_id + }); + added_team = res2.data; + added_team_id = added_team.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('update team', async () => { + added_team.id = added_team.id + 1; + const res3 = await axios.put(base + '/api/teams/' + added_team_id, added_team, { validateStatus: undefined }); + expect(res3.status).toEqual(406); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('add+update parent org (valid)', () => { + let added_org; + let added_org2; + let added_team; + let added_team_id + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new team with a valid org should return 200', async () => { + const res2 = await axios.post(base + '/api/teams', { + "name": "test123", + "parentGroup": added_org.id + }); + added_team = res2.data; + added_team_id = added_team.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new org with just a name should return 200', async () => { + const res3 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org2 = res3.data; + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + }); + it('update team', async () => { + added_team.parentGroup = added_org2; + const res4 = await axios.put(base + '/api/teams/' + added_team_id, added_team, { validateStatus: undefined }); + let updated_team = res4.data; + expect(res4.status).toEqual(200); + expect(res4.headers['content-type']).toContain("application/json") + delete added_org2.address; + delete added_org2.contact; + delete added_org2.teams; + expect(updated_team).toEqual(added_team) + }); +}); \ No newline at end of file diff --git a/src/tests/runners/runner_add.spec.ts b/src/tests/runners/runner_add.spec.ts new file mode 100644 index 0000000..f92ef87 --- /dev/null +++ b/src/tests/runners/runner_add.spec.ts @@ -0,0 +1,100 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/runners', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/runners'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('GET /api/runners/0', () => { + it('basic get should return 404', async () => { + const res = await axios.get(base + '/api/runners/0', { validateStatus: undefined }); + expect(res.status).toEqual(404); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/runners with errors', () => { + it('creating a new runner without any parameters should return 400', async () => { + const res1 = await axios.post(base + '/api/runners', null, { validateStatus: undefined }); + expect(res1.status).toEqual(400); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner without a group should return 400', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "middlename": "middle", + "lastname": "last" + }, { validateStatus: undefined }); + expect(res2.status).toEqual(400); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with a invalid valid group should return 404', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "middlename": "middle", + "lastname": "last", + "group": 0 + }, { validateStatus: undefined }); + expect(res2.status).toEqual(404); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new runner without a invalid phone number should return 400', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "middlename": "middle", + "lastname": "last", + "phone": "123" + }, { validateStatus: undefined }); + expect(res2.status).toEqual(400); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new runner without a invalid mail address should return 400', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "middlename": "middle", + "lastname": "last", + "email ": "123" + }, { validateStatus: undefined }); + expect(res2.status).toEqual(400); + expect(res2.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/runners working', () => { + let added_org_id; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org_id + }, { validateStatus: undefined }); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with all non-relationship optional params should return 200', async () => { + const res3 = await axios.post(base + '/api/runners', { + "firstname": "first", + "middlename": "middle", + "lastname": "last", + "email": "test@example.com", + "phone": "+4909123123456789", + "group": added_org_id + }, { validateStatus: undefined }); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runners/runner_delete.spec.ts b/src/tests/runners/runner_delete.spec.ts new file mode 100644 index 0000000..b1239e4 --- /dev/null +++ b/src/tests/runners/runner_delete.spec.ts @@ -0,0 +1,46 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('adding + deletion (non-existant)', () => { + it('delete', async () => { + const res2 = await axios.delete(base + '/api/runners/0', { validateStatus: undefined }); + expect(res2.status).toEqual(204); + }); +}); +// --------------- +describe('add+delete', () => { + let added_org_id; + let added_runner; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org_id + }, { validateStatus: undefined }); + added_runner = res2.data; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('delete runner', async () => { + const res3 = await axios.delete(base + '/api/runners/' + added_runner.id); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + let deleted_runner = res3.data + expect(deleted_runner).toEqual(added_runner); + }); + it('check if team really was deleted', async () => { + const res4 = await axios.get(base + '/api/runners/' + added_runner.id, { validateStatus: undefined }); + expect(res4.status).toEqual(404); + expect(res4.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/runners/runner_get.spec.ts b/src/tests/runners/runner_get.spec.ts new file mode 100644 index 0000000..13d259c --- /dev/null +++ b/src/tests/runners/runner_get.spec.ts @@ -0,0 +1,57 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/runners', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/runners'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('GET /api/runners/0', () => { + it('basic get should return 404', async () => { + const res = await axios.get(base + '/api/runners/0', { validateStatus: undefined }); + expect(res.status).toEqual(404); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('GET /api/runners after adding', () => { + let added_org_id; + let added_runner; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org_id + }, { validateStatus: undefined }); + added_runner = res2.data; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('explicit get should return 200', async () => { + const res3 = await axios.get(base + '/api/runners/' + added_runner.id, { validateStatus: undefined }); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + let gotten_runner = res3.data + expect(gotten_runner).toEqual(added_runner); + }); + it('get from all runners should return 200', async () => { + const res4 = await axios.get(base + '/api/runners/', { validateStatus: undefined }); + expect(res4.status).toEqual(200); + expect(res4.headers['content-type']).toContain("application/json") + let gotten_runners = res4.data + expect(gotten_runners).toContainEqual(added_runner); + }); +}); \ No newline at end of file diff --git a/src/tests/runners/runner_update.spec.ts b/src/tests/runners/runner_update.spec.ts new file mode 100644 index 0000000..97ccf2a --- /dev/null +++ b/src/tests/runners/runner_update.spec.ts @@ -0,0 +1,145 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + + +describe('Update runner name after adding', () => { + let added_org_id; + let added_runner; + let updated_runner; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org_id + }, { validateStatus: undefined }); + added_runner = res2.data; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('valid update should return 200', async () => { + let runnercopy = added_runner + runnercopy.firstname = "second" + const res3 = await axios.put(base + '/api/runners/' + added_runner.id, runnercopy, { validateStatus: undefined }); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + updated_runner = res3.data + expect(updated_runner).toEqual(runnercopy); + }); +}); +// --------------- +describe('Update runner group after adding', () => { + let added_org_id; + let added_org_2; + let added_runner; + let updated_runner; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org_id + }, { validateStatus: undefined }); + added_runner = res2.data; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('creating a new org with just a name should return 200', async () => { + const res3 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org_2 = res3.data + delete added_org_2.address; + delete added_org_2.contact; + delete added_org_2.teams; + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + }); + it('valid update should return 200', async () => { + added_runner.group = added_org_2; + const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, { validateStatus: undefined }); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + updated_runner = res3.data + expect(updated_runner).toEqual(added_runner); + }); +}); +// --------------- +describe('Update runner id after adding(should fail)', () => { + let added_org_id; + let added_runner; + let added_runner_id; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + let added_org = res1.data + added_org_id = added_org.id; + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org_id + }, { validateStatus: undefined }); + added_runner = res2.data; + added_runner_id = added_runner.id; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('invalid update should return 406', async () => { + added_runner.id++; + const res3 = await axios.put(base + '/api/runners/' + added_runner_id, added_runner, { validateStatus: undefined }); + expect(res3.status).toEqual(406); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('Update runner group with invalid group after adding', () => { + let added_org; + let added_runner; + it('creating a new org with just a name should return 200', async () => { + const res1 = await axios.post(base + '/api/organisations', { + "name": "test123" + }); + added_org = res1.data + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + }); + it('creating a new runner with only needed params should return 200', async () => { + const res2 = await axios.post(base + '/api/runners', { + "firstname": "first", + "lastname": "last", + "group": added_org.id + }, { validateStatus: undefined }); + added_runner = res2.data; + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }); + it('invalid update should return 404', async () => { + added_org.id = 0; + added_runner.group = added_org; + const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, { validateStatus: undefined }); + expect(res3.status).toEqual(404); + expect(res3.headers['content-type']).toContain("application/json") + }); +}); \ No newline at end of file diff --git a/src/tests/tracks.spec.ts b/src/tests/tracks.spec.ts new file mode 100644 index 0000000..b29294c --- /dev/null +++ b/src/tests/tracks.spec.ts @@ -0,0 +1,104 @@ +import axios from 'axios'; +import { config } from '../config'; +const base = "http://localhost:" + config.internal_port + +describe('GET /api/tracks', () => { + it('basic get should return 200', async () => { + const res = await axios.get(base + '/api/tracks'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); + it('correct distance input should return 200', async () => { + const res = await axios.post(base + '/api/tracks', { + "name": "string", + "distance": 400 + }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/tracks', () => { + it('illegal distance input should return 400', async () => { + const res = await axios.post(base + '/api/tracks', { + "name": "string", + "distance": -1 + }, { validateStatus: undefined }); + expect(res.status).toEqual(400); + expect(res.headers['content-type']).toContain("application/json") + }); + it('correct distance input should return 200', async () => { + const res = await axios.post(base + '/api/tracks', { + "name": "string", + "distance": 400 + }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('adding + getting tracks', () => { + it('correct distance input should return 200', async () => { + const res = await axios.post(base + '/api/tracks', { + "name": "string", + "distance": 1000 + }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); + it('check if track was added', async () => { + const res = await axios.get(base + '/api/tracks'); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + let added_track = res.data[res.data.length - 1] + delete added_track.id + expect(added_track).toEqual({ + "name": "string", + "distance": 1000 + }) + }); +}); +// --------------- +describe('adding + getting + updating', () => { + let added_track_id + it('correct distance input should return 200', async () => { + const res = await axios.post(base + '/api/tracks', { + "name": "string", + "distance": 1500 + }); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); + it('get should return 200', async () => { + const res1 = await axios.get(base + '/api/tracks'); + expect(res1.status).toEqual(200); + expect(res1.headers['content-type']).toContain("application/json") + let added_track = res1.data[res1.data.length - 1] + added_track_id = added_track.id + delete added_track.id + expect(added_track).toEqual({ + "name": "string", + "distance": 1500 + }) + }) + it('get should return 200', async () => { + const res2 = await axios.put(base + '/api/tracks/' + added_track_id, { + "id": added_track_id, + "name": "apitrack", + "distance": 5100 + }); + expect(res2.status).toEqual(200); + expect(res2.headers['content-type']).toContain("application/json") + }) + it('get should return 200', async () => { + const res3 = await axios.get(base + '/api/tracks'); + expect(res3.status).toEqual(200); + expect(res3.headers['content-type']).toContain("application/json") + let added_track2 = res3.data[res3.data.length - 1] + delete added_track2.id + expect(added_track2).toEqual({ + "name": "apitrack", + "distance": 5100 + }) + }); +});