Merge pull request 'Alpha Release 0.3.0' (#122) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

Reviewed-on: #122
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
This commit is contained in:
Nicolai Ort 2021-01-24 17:57:36 +00:00
commit c964591839
68 changed files with 1075 additions and 470 deletions

View File

@ -2,8 +2,53 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.3.0](https://git.odit.services/lfk/backend/compare/v0.2.1...v0.3.0)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3697783`](https://git.odit.services/lfk/backend/commit/3697783e190e36f1168132d75da1eca7be27b4f6)
- Merge pull request 'OrganiZation rename feature/117-organization' (#121) from feature/117-organization into dev [`161feaf`](https://git.odit.services/lfk/backend/commit/161feaf364195c7b85041e06cdefef72d75b8951)
- Renamed files and classed from *Organisation* to *Organization*📝 [`c6c643e`](https://git.odit.services/lfk/backend/commit/c6c643ecf125f5fdf58b105f97efad32e8545dd4)
- Changed organisation* to organization* in descriptions, comments and endoints ✏ [`ef15d0d`](https://git.odit.services/lfk/backend/commit/ef15d0d57619d79e014e0c0331965ca2bc664254)
- Added registration valid company tests [`20e102e`](https://git.odit.services/lfk/backend/commit/20e102ec5c52c6a01144d064c96b8b2bd1ccfd00)
- Added registration invalid citizen tests [`81d2197`](https://git.odit.services/lfk/backend/commit/81d2197a3e978ca43bc79720c32d75f8490f08df)
- Implemented registration key generation [`ad44650`](https://git.odit.services/lfk/backend/commit/ad446500f90f945aadc3510377bcfd2123440da0)
- Implemented a runner selfservice registration creation action [`10af1ba`](https://git.odit.services/lfk/backend/commit/10af1ba34148c992e94fa580e1c0210bfaea5112)
- Created a citizenrunner selfservice create action [`6df195b`](https://git.odit.services/lfk/backend/commit/6df195b6ec5fde27f84cbe54992558715b843b87)
- Added registration invalid company tests [`29aeb04`](https://git.odit.services/lfk/backend/commit/29aeb046de769e37fd7257507e36337237697ea0)
- 🧾New changelog file version [CI SKIP] [skip ci] [`5660aec`](https://git.odit.services/lfk/backend/commit/5660aecb50c0e6dd538850c6375d2f692fb7a1f2)
- Implemented a registration key for organisations [`d490247`](https://git.odit.services/lfk/backend/commit/d490247d1e337a680b385d2115e82f79ba54a601)
- Updates old tests to the new ss-ktokens [`a9843ed`](https://git.odit.services/lfk/backend/commit/a9843ed4598485e6e3d18e78b876b6e000ea6e38)
- Added registration valid citizentests [`72941da`](https://git.odit.services/lfk/backend/commit/72941da1cb1c31fd6bfcba2ee3704f34bdd73ef0)
- Added self-service get invalid tests [`e964a8e`](https://git.odit.services/lfk/backend/commit/e964a8ed44109899516c4d3b0dc35fe4990107a1)
- Implemented runner selfservice token generation [`c39a59e`](https://git.odit.services/lfk/backend/commit/c39a59e54ef0b1cc891684283422805af38969e3)
- Citizen runners now have to provide an email address for verification [`dee3639`](https://git.odit.services/lfk/backend/commit/dee36395a69da6c5e1bc4e94bd705b0418a6a3ff)
- Implemented the basics for the runner selfservice registration endpoint [`5288c70`](https://git.odit.services/lfk/backend/commit/5288c701c1ac880f3c8b7ece01457aae4bac87d7)
- Added selfservice get positive test [`0c87906`](https://git.odit.services/lfk/backend/commit/0c87906cc3fa5feaf1d7c186f68d978d4ed7fa8e)
- Implemented the citizen runner self-registration endpoint [`1b5465b`](https://git.odit.services/lfk/backend/commit/1b5465bea810f59cbf8bb1a3e82c062176f79c49)
- Renamedpermisssions from *Organisation* to *Organization*📝 [`cd7e9b8`](https://git.odit.services/lfk/backend/commit/cd7e9b86b4b9d3e1ef0312f6fff436fcef4a5c94)
- Fixed tests testing for a old responseclass [`45c8bb8`](https://git.odit.services/lfk/backend/commit/45c8bb83be0814bed8856a617de435f4694db76c)
- Fixed typo [`46f9503`](https://git.odit.services/lfk/backend/commit/46f9503543ee011d0780caeefa95748e4be45f58)
- 🧾New changelog file version [CI SKIP] [skip ci] [`c5d0646`](https://git.odit.services/lfk/backend/commit/c5d0646c425f83689bffd862edd568ca0c1b5ad8)
- Added registration invalid company tests [`e5b6f65`](https://git.odit.services/lfk/backend/commit/e5b6f650b25af776a543f7f9c7ccf0000bf07a66)
- Marked param as optional (default: false) [`f8d7544`](https://git.odit.services/lfk/backend/commit/f8d754451769e8361ec2367df7bc586f8fffe8eb)
- Bugfix: turned old entity in response to responseclass [`10f98e9`](https://git.odit.services/lfk/backend/commit/10f98e9c992b1fb45334e65082d7c47af214b6ac)
- Resolved missing relation [`3b2ed3f`](https://git.odit.services/lfk/backend/commit/3b2ed3f0f2557dccddf6ba656b201c196cc24bf0)
- Citizen registration now returns tokens [`9dd9304`](https://git.odit.services/lfk/backend/commit/9dd9304a71eae94978710cf9db82dc030ca7a37d)
- Fixed wrong error getting thrown [`6469e3b`](https://git.odit.services/lfk/backend/commit/6469e3bc976c589b42fbac4a95bbee84f67244ee)
- 🚀Bumped version to v0.3.0 [`75e2a44`](https://git.odit.services/lfk/backend/commit/75e2a44c9c7f720d1a5a20611b305e5d56a9155b)
- Merge pull request 'Self service registration feature/112-selfservice_registration' (#120) from feature/112-selfservice_registration into dev [`6a66dd8`](https://git.odit.services/lfk/backend/commit/6a66dd803becb59172e8645c6b55898fb4b4c0b5)
- Fixed fluctuating test bahaviour [`1227408`](https://git.odit.services/lfk/backend/commit/1227408407ac66b9689446c1f318b453a9d45069)
- Updated response schema error to a more fitting one [`5a00394`](https://git.odit.services/lfk/backend/commit/5a003945ac7d1a8d446c1bcc8007523b675ab6f5)
- Added check for empty token for runner self-service get [`6434b4d`](https://git.odit.services/lfk/backend/commit/6434b4dfce2da307d66ec5670d570d66ea8af8f8)
- Specified uft-8 format for string [`34c852b`](https://git.odit.services/lfk/backend/commit/34c852b12aaa88e64efa1e0575361c09652e22e1)
- MAde uuid column unique [`7b00b19`](https://git.odit.services/lfk/backend/commit/7b00b19fce3189069bcdbe0d2bcf91322506eb2b)
- Updated Method of removeing the team of citizen runners [`946efef`](https://git.odit.services/lfk/backend/commit/946efef2523c5ceb627b5c465343422cd985832d)
- Added openapi description [`73b1114`](https://git.odit.services/lfk/backend/commit/73b1114883ed2b87ef523130de4c5ca90a11c856)
#### [v0.2.1](https://git.odit.services/lfk/backend/compare/v0.2.0...v0.2.1) #### [v0.2.1](https://git.odit.services/lfk/backend/compare/v0.2.0...v0.2.1)
> 21 January 2021
- Merge pull request 'Alpha Release 0.2.1' (#119) from dev into main [`b441658`](https://git.odit.services/lfk/backend/commit/b44165857016c3ecdf0dffe8d324d572524d10ed)
- Created a donation runner response class for the runner selfservice [`88a7089`](https://git.odit.services/lfk/backend/commit/88a7089289e35be4468cb952b311fcb15c54c5a1) - Created a donation runner response class for the runner selfservice [`88a7089`](https://git.odit.services/lfk/backend/commit/88a7089289e35be4468cb952b311fcb15c54c5a1)
- Readme reorganisation [skip ci] [`e2ec0a3`](https://git.odit.services/lfk/backend/commit/e2ec0a3b64a7388ae85d557dfb66354d70cd1b72) - Readme reorganisation [skip ci] [`e2ec0a3`](https://git.odit.services/lfk/backend/commit/e2ec0a3b64a7388ae85d557dfb66354d70cd1b72)
- Added a seeder for runner test data [`9df9d9a`](https://git.odit.services/lfk/backend/commit/9df9d9ae80277d5ccc753639badb48c4afb13088) - Added a seeder for runner test data [`9df9d9a`](https://git.odit.services/lfk/backend/commit/9df9d9ae80277d5ccc753639badb48c4afb13088)
@ -20,17 +65,18 @@ All notable changes to this project will be documented in this file. Dates are d
- Added a citizen org seeder [`2db6510`](https://git.odit.services/lfk/backend/commit/2db6510a8ad83300b286a3bd35ca4db103da72d1) - Added a citizen org seeder [`2db6510`](https://git.odit.services/lfk/backend/commit/2db6510a8ad83300b286a3bd35ca4db103da72d1)
- 🧾New changelog file version [CI SKIP] [skip ci] [`d528134`](https://git.odit.services/lfk/backend/commit/d5281348b6f3bd6f2e6936ee4497860699b8c3c6) - 🧾New changelog file version [CI SKIP] [skip ci] [`d528134`](https://git.odit.services/lfk/backend/commit/d5281348b6f3bd6f2e6936ee4497860699b8c3c6)
- 📖New license file version [CI SKIP] [skip ci] [`d8b6669`](https://git.odit.services/lfk/backend/commit/d8b6669d126e64d9e434b5f841ae17a02117822b) - 📖New license file version [CI SKIP] [skip ci] [`d8b6669`](https://git.odit.services/lfk/backend/commit/d8b6669d126e64d9e434b5f841ae17a02117822b)
- Added get tests for the /runner/scans endpoint [`26dff4f`](https://git.odit.services/lfk/backend/commit/26dff4f41829e8571231aff3c5d0e3a7c53559d8) - 🧾New changelog file version [CI SKIP] [skip ci] [`e95c457`](https://git.odit.services/lfk/backend/commit/e95c457e444e9d2e99c2af8b6ee369c36d4ca8ea)
- Beautified import [`c5f7cb2`](https://git.odit.services/lfk/backend/commit/c5f7cb2c68dbee0ab1e0361754f4d4b876666c82) - Beautified import [`c5f7cb2`](https://git.odit.services/lfk/backend/commit/c5f7cb2c68dbee0ab1e0361754f4d4b876666c82)
- Added sqlite as to env.sample db of choice [skip ci] [`f4668b6`](https://git.odit.services/lfk/backend/commit/f4668b6e81d7aeac62e24291ffcb39b00ea44aac)
- 🚀Bumped version to v0.2.1 [`6de9d54`](https://git.odit.services/lfk/backend/commit/6de9d547b736c4538dac5254353d483576337290) - 🚀Bumped version to v0.2.1 [`6de9d54`](https://git.odit.services/lfk/backend/commit/6de9d547b736c4538dac5254353d483576337290)
- Merge pull request 'Runner scans endpoint feature/113-runner_scans' (#116) from feature/113-runner_scans into dev [`36d01a0`](https://git.odit.services/lfk/backend/commit/36d01a0a890eb74428679ec6c4fcb14708aaa9fe) - Merge pull request 'Runner scans endpoint feature/113-runner_scans' (#116) from feature/113-runner_scans into dev [`36d01a0`](https://git.odit.services/lfk/backend/commit/36d01a0a890eb74428679ec6c4fcb14708aaa9fe)
- Merge pull request 'Runner selfservice info endpoint feature/111-runner_selfservic_info' (#115) from feature/111-runner_selfservic_info into dev [`1717df1`](https://git.odit.services/lfk/backend/commit/1717df113edeab2d2628041ee1eccc27380fd379) - Added get tests for the /runner/scans endpoint [`26dff4f`](https://git.odit.services/lfk/backend/commit/26dff4f41829e8571231aff3c5d0e3a7c53559d8)
- Merge pull request 'Implemented more seeding feature/110-seeding' (#114) from feature/110-seeding into dev [`886c109`](https://git.odit.services/lfk/backend/commit/886c1092d60f8e39357e3b841ed01bb082ede2c4)
- Implemented the get part of the runner selfservice (no jwts are availdable yet (tm) [`da1fe34`](https://git.odit.services/lfk/backend/commit/da1fe34249a741115c1aeedcade16c5c852e896b) - Implemented the get part of the runner selfservice (no jwts are availdable yet (tm) [`da1fe34`](https://git.odit.services/lfk/backend/commit/da1fe34249a741115c1aeedcade16c5c852e896b)
- Fixed the bool converter for null values [`e12aedd`](https://git.odit.services/lfk/backend/commit/e12aedd1aad6de1f934e9593dda4607a303b2eb5) - Fixed the bool converter for null values [`e12aedd`](https://git.odit.services/lfk/backend/commit/e12aedd1aad6de1f934e9593dda4607a303b2eb5)
- Added a config option for test data seeding [`67ba489`](https://git.odit.services/lfk/backend/commit/67ba489fe2f2a2706d640a668cd0e675ded6a7df) - Added a config option for test data seeding [`67ba489`](https://git.odit.services/lfk/backend/commit/67ba489fe2f2a2706d640a668cd0e675ded6a7df)
- SEED_TEST_DATA is now false by default [`8870ebd`](https://git.odit.services/lfk/backend/commit/8870ebdb5e6d9045222440abc2c047929a74b520) - SEED_TEST_DATA is now false by default [`8870ebd`](https://git.odit.services/lfk/backend/commit/8870ebdb5e6d9045222440abc2c047929a74b520)
- Added sqlite as to env.sample db of choice [skip ci] [`f4668b6`](https://git.odit.services/lfk/backend/commit/f4668b6e81d7aeac62e24291ffcb39b00ea44aac)
- Merge pull request 'Runner selfservice info endpoint feature/111-runner_selfservic_info' (#115) from feature/111-runner_selfservic_info into dev [`1717df1`](https://git.odit.services/lfk/backend/commit/1717df113edeab2d2628041ee1eccc27380fd379)
- Merge pull request 'Implemented more seeding feature/110-seeding' (#114) from feature/110-seeding into dev [`886c109`](https://git.odit.services/lfk/backend/commit/886c1092d60f8e39357e3b841ed01bb082ede2c4)
- Updated the openapi description [`1915697`](https://git.odit.services/lfk/backend/commit/191569792c9a5cee93718555bba4e7679e4391af) - Updated the openapi description [`1915697`](https://git.odit.services/lfk/backend/commit/191569792c9a5cee93718555bba4e7679e4391af)
- Fixed wrong amount calculation [`4ee8079`](https://git.odit.services/lfk/backend/commit/4ee807973e1995681ec549f7c482bc5514a6ec55) - Fixed wrong amount calculation [`4ee8079`](https://git.odit.services/lfk/backend/commit/4ee807973e1995681ec549f7c482bc5514a6ec55)
- Added bool conversion for testdata seeding env var [`c18012f`](https://git.odit.services/lfk/backend/commit/c18012f65a704e07acd56870c9ed9f6d06cf97a9) - Added bool conversion for testdata seeding env var [`c18012f`](https://git.odit.services/lfk/backend/commit/c18012f65a704e07acd56870c9ed9f6d06cf97a9)

View File

@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-backend", "name": "@odit/lfk-backend",
"version": "0.2.1", "version": "0.3.0",
"main": "src/app.ts", "main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend", "repository": "https://git.odit.services/lfk/backend",
"author": { "author": {

View File

@ -28,7 +28,7 @@ export class GroupContactController {
@OpenAPI({ description: 'Lists all contacts. <br> This includes the contact\'s associated groups.' }) @OpenAPI({ description: 'Lists all contacts. <br> This includes the contact\'s associated groups.' })
async getAll() { async getAll() {
let responseContacts: ResponseGroupContact[] = new Array<ResponseGroupContact>(); let responseContacts: ResponseGroupContact[] = new Array<ResponseGroupContact>();
const contacts = await this.contactRepository.find({ relations: ['groups'] }); const contacts = await this.contactRepository.find({ relations: ['groups', 'groups.parentGroup'] });
contacts.forEach(contact => { contacts.forEach(contact => {
responseContacts.push(contact.toResponse()); responseContacts.push(contact.toResponse());
}); });
@ -42,7 +42,7 @@ export class GroupContactController {
@OnUndefined(GroupContactNotFoundError) @OnUndefined(GroupContactNotFoundError)
@OpenAPI({ description: 'Lists all information about the contact whose id got provided. <br> This includes the contact\'s associated groups.' }) @OpenAPI({ description: 'Lists all information about the contact whose id got provided. <br> This includes the contact\'s associated groups.' })
async getOne(@Param('id') id: number) { async getOne(@Param('id') id: number) {
let contact = await this.contactRepository.findOne({ id: id }, { relations: ['groups'] }) let contact = await this.contactRepository.findOne({ id: id }, { relations: ['groups', 'groups.parentGroup'] })
if (!contact) { throw new GroupContactNotFoundError(); } if (!contact) { throw new GroupContactNotFoundError(); }
return contact.toResponse(); return contact.toResponse();
} }
@ -61,7 +61,7 @@ export class GroupContactController {
} }
contact = await this.contactRepository.save(contact) contact = await this.contactRepository.save(contact)
return (await this.contactRepository.findOne({ id: contact.id }, { relations: ['groups'] })).toResponse(); return (await this.contactRepository.findOne({ id: contact.id }, { relations: ['groups', 'groups.parentGroup'] })).toResponse();
} }
@Put('/:id') @Put('/:id')
@ -83,7 +83,7 @@ export class GroupContactController {
} }
await this.contactRepository.save(await contact.update(oldContact)); await this.contactRepository.save(await contact.update(oldContact));
return (await this.contactRepository.findOne({ id: contact.id }, { relations: ['groups'] })).toResponse(); return (await this.contactRepository.findOne({ id: contact.id }, { relations: ['groups', 'groups.parentGroup'] })).toResponse();
} }
@Delete('/:id') @Delete('/:id')
@ -95,7 +95,7 @@ export class GroupContactController {
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) { async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let contact = await this.contactRepository.findOne({ id: id }); let contact = await this.contactRepository.findOne({ id: id });
if (!contact) { return null; } if (!contact) { return null; }
const responseContact = await this.contactRepository.findOne(contact, { relations: ['groups'] }); const responseContact = await this.contactRepository.findOne(contact, { relations: ['groups', 'groups.parentGroup'] });
for (let group of responseContact.groups) { for (let group of responseContact.groups) {
group.contact = null; group.contact = null;
await getConnection().getRepository(RunnerGroup).save(group); await getConnection().getRepository(RunnerGroup).save(group);

View File

@ -36,7 +36,7 @@ export class ImportController {
return responseRunners; return responseRunners;
} }
@Post('/organisations/:id/import') @Post('/organizations/:id/import')
@ContentType("application/json") @ContentType("application/json")
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 }) @ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })
@ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerGroupNotFoundError, { statusCode: 404 })
@ -78,7 +78,7 @@ export class ImportController {
return await this.postJSON(importRunners, groupID); return await this.postJSON(importRunners, groupID);
} }
@Post('/organisations/:id/import/csv') @Post('/organizations/:id/import/csv')
@ContentType("application/json") @ContentType("application/json")
@UseBefore(RawBodyMiddleware) @UseBefore(RawBodyMiddleware)
@ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 }) @ResponseSchema(ResponseRunner, { isArray: true, statusCode: 200 })

View File

@ -1,127 +0,0 @@
import { Authorized, 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 { RunnerOrganisationHasRunnersError, RunnerOrganisationHasTeamsError, RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors';
import { CreateRunnerOrganisation } from '../models/actions/create/CreateRunnerOrganisation';
import { UpdateRunnerOrganisation } from '../models/actions/update/UpdateRunnerOrganisation';
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')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class RunnerOrganisationController {
private runnerOrganisationRepository: Repository<RunnerOrganisation>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerOrganisation);
}
@Get()
@Authorized("ORGANISATION:GET")
@ResponseSchema(ResponseRunnerOrganisation, { isArray: true })
@OpenAPI({ description: 'Lists all organisations. <br> This includes their address, contact and teams (if existing/associated).' })
async getAll() {
let responseTeams: ResponseRunnerOrganisation[] = new Array<ResponseRunnerOrganisation>();
const runners = await this.runnerOrganisationRepository.find({ relations: ['contact', 'teams'] });
runners.forEach(runner => {
responseTeams.push(new ResponseRunnerOrganisation(runner));
});
return responseTeams;
}
@Get('/:id')
@Authorized("ORGANISATION:GET")
@ResponseSchema(ResponseRunnerOrganisation)
@ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 })
@OnUndefined(RunnerOrganisationNotFoundError)
@OpenAPI({ description: 'Lists all information about the organisation whose id got provided.' })
async getOne(@Param('id') id: number) {
let runnerOrg = await this.runnerOrganisationRepository.findOne({ id: id }, { relations: ['contact', 'teams'] });
if (!runnerOrg) { throw new RunnerOrganisationNotFoundError(); }
return new ResponseRunnerOrganisation(runnerOrg);
}
@Post()
@Authorized("ORGANISATION:CREATE")
@ResponseSchema(ResponseRunnerOrganisation)
@OpenAPI({ description: 'Create a new organsisation.' })
async post(@Body({ validate: true }) createRunnerOrganisation: CreateRunnerOrganisation) {
let runnerOrganisation;
try {
runnerOrganisation = await createRunnerOrganisation.toEntity();
} catch (error) {
throw error;
}
runnerOrganisation = await this.runnerOrganisationRepository.save(runnerOrganisation);
return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['contact', 'teams'] }));
}
@Put('/:id')
@Authorized("ORGANISATION:UPDATE")
@ResponseSchema(ResponseRunnerOrganisation)
@ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 })
@ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the organisation whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) updateOrganisation: UpdateRunnerOrganisation) {
let oldRunnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id });
if (!oldRunnerOrganisation) {
throw new RunnerOrganisationNotFoundError();
}
if (oldRunnerOrganisation.id != updateOrganisation.id) {
throw new RunnerOrganisationIdsNotMatchingError();
}
await this.runnerOrganisationRepository.save(await updateOrganisation.update(oldRunnerOrganisation));
return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(id, { relations: ['contact', 'teams'] }));
}
@Delete('/:id')
@Authorized("ORGANISATION:DELETE")
@ResponseSchema(ResponseRunnerOrganisation)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@ResponseSchema(RunnerOrganisationHasTeamsError, { statusCode: 406 })
@ResponseSchema(RunnerOrganisationHasRunnersError, { statusCode: 406 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the organsisation whose id you provided. <br> If the organisation still has runners and/or teams associated this will fail. <br> To delete the organisation with all associated runners and teams set the force QueryParam to true (cascading deletion might take a while). <br> This won\'t delete the associated contact. <br> If no organisation with this id exists it will just return 204(no content).' })
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: ['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;
}
}

View File

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

View File

@ -1,23 +1,31 @@
import * as jwt from "jsonwebtoken"; import * as jwt from "jsonwebtoken";
import { Get, JsonController, OnUndefined, Param } from 'routing-controllers'; import { Body, Get, JsonController, OnUndefined, Param, Post } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm'; import { getConnectionManager, Repository } from 'typeorm';
import { config } from '../config'; import { config } from '../config';
import { InvalidCredentialsError } from '../errors/AuthError'; import { InvalidCredentialsError, JwtNotProvidedError } from '../errors/AuthError';
import { RunnerNotFoundError } from '../errors/RunnerErrors'; import { RunnerEmailNeededError, RunnerNotFoundError } from '../errors/RunnerErrors';
import { RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
import { JwtCreator } from '../jwtcreator';
import { CreateSelfServiceCitizenRunner } from '../models/actions/create/CreateSelfServiceCitizenRunner';
import { CreateSelfServiceRunner } from '../models/actions/create/CreateSelfServiceRunner';
import { Runner } from '../models/entities/Runner'; import { Runner } from '../models/entities/Runner';
import { RunnerGroup } from '../models/entities/RunnerGroup';
import { RunnerOrganization } from '../models/entities/RunnerOrganization';
import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner'; import { ResponseSelfServiceRunner } from '../models/responses/ResponseSelfServiceRunner';
@JsonController('/runners') @JsonController('/runners')
export class RunnerSelfServiceController { export class RunnerSelfServiceController {
private runnerRepository: Repository<Runner>; private runnerRepository: Repository<Runner>;
private orgRepository: Repository<RunnerOrganization>;
/** /**
* Gets the repository of this controller's model/entity. * Gets the repository of this controller's model/entity.
*/ */
constructor() { constructor() {
this.runnerRepository = getConnectionManager().get().getRepository(Runner); this.runnerRepository = getConnectionManager().get().getRepository(Runner);
this.orgRepository = getConnectionManager().get().getRepository(RunnerOrganization);
} }
@Get('/me/:jwt') @Get('/me/:jwt')
@ -29,11 +37,40 @@ export class RunnerSelfServiceController {
return (new ResponseSelfServiceRunner(await this.getRunner(token))); return (new ResponseSelfServiceRunner(await this.getRunner(token)));
} }
@Post('/register')
@ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerEmailNeededError, { statusCode: 406 })
@OpenAPI({ description: 'Create a new selfservice runner in the citizen org. <br> This endpoint shoud be used to allow "everyday citizen" to register themselves. <br> You have to provide a mail address, b/c the future we\'ll implement email verification.' })
async registerRunner(@Body({ validate: true }) createRunner: CreateSelfServiceCitizenRunner) {
let runner = await createRunner.toEntity();
runner = await this.runnerRepository.save(runner);
let response = new ResponseSelfServiceRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] }));
response.token = JwtCreator.createSelfService(runner);
return response;
}
@Post('/register/:token')
@ResponseSchema(ResponseSelfServiceRunner)
@ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Create a new selfservice runner in a provided org. <br> The orgs get provided and authorized via api tokens that can be optained via the /organizations endpoint.' })
async registerOrganizationRunner(@Param('token') token: string, @Body({ validate: true }) createRunner: CreateSelfServiceRunner) {
const org = await this.getOrgansisation(token);
let runner = await createRunner.toEntity(org);
runner = await this.runnerRepository.save(runner);
let response = new ResponseSelfServiceRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] }));
response.token = JwtCreator.createSelfService(runner);
return response;
}
/** /**
* Get's a runner by a provided jwt token. * Get's a runner by a provided jwt token.
* @param token The runner jwt provided by the runner to identitfy themselves. * @param token The runner jwt provided by the runner to identitfy themselves.
*/ */
private async getRunner(token: string): Promise<Runner> { private async getRunner(token: string): Promise<Runner> {
if (token == "") { throw new JwtNotProvidedError(); }
let jwtPayload = undefined let jwtPayload = undefined
try { try {
jwtPayload = <any>jwt.verify(token, config.jwt_secret); jwtPayload = <any>jwt.verify(token, config.jwt_secret);
@ -41,9 +78,21 @@ export class RunnerSelfServiceController {
throw new InvalidCredentialsError(); throw new InvalidCredentialsError();
} }
const runner = await this.runnerRepository.findOne({ id: jwtPayload["id"] }, { relations: ['scans', 'group', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] }); const runner = await this.runnerRepository.findOne({ id: jwtPayload["id"] }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards', 'distanceDonations', 'distanceDonations.donor', 'distanceDonations.runner', 'distanceDonations.runner.scans', 'distanceDonations.runner.scans.track'] });
if (!runner) { throw new RunnerNotFoundError() } if (!runner) { throw new RunnerNotFoundError() }
return runner; return runner;
} }
/**
* Get's a runner org by a provided registration api key.
* @param token The organization's registration api token.
*/
private async getOrgansisation(token: string): Promise<RunnerGroup> {
token = Buffer.from(token, 'base64').toString('utf8');
const organization = await this.orgRepository.findOne({ key: token });
if (!organization) { throw new RunnerOrganizationNotFoundError; }
return organization;
}
} }

View File

@ -25,7 +25,7 @@ export class RunnerTeamController {
@Get() @Get()
@Authorized("TEAM:GET") @Authorized("TEAM:GET")
@ResponseSchema(ResponseRunnerTeam, { isArray: true }) @ResponseSchema(ResponseRunnerTeam, { isArray: true })
@OpenAPI({ description: 'Lists all teams. <br> This includes their parent organisation and contact (if existing/associated).' }) @OpenAPI({ description: 'Lists all teams. <br> This includes their parent organization and contact (if existing/associated).' })
async getAll() { async getAll() {
let responseTeams: ResponseRunnerTeam[] = new Array<ResponseRunnerTeam>(); let responseTeams: ResponseRunnerTeam[] = new Array<ResponseRunnerTeam>();
const runners = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] }); const runners = await this.runnerTeamRepository.find({ relations: ['parentGroup', 'contact'] });

View File

@ -4,12 +4,12 @@ import { getConnection } from 'typeorm';
import StatsAuth from '../middlewares/StatsAuth'; import StatsAuth from '../middlewares/StatsAuth';
import { Donation } from '../models/entities/Donation'; import { Donation } from '../models/entities/Donation';
import { Runner } from '../models/entities/Runner'; import { Runner } from '../models/entities/Runner';
import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; import { RunnerOrganization } from '../models/entities/RunnerOrganization';
import { RunnerTeam } from '../models/entities/RunnerTeam'; import { RunnerTeam } from '../models/entities/RunnerTeam';
import { Scan } from '../models/entities/Scan'; import { Scan } from '../models/entities/Scan';
import { User } from '../models/entities/User'; import { User } from '../models/entities/User';
import { ResponseStats } from '../models/responses/ResponseStats'; import { ResponseStats } from '../models/responses/ResponseStats';
import { ResponseStatsOrgnisation } from '../models/responses/ResponseStatsOrganisation'; import { ResponseStatsOrgnisation } from '../models/responses/ResponseStatsOrganization';
import { ResponseStatsRunner } from '../models/responses/ResponseStatsRunner'; import { ResponseStatsRunner } from '../models/responses/ResponseStatsRunner';
import { ResponseStatsTeam } from '../models/responses/ResponseStatsTeam'; import { ResponseStatsTeam } from '../models/responses/ResponseStatsTeam';
@ -23,7 +23,7 @@ export class StatsController {
let connection = getConnection(); let connection = getConnection();
let runners = await connection.getRepository(Runner).find({ relations: ['scans', 'scans.track'] }); let runners = await connection.getRepository(Runner).find({ relations: ['scans', 'scans.track'] });
let teams = await connection.getRepository(RunnerTeam).find(); let teams = await connection.getRepository(RunnerTeam).find();
let orgs = await connection.getRepository(RunnerOrganisation).find(); let orgs = await connection.getRepository(RunnerOrganization).find();
let users = await connection.getRepository(User).find(); let users = await connection.getRepository(User).find();
let scans = await connection.getRepository(Scan).find(); let scans = await connection.getRepository(Scan).find();
let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] }); let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] });
@ -94,12 +94,12 @@ export class StatsController {
return responseTeams; return responseTeams;
} }
@Get("/organisations/distance") @Get("/organizations/distance")
@UseBefore(StatsAuth) @UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsOrgnisation, { isArray: true }) @ResponseSchema(ResponseStatsOrgnisation, { isArray: true })
@OpenAPI({ description: "Returns the top ten organisations by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) @OpenAPI({ description: "Returns the top ten organizations by distance.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopOrgsByDistance() { async getTopOrgsByDistance() {
let orgs = await getConnection().getRepository(RunnerOrganisation).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] }); let orgs = await getConnection().getRepository(RunnerOrganization).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] });
let topOrgs = orgs.sort((org1, org2) => org1.distance - org2.distance).slice(0, 9); let topOrgs = orgs.sort((org1, org2) => org1.distance - org2.distance).slice(0, 9);
let responseOrgs: ResponseStatsOrgnisation[] = new Array<ResponseStatsOrgnisation>(); let responseOrgs: ResponseStatsOrgnisation[] = new Array<ResponseStatsOrgnisation>();
topOrgs.forEach(org => { topOrgs.forEach(org => {
@ -108,12 +108,12 @@ export class StatsController {
return responseOrgs; return responseOrgs;
} }
@Get("/organisations/donations") @Get("/organizations/donations")
@UseBefore(StatsAuth) @UseBefore(StatsAuth)
@ResponseSchema(ResponseStatsOrgnisation, { isArray: true }) @ResponseSchema(ResponseStatsOrgnisation, { isArray: true })
@OpenAPI({ description: "Returns the top ten organisations by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] }) @OpenAPI({ description: "Returns the top ten organizations by donations.", security: [{ "StatsApiToken": [] }, { "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
async getTopOrgsByDonations() { async getTopOrgsByDonations() {
let orgs = await getConnection().getRepository(RunnerOrganisation).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] }); let orgs = await getConnection().getRepository(RunnerOrganization).find({ relations: ['runners', 'runners.scans', 'runners.distanceDonations', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.scans', 'teams.runners.distanceDonations', 'teams.runners.scans.track'] });
let topOrgs = orgs.sort((org1, org2) => org1.distanceDonationAmount - org2.distanceDonationAmount).slice(0, 9); let topOrgs = orgs.sort((org1, org2) => org1.distanceDonationAmount - org2.distanceDonationAmount).slice(0, 9);
let responseOrgs: ResponseStatsOrgnisation[] = new Array<ResponseStatsOrgnisation>(); let responseOrgs: ResponseStatsOrgnisation[] = new Array<ResponseStatsOrgnisation>();
topOrgs.forEach(org => { topOrgs.forEach(org => {

View File

@ -32,7 +32,18 @@ export class RunnerGroupNeededError extends NotAcceptableError {
name = "RunnerGroupNeededError" name = "RunnerGroupNeededError"
@IsString() @IsString()
message = "Runner's need to be part of one group (team or organisation)! \n You provided neither." message = "Runner's need to be part of one group (team or organization)! \n You provided neither."
}
/**
* Error to throw when a citizen runner has no mail-address.
*/
export class RunnerEmailNeededError extends NotAcceptableError {
@IsString()
name = "RunnerEmailNeededError"
@IsString()
message = "Citizenrunners have to provide an email address for verification and contacting."
} }
/** /**

View File

@ -1,58 +0,0 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a runner organisation couldn't be found.
*/
export class RunnerOrganisationNotFoundError extends NotFoundError {
@IsString()
name = "RunnerOrganisationNotFoundError"
@IsString()
message = "RunnerOrganisation not found!"
}
/**
* Error to throw when two runner organisation's ids don't match.
* Usually occurs when a user tries to change a runner organisation's id.
*/
export class RunnerOrganisationIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a runner organisation's id: This isn't allowed!"
}
/**
* Error to throw when a organisation still has runners associated.
*/
export class RunnerOrganisationHasRunnersError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationHasRunnersError"
@IsString()
message = "This organisation still has runners associated with it. \n If you want to delete this organisation with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw when a organisation still has teams associated.
*/
export class RunnerOrganisationHasTeamsError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationHasTeamsError"
@IsString()
message = "This organisation still has teams associated with it. \n If you want to delete this organisation with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw, when a provided runnerOrganisation doesn't belong to the accepted types.
*/
export class RunnerOrganisationWrongTypeError extends NotAcceptableError {
@IsString()
name = "RunnerOrganisationWrongTypeError"
@IsString()
message = "The runner organisation must be an existing organisation's id. \n You provided a object of another type."
}

View File

@ -0,0 +1,58 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a runner organization couldn't be found.
*/
export class RunnerOrganizationNotFoundError extends NotFoundError {
@IsString()
name = "RunnerOrganizationNotFoundError"
@IsString()
message = "RunnerOrganization not found!"
}
/**
* Error to throw when two runner organization's ids don't match.
* Usually occurs when a user tries to change a runner organization's id.
*/
export class RunnerOrganizationIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "RunnerOrganizationIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a runner organization's id: This isn't allowed!"
}
/**
* Error to throw when a organization still has runners associated.
*/
export class RunnerOrganizationHasRunnersError extends NotAcceptableError {
@IsString()
name = "RunnerOrganizationHasRunnersError"
@IsString()
message = "This organization still has runners associated with it. \n If you want to delete this organization with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw when a organization still has teams associated.
*/
export class RunnerOrganizationHasTeamsError extends NotAcceptableError {
@IsString()
name = "RunnerOrganizationHasTeamsError"
@IsString()
message = "This organization still has teams associated with it. \n If you want to delete this organization with all it's runners and teams add `?force` to your query."
}
/**
* Error to throw, when a provided runnerOrganization doesn't belong to the accepted types.
*/
export class RunnerOrganizationWrongTypeError extends NotAcceptableError {
@IsString()
name = "RunnerOrganizationWrongTypeError"
@IsString()
message = "The runner organization must be an existing organization's id. \n You provided a object of another type."
}

View File

@ -43,5 +43,5 @@ export class RunnerTeamNeedsParentError extends NotAcceptableError {
name = "RunnerTeamNeedsParentError" name = "RunnerTeamNeedsParentError"
@IsString() @IsString()
message = "You provided no runner organisation as this team's parent group." message = "You provided no runner organization as this team's parent group."
} }

View File

@ -1,6 +1,7 @@
import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator'; import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
import * as jsonwebtoken from "jsonwebtoken"; import * as jsonwebtoken from "jsonwebtoken";
import { config } from './config'; import { config } from './config';
import { Runner } from './models/entities/Runner';
import { User } from './models/entities/User'; import { User } from './models/entities/User';
/** /**
@ -34,6 +35,19 @@ export class JwtCreator {
}, config.jwt_secret) }, config.jwt_secret)
} }
/**
* Creates a new selfservice token for a given runner.
* @param runner Runner entity that the access token shall be created for.
* @param expiry_timestamp Timestamp for the token expiry. Will be set about 9999 years if none provided.
*/
public static createSelfService(runner: Runner, expiry_timestamp?: number) {
if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 36000 * 60 * 24 * 365 * 9999; }
return jsonwebtoken.sign({
id: runner.id,
exp: expiry_timestamp
}, config.jwt_secret)
}
/** /**
* Creates a new password reset token for a given user. * Creates a new password reset token for a given user.
* The token is valid for 15 minutes or 1 use - whatever comes first. * The token is valid for 15 minutes or 1 use - whatever comes first.

View File

@ -42,7 +42,7 @@ const StatsAuth = async (req: Request, res: Response, next: () => void) => {
let user_authorized = false; let user_authorized = false;
try { try {
let action = { request: req, response: res, context: null, next: next } let action = { request: req, response: res, context: null, next: next }
user_authorized = await authchecker(action, ["RUNNER:GET", "TEAM:GET", "ORGANISATION:GET"]); user_authorized = await authchecker(action, ["RUNNER:GET", "TEAM:GET", "ORGANIZATION:GET"]);
} }
finally { finally {
if (user_authorized == false) { if (user_authorized == false) {

View File

@ -1,9 +1,9 @@
import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { RunnerGroupNeededError } from '../../errors/RunnerErrors'; import { RunnerGroupNeededError } from '../../errors/RunnerErrors';
import { RunnerOrganisationNotFoundError } from '../../errors/RunnerOrganisationErrors'; import { RunnerOrganizationNotFoundError } from '../../errors/RunnerOrganizationErrors';
import { RunnerGroup } from '../entities/RunnerGroup'; import { RunnerGroup } from '../entities/RunnerGroup';
import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerOrganization } from '../entities/RunnerOrganization';
import { RunnerTeam } from '../entities/RunnerTeam'; import { RunnerTeam } from '../entities/RunnerTeam';
import { CreateRunner } from './create/CreateRunner'; import { CreateRunner } from './create/CreateRunner';
@ -78,9 +78,9 @@ export class ImportRunner {
let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: groupID }); let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: groupID });
if (team) { return team; } if (team) { return team; }
let org = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: groupID }); let org = await getConnectionManager().get().getRepository(RunnerOrganization).findOne({ id: groupID });
if (!org) { if (!org) {
throw new RunnerOrganisationNotFoundError(); throw new RunnerOrganizationNotFoundError();
} }
if (this.team === undefined) { return org; } if (this.team === undefined) { return org; }

View File

@ -1,7 +1,7 @@
import { IsInt } from 'class-validator'; import { IsInt } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors'; import { RunnerGroupNotFoundError } from '../../../errors/RunnerGroupErrors';
import { RunnerOrganisationWrongTypeError } from '../../../errors/RunnerOrganisationErrors'; import { RunnerOrganizationWrongTypeError } from '../../../errors/RunnerOrganizationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { Address } from '../../entities/Address'; import { Address } from '../../entities/Address';
import { Runner } from '../../entities/Runner'; import { Runner } from '../../entities/Runner';
@ -50,6 +50,6 @@ export class CreateRunner extends CreateParticipant {
return group; return group;
} }
throw new RunnerOrganisationWrongTypeError; throw new RunnerOrganizationWrongTypeError;
} }
} }

View File

@ -1,30 +0,0 @@
import { IsObject, IsOptional } from 'class-validator';
import { Address } from '../../entities/Address';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation';
import { CreateRunnerGroup } from './CreateRunnerGroup';
/**
* This classed is used to create a new RunnerOrganisation entity from a json body (post request).
*/
export class CreateRunnerOrganisation extends CreateRunnerGroup {
/**
* The new organisation's address.
*/
@IsOptional()
@IsObject()
address?: Address;
/**
* Creates a new RunnerOrganisation entity from this.
*/
public async toEntity(): Promise<RunnerOrganisation> {
let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation();
newRunnerOrganisation.name = this.name;
newRunnerOrganisation.contact = await this.getContact();
newRunnerOrganisation.address = this.address;
Address.validate(newRunnerOrganisation.address);
return newRunnerOrganisation;
}
}

View File

@ -0,0 +1,43 @@
import { IsBoolean, IsObject, IsOptional } from 'class-validator';
import * as uuid from 'uuid';
import { Address } from '../../entities/Address';
import { RunnerOrganization } from '../../entities/RunnerOrganization';
import { CreateRunnerGroup } from './CreateRunnerGroup';
/**
* This classed is used to create a new RunnerOrganization entity from a json body (post request).
*/
export class CreateRunnerOrganization extends CreateRunnerGroup {
/**
* The new organization's address.
*/
@IsOptional()
@IsObject()
address?: Address;
/**
* Is registration enabled for the new organization?
*/
@IsOptional()
@IsBoolean()
registrationEnabled?: boolean = false;
/**
* Creates a new RunnerOrganization entity from this.
*/
public async toEntity(): Promise<RunnerOrganization> {
let newRunnerOrganization: RunnerOrganization = new RunnerOrganization();
newRunnerOrganization.name = this.name;
newRunnerOrganization.contact = await this.getContact();
newRunnerOrganization.address = this.address;
Address.validate(newRunnerOrganization.address);
if (this.registrationEnabled) {
newRunnerOrganization.key = uuid.v4().toUpperCase();
}
return newRunnerOrganization;
}
}

View File

@ -1,8 +1,8 @@
import { IsInt, IsNotEmpty } from 'class-validator'; import { IsInt, IsNotEmpty } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { RunnerOrganisationNotFoundError } from '../../../errors/RunnerOrganisationErrors'; import { RunnerOrganizationNotFoundError } from '../../../errors/RunnerOrganizationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation'; import { RunnerOrganization } from '../../entities/RunnerOrganization';
import { RunnerTeam } from '../../entities/RunnerTeam'; import { RunnerTeam } from '../../entities/RunnerTeam';
import { CreateRunnerGroup } from './CreateRunnerGroup'; import { CreateRunnerGroup } from './CreateRunnerGroup';
@ -21,12 +21,12 @@ export class CreateRunnerTeam extends CreateRunnerGroup {
/** /**
* Gets the new team's parent org based on it's id. * Gets the new team's parent org based on it's id.
*/ */
public async getParent(): Promise<RunnerOrganisation> { public async getParent(): Promise<RunnerOrganization> {
if (this.parentGroup === undefined || this.parentGroup === null) { if (this.parentGroup === undefined || this.parentGroup === null) {
throw new RunnerTeamNeedsParentError(); throw new RunnerTeamNeedsParentError();
} }
let parentGroup = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: this.parentGroup }); let parentGroup = await getConnectionManager().get().getRepository(RunnerOrganization).findOne({ id: this.parentGroup });
if (!parentGroup) { throw new RunnerOrganisationNotFoundError();; } if (!parentGroup) { throw new RunnerOrganizationNotFoundError();; }
return parentGroup; return parentGroup;
} }

View File

@ -0,0 +1,52 @@
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerEmailNeededError } from '../../../errors/RunnerErrors';
import { Address } from '../../entities/Address';
import { Runner } from '../../entities/Runner';
import { RunnerOrganization } from '../../entities/RunnerOrganization';
import { CreateParticipant } from './CreateParticipant';
/**
* This classed is used to create a new Runner entity from a json body (post request).
*/
export class CreateSelfServiceCitizenRunner extends CreateParticipant {
/**
* The new runners's e-mail address.
* Must be provided for email-verification to work.
*/
@IsString()
@IsNotEmpty()
@IsEmail()
email: string;
/**
* Creates a new Runner entity from this.
*/
public async toEntity(): Promise<Runner> {
let newRunner: Runner = new Runner();
newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname;
newRunner.phone = this.phone;
newRunner.email = this.email;
if (!newRunner.email) {
throw new RunnerEmailNeededError();
}
newRunner.group = await this.getGroup();
newRunner.address = this.address;
Address.validate(newRunner.address);
return newRunner;
}
/**
* Gets the new runner's group by it's id.
*/
public async getGroup(): Promise<RunnerOrganization> {
return await getConnection().getRepository(RunnerOrganization).findOne({ id: 1 });
}
}

View File

@ -0,0 +1,55 @@
import { IsInt, IsOptional } from 'class-validator';
import { getConnection } from 'typeorm';
import { RunnerTeamNotFoundError } from '../../../errors/RunnerTeamErrors';
import { Address } from '../../entities/Address';
import { Runner } from '../../entities/Runner';
import { RunnerGroup } from '../../entities/RunnerGroup';
import { RunnerTeam } from '../../entities/RunnerTeam';
import { CreateParticipant } from './CreateParticipant';
/**
* This classed is used to create a new Runner entity from a json body (post request).
*/
export class CreateSelfServiceRunner extends CreateParticipant {
/**
* The new runner's team's id.
* The team has to be a part of the runner's org.
* The team property may get ignored.
* If no team get's provided the runner's group will be their org.
*/
@IsInt()
@IsOptional()
team?: number;
/**
* Creates a new Runner entity from this.
*/
public async toEntity(group: RunnerGroup): Promise<Runner> {
let newRunner: Runner = new Runner();
newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname;
newRunner.phone = this.phone;
newRunner.email = this.email;
newRunner.group = await this.getGroup(group);
newRunner.address = this.address;
Address.validate(newRunner.address);
return newRunner;
}
/**
* Gets the new runner's group by it's id.
*/
public async getGroup(group: RunnerGroup): Promise<RunnerGroup> {
if (!this.team) {
return group;
}
const team = await getConnection().getRepository(RunnerTeam).findOne({ id: this.team }, { relations: ["parentGroup"] });
if (!team) { throw new RunnerTeamNotFoundError(); }
if (team.parentGroup.id != group.id) { throw new RunnerTeamNotFoundError(); }
return team;
}
}

View File

@ -1,38 +0,0 @@
import { IsInt, IsObject, IsOptional } from 'class-validator';
import { Address } from '../../entities/Address';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation';
import { CreateRunnerGroup } from '../create/CreateRunnerGroup';
/**
* This class is used to update a RunnerOrganisation entity (via put request).
*/
export class UpdateRunnerOrganisation extends CreateRunnerGroup {
/**
* The updated orgs's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated organisation's address.
*/
@IsOptional()
@IsObject()
address?: Address;
/**
* Updates a provided RunnerOrganisation entity based on this.
*/
public async update(organisation: RunnerOrganisation): Promise<RunnerOrganisation> {
organisation.name = this.name;
organisation.contact = await this.getContact();
if (!this.address) { organisation.address.reset(); }
else { organisation.address = this.address; }
Address.validate(organisation.address);
return organisation;
}
}

View File

@ -0,0 +1,53 @@
import { IsBoolean, IsInt, IsObject, IsOptional } from 'class-validator';
import * as uuid from 'uuid';
import { Address } from '../../entities/Address';
import { RunnerOrganization } from '../../entities/RunnerOrganization';
import { CreateRunnerGroup } from '../create/CreateRunnerGroup';
/**
* This class is used to update a RunnerOrganization entity (via put request).
*/
export class UpdateRunnerOrganization extends CreateRunnerGroup {
/**
* The updated orgs's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* The updated organization's address.
*/
@IsOptional()
@IsObject()
address?: Address;
/**
* Is registration enabled for the updated organization?
*/
@IsOptional()
@IsBoolean()
registrationEnabled?: boolean = false;
/**
* Updates a provided RunnerOrganization entity based on this.
*/
public async update(organization: RunnerOrganization): Promise<RunnerOrganization> {
organization.name = this.name;
organization.contact = await this.getContact();
if (!this.address) { organization.address.reset(); }
else { organization.address = this.address; }
Address.validate(organization.address);
if (this.registrationEnabled && !organization.key) {
organization.key = uuid.v4().toUpperCase();
}
else {
organization.key = null;
}
return organization;
}
}

View File

@ -1,8 +1,8 @@
import { IsInt, IsPositive } from 'class-validator'; import { IsInt, IsPositive } from 'class-validator';
import { getConnectionManager } from 'typeorm'; import { getConnectionManager } from 'typeorm';
import { RunnerOrganisationNotFoundError } from '../../../errors/RunnerOrganisationErrors'; import { RunnerOrganizationNotFoundError } from '../../../errors/RunnerOrganizationErrors';
import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors'; import { RunnerTeamNeedsParentError } from '../../../errors/RunnerTeamErrors';
import { RunnerOrganisation } from '../../entities/RunnerOrganisation'; import { RunnerOrganization } from '../../entities/RunnerOrganization';
import { RunnerTeam } from '../../entities/RunnerTeam'; import { RunnerTeam } from '../../entities/RunnerTeam';
import { CreateRunnerGroup } from '../create/CreateRunnerGroup'; import { CreateRunnerGroup } from '../create/CreateRunnerGroup';
@ -28,12 +28,12 @@ export class UpdateRunnerTeam extends CreateRunnerGroup {
/** /**
* Loads the updated teams's parentGroup based on it's id. * Loads the updated teams's parentGroup based on it's id.
*/ */
public async getParent(): Promise<RunnerOrganisation> { public async getParent(): Promise<RunnerOrganization> {
if (this.parentGroup === undefined || this.parentGroup === null) { if (this.parentGroup === undefined || this.parentGroup === null) {
throw new RunnerTeamNeedsParentError(); throw new RunnerTeamNeedsParentError();
} }
let parentGroup = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: this.parentGroup }); let parentGroup = await getConnectionManager().get().getRepository(RunnerOrganization).findOne({ id: this.parentGroup });
if (!parentGroup) { throw new RunnerOrganisationNotFoundError();; } if (!parentGroup) { throw new RunnerOrganizationNotFoundError();; }
return parentGroup; return parentGroup;
} }

View File

@ -16,7 +16,7 @@ import { Scan } from "./Scan";
export class Runner extends Participant { export class Runner extends Participant {
/** /**
* The runner's associated group. * The runner's associated group.
* Can be a runner team or organisation. * Can be a runner team or organization.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => RunnerGroup, group => group.runners) @ManyToOne(() => RunnerGroup, group => group.runners)

View File

@ -1,34 +1,44 @@
import { IsInt, IsOptional } from "class-validator"; import { IsInt, IsOptional, IsString } from "class-validator";
import { ChildEntity, Column, OneToMany } from "typeorm"; import { ChildEntity, Column, OneToMany } from "typeorm";
import { ResponseRunnerOrganisation } from '../responses/ResponseRunnerOrganisation'; import { ResponseRunnerOrganization } from '../responses/ResponseRunnerOrganization';
import { Address } from './Address'; import { Address } from './Address';
import { Runner } from './Runner'; import { Runner } from './Runner';
import { RunnerGroup } from "./RunnerGroup"; import { RunnerGroup } from "./RunnerGroup";
import { RunnerTeam } from "./RunnerTeam"; import { RunnerTeam } from "./RunnerTeam";
/** /**
* Defines the RunnerOrganisation entity. * Defines the RunnerOrganization entity.
* This usually is a school, club or company. * This usually is a school, club or company.
*/ */
@ChildEntity() @ChildEntity()
export class RunnerOrganisation extends RunnerGroup { export class RunnerOrganization extends RunnerGroup {
/** /**
* The organisations's address. * The organizations's address.
*/ */
@IsOptional() @IsOptional()
@Column(type => Address) @Column(type => Address)
address?: Address; address?: Address;
/** /**
* The organisation's teams. * The organization's teams.
* Used to link teams to a organisation. * Used to link teams to a organization.
*/ */
@OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true }) @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true })
teams: RunnerTeam[]; teams: RunnerTeam[];
/** /**
* Returns all runners associated with this organisation (directly or indirectly via teams). * The organization's api key for self-service registration.
* The api key can be used for the /runners/register/:token endpoint.
* Is has to be base64 encoded if used via the api (to keep url-safety).
*/
@Column({ nullable: true, unique: true })
@IsString()
@IsOptional()
key?: string;
/**
* Returns all runners associated with this organization (directly or indirectly via teams).
*/ */
public get allRunners(): Runner[] { public get allRunners(): Runner[] {
let returnRunners: Runner[] = new Array<Runner>(); let returnRunners: Runner[] = new Array<Runner>();
@ -58,7 +68,7 @@ export class RunnerOrganisation extends RunnerGroup {
/** /**
* Turns this entity into it's response class. * Turns this entity into it's response class.
*/ */
public toResponse(): ResponseRunnerOrganisation { public toResponse(): ResponseRunnerOrganization {
return new ResponseRunnerOrganisation(this); return new ResponseRunnerOrganization(this);
} }
} }

View File

@ -2,7 +2,7 @@ import { IsNotEmpty } from "class-validator";
import { ChildEntity, ManyToOne } from "typeorm"; import { ChildEntity, ManyToOne } from "typeorm";
import { ResponseRunnerTeam } from '../responses/ResponseRunnerTeam'; import { ResponseRunnerTeam } from '../responses/ResponseRunnerTeam';
import { RunnerGroup } from "./RunnerGroup"; import { RunnerGroup } from "./RunnerGroup";
import { RunnerOrganisation } from "./RunnerOrganisation"; import { RunnerOrganization } from "./RunnerOrganization";
/** /**
* Defines the RunnerTeam entity. * Defines the RunnerTeam entity.
@ -13,11 +13,11 @@ export class RunnerTeam extends RunnerGroup {
/** /**
* The team's parent group. * The team's parent group.
* Every team has to be part of a runnerOrganisation - this get's checked on creation and update. * Every team has to be part of a runnerOrganization - this get's checked on creation and update.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => RunnerOrganisation, org => org.teams, { nullable: true }) @ManyToOne(() => RunnerOrganization, org => org.teams, { nullable: true })
parentGroup?: RunnerOrganisation; parentGroup?: RunnerOrganization;
/** /**
* Turns this entity into it's response class. * Turns this entity into it's response class.

View File

@ -3,7 +3,7 @@
*/ */
export enum PermissionTarget { export enum PermissionTarget {
RUNNER = 'RUNNER', RUNNER = 'RUNNER',
ORGANISATION = 'ORGANISATION', ORGANIZATION = 'ORGANIZATION',
TEAM = 'TEAM', TEAM = 'TEAM',
TRACK = 'TRACK', TRACK = 'TRACK',
USER = 'USER', USER = 'USER',

View File

@ -1,39 +0,0 @@
import {
IsArray,
IsObject,
IsOptional
} from "class-validator";
import { Address } from '../entities/Address';
import { RunnerOrganisation } from '../entities/RunnerOrganisation';
import { RunnerTeam } from '../entities/RunnerTeam';
import { ResponseRunnerGroup } from './ResponseRunnerGroup';
/**
* Defines the runnerOrganisation response.
*/
export class ResponseRunnerOrganisation extends ResponseRunnerGroup {
/**
* The runnerOrganisation's address.
*/
@IsObject()
@IsOptional()
address?: Address;
/**
* The runnerOrganisation associated teams.
*/
@IsArray()
teams: RunnerTeam[];
/**
* Creates a ResponseRunnerOrganisation object from a runnerOrganisation.
* @param org The runnerOrganisation the response shall be build for.
*/
public constructor(org: RunnerOrganisation) {
super(org);
this.address = org.address;
this.teams = org.teams;
}
}

View File

@ -0,0 +1,62 @@
import {
IsArray,
IsBase64,
IsBoolean,
IsObject,
IsOptional,
IsString
} from "class-validator";
import { Address } from '../entities/Address';
import { RunnerOrganization } from '../entities/RunnerOrganization';
import { RunnerTeam } from '../entities/RunnerTeam';
import { ResponseRunnerGroup } from './ResponseRunnerGroup';
/**
* Defines the runnerOrganization response.
*/
export class ResponseRunnerOrganization extends ResponseRunnerGroup {
/**
* The runnerOrganization's address.
*/
@IsObject()
@IsOptional()
address?: Address;
/**
* The runnerOrganization associated teams.
*/
@IsArray()
teams: RunnerTeam[];
/**
* The organization's registration key.
* If registration is disabled this is null.
*/
@IsString()
@IsOptional()
@IsBase64()
registrationKey?: string;
/**
* Is registration enabled for the organization?
*/
@IsOptional()
@IsBoolean()
registrationEnabled?: boolean = true;
/**
* Creates a ResponseRunnerOrganization object from a runnerOrganization.
* @param org The runnerOrganization the response shall be build for.
*/
public constructor(org: RunnerOrganization) {
super(org);
this.address = org.address;
this.teams = org.teams;
if (!org.key) { this.registrationEnabled = false; }
else { this.registrationKey = Buffer.from(org.key).toString('base64'); }
}
}

View File

@ -1,7 +1,7 @@
import { IsNotEmpty, IsObject } from "class-validator"; import { IsNotEmpty, IsObject } from "class-validator";
import { RunnerOrganisation } from '../entities/RunnerOrganisation';
import { RunnerTeam } from '../entities/RunnerTeam'; import { RunnerTeam } from '../entities/RunnerTeam';
import { ResponseRunnerGroup } from './ResponseRunnerGroup'; import { ResponseRunnerGroup } from './ResponseRunnerGroup';
import { ResponseRunnerOrganization } from './ResponseRunnerOrganization';
/** /**
* Defines the runnerTeam response. * Defines the runnerTeam response.
@ -9,11 +9,11 @@ import { ResponseRunnerGroup } from './ResponseRunnerGroup';
export class ResponseRunnerTeam extends ResponseRunnerGroup { export class ResponseRunnerTeam extends ResponseRunnerGroup {
/** /**
* The runnerTeam's parent group (organisation). * The runnerTeam's parent group (organization).
*/ */
@IsObject() @IsObject()
@IsNotEmpty() @IsNotEmpty()
parentGroup: RunnerOrganisation; parentGroup: ResponseRunnerOrganization;
/** /**
* Creates a ResponseRunnerTeam object from a runnerTeam. * Creates a ResponseRunnerTeam object from a runnerTeam.
@ -21,6 +21,6 @@ export class ResponseRunnerTeam extends ResponseRunnerGroup {
*/ */
public constructor(team: RunnerTeam) { public constructor(team: RunnerTeam) {
super(team); super(team);
this.parentGroup = team.parentGroup; this.parentGroup = team.parentGroup.toResponse();
} }
} }

View File

@ -1,4 +1,4 @@
import { IsInt, IsString } from "class-validator"; import { IsInt, IsOptional, IsString } from "class-validator";
import { DistanceDonation } from '../entities/DistanceDonation'; import { DistanceDonation } from '../entities/DistanceDonation';
import { Runner } from '../entities/Runner'; import { Runner } from '../entities/Runner';
import { RunnerGroup } from '../entities/RunnerGroup'; import { RunnerGroup } from '../entities/RunnerGroup';
@ -36,6 +36,14 @@ export class ResponseSelfServiceRunner extends ResponseParticipant {
@IsString() @IsString()
donations: ResponseSelfServiceDonation[] donations: ResponseSelfServiceDonation[]
/**
* The runner's self-service jwt for auth.
* Will only get delivered on registration/via email.
*/
@IsString()
@IsOptional()
token: string;
/** /**
* Creates a ResponseRunner object from a runner. * Creates a ResponseRunner object from a runner.
* @param runner The user the response shall be build for. * @param runner The user the response shall be build for.

View File

@ -3,7 +3,7 @@ import {
} from "class-validator"; } from "class-validator";
import { Donation } from '../entities/Donation'; import { Donation } from '../entities/Donation';
import { Runner } from '../entities/Runner'; import { Runner } from '../entities/Runner';
import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerOrganization } from '../entities/RunnerOrganization';
import { RunnerTeam } from '../entities/RunnerTeam'; import { RunnerTeam } from '../entities/RunnerTeam';
import { Scan } from '../entities/Scan'; import { Scan } from '../entities/Scan';
import { User } from '../entities/User'; import { User } from '../entities/User';
@ -26,7 +26,7 @@ export class ResponseStats {
total_teams: number; total_teams: number;
/** /**
* The amount of organisations registered in the system. * The amount of organizations registered in the system.
*/ */
@IsInt() @IsInt()
total_orgs: number; total_orgs: number;
@ -70,7 +70,7 @@ export class ResponseStats {
* @param scans Array containing all scans - no relations have to be resolved. * @param scans Array containing all scans - no relations have to be resolved.
* @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track * @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track
*/ */
public constructor(runners: Runner[], teams: RunnerTeam[], orgs: RunnerOrganisation[], users: User[], scans: Scan[], donations: Donation[]) { public constructor(runners: Runner[], teams: RunnerTeam[], orgs: RunnerOrganization[], users: User[], scans: Scan[], donations: Donation[]) {
this.total_runners = runners.length; this.total_runners = runners.length;
this.total_teams = teams.length; this.total_teams = teams.length;
this.total_orgs = orgs.length; this.total_orgs = orgs.length;

View File

@ -3,7 +3,7 @@ import {
IsString IsString
} from "class-validator"; } from "class-validator";
import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerOrganization } from '../entities/RunnerOrganization';
/** /**
* Defines the org stats response. * Defines the org stats response.
@ -35,10 +35,10 @@ export class ResponseStatsOrgnisation {
donationAmount: number; donationAmount: number;
/** /**
* Creates a new organisation stats response from a organisation * Creates a new organization stats response from a organization
* @param org The organisation whoes response shall be generated - the following relations have to be resolved: runners, runners.scans, runners.distanceDonations, runners.scans.track, teams, teams.runners, teams.runners.scans, teams.runners.distanceDonations, teams.runners.scans.track * @param org The organization whoes response shall be generated - the following relations have to be resolved: runners, runners.scans, runners.distanceDonations, runners.scans.track, teams, teams.runners, teams.runners.scans, teams.runners.distanceDonations, teams.runners.scans.track
*/ */
public constructor(org: RunnerOrganisation) { public constructor(org: RunnerOrganization) {
this.name = org.name; this.name = org.name;
this.id = org.id; this.id = org.id;
this.distance = org.distance; this.distance = org.distance;

View File

@ -1,15 +1,15 @@
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { Factory, Seeder } from 'typeorm-seeding'; import { Factory, Seeder } from 'typeorm-seeding';
import { CreateRunnerOrganisation } from '../models/actions/create/CreateRunnerOrganisation'; import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization';
import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; import { RunnerOrganization } from '../models/entities/RunnerOrganization';
/** /**
* Seeds the public runner org (named: "Citizen" by default). * Seeds the public runner org (named: "Citizen" by default).
*/ */
export default class SeedPublicOrg implements Seeder { export default class SeedPublicOrg implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<any> { public async run(factory: Factory, connection: Connection): Promise<any> {
let publicOrg = new CreateRunnerOrganisation(); let publicOrg = new CreateRunnerOrganization();
publicOrg.name = "Citizen"; publicOrg.name = "Citizen";
await connection.getRepository(RunnerOrganisation).save(await publicOrg.toEntity()); await connection.getRepository(RunnerOrganization).save(await publicOrg.toEntity());
} }
} }

View File

@ -2,13 +2,13 @@ import { Connection } from 'typeorm';
import { Factory, Seeder } from 'typeorm-seeding'; import { Factory, Seeder } from 'typeorm-seeding';
import { CreateGroupContact } from '../models/actions/create/CreateGroupContact'; import { CreateGroupContact } from '../models/actions/create/CreateGroupContact';
import { CreateRunner } from '../models/actions/create/CreateRunner'; import { CreateRunner } from '../models/actions/create/CreateRunner';
import { CreateRunnerOrganisation } from '../models/actions/create/CreateRunnerOrganisation'; import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization';
import { CreateRunnerTeam } from '../models/actions/create/CreateRunnerTeam'; import { CreateRunnerTeam } from '../models/actions/create/CreateRunnerTeam';
import { Address } from '../models/entities/Address'; import { Address } from '../models/entities/Address';
import { GroupContact } from '../models/entities/GroupContact'; import { GroupContact } from '../models/entities/GroupContact';
import { Runner } from '../models/entities/Runner'; import { Runner } from '../models/entities/Runner';
import { RunnerGroup } from '../models/entities/RunnerGroup'; import { RunnerGroup } from '../models/entities/RunnerGroup';
import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; import { RunnerOrganization } from '../models/entities/RunnerOrganization';
import { RunnerTeam } from '../models/entities/RunnerTeam'; import { RunnerTeam } from '../models/entities/RunnerTeam';
/** /**
@ -17,15 +17,15 @@ import { RunnerTeam } from '../models/entities/RunnerTeam';
*/ */
export default class SeedTestRunners implements Seeder { export default class SeedTestRunners implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<any> { public async run(factory: Factory, connection: Connection): Promise<any> {
let testOrg: RunnerOrganisation = await this.createTestOrg(connection); let testOrg: RunnerOrganization = await this.createTestOrg(connection);
let testTeam: RunnerTeam = await this.createTestTeam(connection, testOrg); let testTeam: RunnerTeam = await this.createTestTeam(connection, testOrg);
await this.createTestContact(connection, testOrg); await this.createTestContact(connection, testOrg);
await this.createTestRunners(connection, testOrg); await this.createTestRunners(connection, testOrg);
await this.createTestRunners(connection, testTeam); await this.createTestRunners(connection, testTeam);
} }
public async createTestOrg(connection: Connection): Promise<RunnerOrganisation> { public async createTestOrg(connection: Connection): Promise<RunnerOrganization> {
let testOrg = new CreateRunnerOrganisation(); let testOrg = new CreateRunnerOrganization();
testOrg.name = "Test Org"; testOrg.name = "Test Org";
testOrg.address = new Address(); testOrg.address = new Address();
@ -34,10 +34,10 @@ export default class SeedTestRunners implements Seeder {
testOrg.address.country = "Germany"; testOrg.address.country = "Germany";
testOrg.address.postalcode = "90174"; testOrg.address.postalcode = "90174";
return await connection.getRepository(RunnerOrganisation).save(await testOrg.toEntity()); return await connection.getRepository(RunnerOrganization).save(await testOrg.toEntity());
} }
public async createTestTeam(connection: Connection, org: RunnerOrganisation): Promise<RunnerTeam> { public async createTestTeam(connection: Connection, org: RunnerOrganization): Promise<RunnerTeam> {
let testTeam = new CreateRunnerTeam(); let testTeam = new CreateRunnerTeam();
testTeam.name = "Test Team"; testTeam.name = "Test Team";
testTeam.parentGroup = org.id; testTeam.parentGroup = org.id;

View File

@ -69,7 +69,7 @@ describe('POST /api/cards successfully (with runner)', () => {
let added_org; let added_org;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -50,7 +50,7 @@ describe('adding + updating card.runner successfully', () => {
let added_runner2; let added_runner2;
let added_card; let added_card;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -108,7 +108,7 @@ describe('POST /api/contacts working (with group)', () => {
let added_team; let added_team;
let added_contact; let added_contact;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;
@ -123,7 +123,6 @@ describe('POST /api/contacts working (with group)', () => {
"parentGroup": added_org.id "parentGroup": added_org.id
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;
delete res.data.parentGroup;
added_team = res.data; added_team = res.data;
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")

View File

@ -50,7 +50,7 @@ describe('add+delete (with org)', () => {
let added_org; let added_org;
let added_contact; let added_contact;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;
@ -88,7 +88,7 @@ describe('add+delete (with team)', () => {
let added_team; let added_team;
let added_contact; let added_contact;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;
@ -137,7 +137,7 @@ describe('add+delete (with org&team)', () => {
let added_team; let added_team;
let added_contact; let added_contact;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;

View File

@ -59,7 +59,7 @@ describe('Update contact group after adding (should work)', () => {
let added_team; let added_team;
let added_contact; let added_contact;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;
@ -74,7 +74,6 @@ describe('Update contact group after adding (should work)', () => {
"parentGroup": added_org.id "parentGroup": added_org.id
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;
delete res.data.parentGroup;
added_team = res.data; added_team = res.data;
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
@ -112,6 +111,7 @@ describe('Update contact group after adding (should work)', () => {
"lastname": "last", "lastname": "last",
"groups": added_team.id "groups": added_team.id
}, axios_config); }, axios_config);
console.log(res.data)
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
expect(res.data).toEqual({ expect(res.data).toEqual({
@ -189,7 +189,7 @@ describe('Update contact group invalid after adding (should fail)', () => {
let added_org; let added_org;
let added_contact; let added_contact;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res.data.contact; delete res.data.contact;

View File

@ -83,7 +83,7 @@ describe('POST /api/donations/distance illegally', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -199,7 +199,7 @@ describe('POST /api/donations/distance successfully', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data

View File

@ -70,7 +70,7 @@ describe('DELETE distance donation', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data

View File

@ -73,7 +73,7 @@ describe('adding + getting distance donation', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data

View File

@ -84,7 +84,7 @@ describe('adding + updating distance donation illegally', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -253,7 +253,7 @@ describe('adding + updating distance donation valid', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data

View File

@ -60,7 +60,7 @@ describe('DELETE donor with donations invalid', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -115,7 +115,7 @@ describe('DELETE donor with donations valid', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data

View File

@ -14,24 +14,24 @@ beforeAll(async () => {
}; };
}); });
describe('GET /api/organisations', () => { describe('GET /api/organizations', () => {
it('basic get should return 200', async () => { it('basic get should return 200', async () => {
const res = await axios.get(base + '/api/organisations', axios_config); const res = await axios.get(base + '/api/organizations', axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
}); });
// --------------- // ---------------
describe('POST /api/organisations', () => { describe('POST /api/organizations', () => {
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with without a name should return 400', async () => { it('creating a new org with without a name should return 400', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": null "name": null
}, axios_config); }, axios_config);
expect(res.status).toEqual(400); expect(res.status).toEqual(400);
@ -41,14 +41,14 @@ describe('POST /api/organisations', () => {
// --------------- // ---------------
describe('adding + getting from all orgs', () => { describe('adding + getting from all orgs', () => {
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('check if org was added', async () => { it('check if org was added', async () => {
const res = await axios.get(base + '/api/organisations', axios_config); const res = await axios.get(base + '/api/organizations', axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
let added_org = res.data[res.data.length - 1] let added_org = res.data[res.data.length - 1]
@ -63,6 +63,7 @@ describe('adding + getting from all orgs', () => {
"country": null, "country": null,
"postalcode": null, "postalcode": null,
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}) })
}); });
@ -71,7 +72,7 @@ describe('adding + getting from all orgs', () => {
describe('adding + getting explicitly', () => { describe('adding + getting explicitly', () => {
let added_org_id let added_org_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data
@ -80,7 +81,7 @@ describe('adding + getting explicitly', () => {
expect(res1.headers['content-type']).toContain("application/json") expect(res1.headers['content-type']).toContain("application/json")
}); });
it('check if org was added', async () => { it('check if org was added', async () => {
const res2 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); const res2 = await axios.get(base + '/api/organizations/' + added_org_id, axios_config);
expect(res2.status).toEqual(200); expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
let added_org2 = res2.data let added_org2 = res2.data
@ -96,6 +97,7 @@ describe('adding + getting explicitly', () => {
"country": null, "country": null,
"postalcode": null, "postalcode": null,
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}) })
}); });

View File

@ -17,7 +17,7 @@ beforeAll(async () => {
// --------------- // ---------------
describe('adding + deletion (non-existant)', () => { describe('adding + deletion (non-existant)', () => {
it('delete', async () => { it('delete', async () => {
const res2 = await axios.delete(base + '/api/organisations/0', axios_config); const res2 = await axios.delete(base + '/api/organizations/0', axios_config);
expect(res2.status).toEqual(204); expect(res2.status).toEqual(204);
}); });
}); });
@ -26,7 +26,7 @@ describe('adding + deletion (successfull)', () => {
let added_org_id let added_org_id
let added_org let added_org
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -35,7 +35,7 @@ describe('adding + deletion (successfull)', () => {
expect(res1.headers['content-type']).toContain("application/json") expect(res1.headers['content-type']).toContain("application/json")
}); });
it('delete', async () => { it('delete', async () => {
const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, axios_config); const res2 = await axios.delete(base + '/api/organizations/' + added_org_id, axios_config);
expect(res2.status).toEqual(200); expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
let added_org2 = res2.data let added_org2 = res2.data
@ -51,11 +51,12 @@ describe('adding + deletion (successfull)', () => {
"country": null, "country": null,
"postalcode": null, "postalcode": null,
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('check if org really was deleted', async () => { it('check if org really was deleted', async () => {
const res3 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); const res3 = await axios.get(base + '/api/organizations/' + added_org_id, axios_config);
expect(res3.status).toEqual(404); expect(res3.status).toEqual(404);
expect(res3.headers['content-type']).toContain("application/json") expect(res3.headers['content-type']).toContain("application/json")
}); });
@ -67,7 +68,7 @@ describe('adding + deletion with teams still existing (without force)', () => {
let added_team; let added_team;
let added_team_id let added_team_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data; added_org = res1.data;
@ -86,7 +87,7 @@ describe('adding + deletion with teams still existing (without force)', () => {
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
}); });
it('delete org - this should fail with a 406', async () => { it('delete org - this should fail with a 406', async () => {
const res2 = await axios.delete(base + '/api/organisations/' + added_org_id, axios_config); const res2 = await axios.delete(base + '/api/organizations/' + added_org_id, axios_config);
expect(res2.status).toEqual(406); expect(res2.status).toEqual(406);
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
}); });
@ -98,7 +99,7 @@ describe('adding + deletion with teams still existing (with force)', () => {
let added_team; let added_team;
let added_team_id let added_team_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data; added_org = res1.data;
@ -117,7 +118,7 @@ describe('adding + deletion with teams still existing (with force)', () => {
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
}); });
it('delete', async () => { it('delete', async () => {
const res2 = await axios.delete(base + '/api/organisations/' + added_org_id + '?force=true', axios_config); const res2 = await axios.delete(base + '/api/organizations/' + added_org_id + '?force=true', axios_config);
expect(res2.status).toEqual(200); expect(res2.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
let added_org2 = res2.data let added_org2 = res2.data
@ -134,10 +135,11 @@ describe('adding + deletion with teams still existing (with force)', () => {
"country": null, "country": null,
"postalcode": null, "postalcode": null,
}, },
"registrationEnabled": false,
}); });
}); });
it('check if org really was deleted', async () => { it('check if org really was deleted', async () => {
const res3 = await axios.get(base + '/api/organisations/' + added_org_id, axios_config); const res3 = await axios.get(base + '/api/organizations/' + added_org_id, axios_config);
expect(res3.status).toEqual(404); expect(res3.status).toEqual(404);
expect(res3.headers['content-type']).toContain("application/json") expect(res3.headers['content-type']).toContain("application/json")
}); });

View File

@ -14,15 +14,15 @@ beforeAll(async () => {
}; };
}); });
describe('GET /api/organisations', () => { describe('GET /api/organizations', () => {
it('basic get should return 200', async () => { it('basic get should return 200', async () => {
const res = await axios.get(base + '/api/organisations', axios_config); const res = await axios.get(base + '/api/organizations', axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
}); });
// --------------- // ---------------
describe('GET /api/organisations/0', () => { describe('GET /api/organizations/0', () => {
it('basic get should return 404', async () => { it('basic get should return 404', async () => {
const res = await axios.get(base + '/api/runners/0', axios_config); const res = await axios.get(base + '/api/runners/0', axios_config);
expect(res.status).toEqual(404); expect(res.status).toEqual(404);

View File

@ -19,7 +19,7 @@ describe('adding + updating name', () => {
let added_org_id let added_org_id
let added_org let added_org
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -28,7 +28,7 @@ describe('adding + updating name', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('update org', async () => { it('update org', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -49,6 +49,7 @@ describe('adding + updating name', () => {
"country": null, "country": null,
"postalcode": null, "postalcode": null,
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}) })
}); });
@ -58,7 +59,7 @@ describe('adding + try updating id (should return 406)', () => {
let added_org_id let added_org_id
let added_org let added_org
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -67,7 +68,7 @@ describe('adding + try updating id (should return 406)', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('update org', async () => { it('update org', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id + 1, "id": added_org_id + 1,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -82,7 +83,7 @@ describe('adding + updateing address valid)', () => {
let added_org_id let added_org_id
let added_org let added_org
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -91,7 +92,7 @@ describe('adding + updateing address valid)', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('adding address to org should return 200', async () => { it('adding address to org should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -116,11 +117,12 @@ describe('adding + updateing address valid)', () => {
"country": "Burkina Faso", "country": "Burkina Faso",
"postalcode": "90174" "postalcode": "90174"
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('updateing address\'s first line should return 200', async () => { it('updateing address\'s first line should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -145,11 +147,12 @@ describe('adding + updateing address valid)', () => {
"country": "Burkina Faso", "country": "Burkina Faso",
"postalcode": "90174" "postalcode": "90174"
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('updateing address\'s second line should return 200', async () => { it('updateing address\'s second line should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -174,11 +177,12 @@ describe('adding + updateing address valid)', () => {
"country": "Burkina Faso", "country": "Burkina Faso",
"postalcode": "90174" "postalcode": "90174"
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('updateing address\'s city should return 200', async () => { it('updateing address\'s city should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -203,11 +207,12 @@ describe('adding + updateing address valid)', () => {
"country": "Burkina Faso", "country": "Burkina Faso",
"postalcode": "90174" "postalcode": "90174"
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('updateing address\'s country should return 200', async () => { it('updateing address\'s country should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -232,11 +237,12 @@ describe('adding + updateing address valid)', () => {
"country": "Germany", "country": "Germany",
"postalcode": "90174" "postalcode": "90174"
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('updateing address\'s postal code should return 200', async () => { it('updateing address\'s postal code should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -261,14 +267,15 @@ describe('adding + updateing address valid)', () => {
"country": "Germany", "country": "Germany",
"postalcode": "91065" "postalcode": "91065"
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
it('removing org\'s should return 200', async () => { it('removing org\'s address should return 200', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null "contact": null,
}, axios_config); }, axios_config);
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
@ -283,6 +290,7 @@ describe('adding + updateing address valid)', () => {
"country": null, "country": null,
"postalcode": null "postalcode": null
}, },
"registrationEnabled": false,
"teams": [] "teams": []
}); });
}); });
@ -292,7 +300,7 @@ describe('adding + updateing address invalid)', () => {
let added_org_id let added_org_id
let added_org let added_org
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -301,7 +309,7 @@ describe('adding + updateing address invalid)', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('adding address to org w/o address1 should return 400', async () => { it('adding address to org w/o address1 should return 400', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -317,7 +325,7 @@ describe('adding + updateing address invalid)', () => {
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
}); });
it('adding address to org w/o city should return 400', async () => { it('adding address to org w/o city should return 400', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -333,7 +341,7 @@ describe('adding + updateing address invalid)', () => {
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
}); });
it('adding address to org w/o country should return 400', async () => { it('adding address to org w/o country should return 400', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -349,7 +357,7 @@ describe('adding + updateing address invalid)', () => {
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
}); });
it('adding address to org w/o postal code should return 400', async () => { it('adding address to org w/o postal code should return 400', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,
@ -365,7 +373,7 @@ describe('adding + updateing address invalid)', () => {
expect(res.headers['content-type']).toContain("application/json"); expect(res.headers['content-type']).toContain("application/json");
}); });
it('adding address to org w/ invalid postal code should return 400', async () => { it('adding address to org w/ invalid postal code should return 400', async () => {
const res = await axios.put(base + '/api/organisations/' + added_org_id, { const res = await axios.put(base + '/api/organizations/' + added_org_id, {
"id": added_org_id, "id": added_org_id,
"name": "testlelele", "name": "testlelele",
"contact": null, "contact": null,

View File

@ -58,7 +58,7 @@ describe('POST /api/teams with errors', () => {
describe('POST /api/teams working', () => { describe('POST /api/teams working', () => {
let added_org_id; let added_org_id;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data

View File

@ -21,7 +21,7 @@ describe('adding org', () => {
let added_team; let added_team;
let added_team_id let added_team_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data; added_org = res1.data;

View File

@ -20,7 +20,7 @@ describe('adding + updating name', () => {
let added_team; let added_team;
let added_team_id let added_team_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data; added_org = res1.data;
@ -59,7 +59,7 @@ describe('adding + try updating id (should return 406)', () => {
let added_team; let added_team;
let added_team_id let added_team_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data; added_org = res1.data;
@ -92,7 +92,7 @@ describe('add+update parent org (valid)', () => {
let added_team; let added_team;
let added_team_id let added_team_id
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data; added_org = res1.data;
@ -110,7 +110,7 @@ describe('add+update parent org (valid)', () => {
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res3 = await axios.post(base + '/api/organisations', { const res3 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org2 = res3.data; added_org2 = res3.data;
@ -120,11 +120,13 @@ describe('add+update parent org (valid)', () => {
it('update team', async () => { it('update team', async () => {
added_team.parentGroup = added_org2.id; added_team.parentGroup = added_org2.id;
const res4 = await axios.put(base + '/api/teams/' + added_team_id, added_team, axios_config); const res4 = await axios.put(base + '/api/teams/' + added_team_id, added_team, axios_config);
let updated_team = res4.data;
expect(res4.status).toEqual(200); expect(res4.status).toEqual(200);
expect(res4.headers['content-type']).toContain("application/json") expect(res4.headers['content-type']).toContain("application/json")
delete added_org2.contact; delete added_org2.contact;
delete added_org2.teams; delete added_org2.teams;
expect(updated_team.parentGroup).toEqual(added_org2) delete added_org2.registrationEnabled;
delete res4.data.parentGroup.key;
delete res4.data.parentGroup.registrationEnabled;
expect(res4.data.parentGroup).toEqual(added_org2)
}); });
}); });

View File

@ -80,7 +80,7 @@ describe('POST /api/runners with errors', () => {
describe('POST /api/runners working', () => { describe('POST /api/runners working', () => {
let added_org_id; let added_org_id;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data

View File

@ -25,7 +25,7 @@ describe('add+delete', () => {
let added_org_id; let added_org_id;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data
@ -71,7 +71,7 @@ describe('DELETE donor with donations invalid', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data
@ -118,7 +118,7 @@ describe('DELETE donor with donations valid', () => {
expect(res.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organisations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res.data added_org = res.data

View File

@ -33,7 +33,7 @@ describe('GET /api/runners after adding', () => {
let added_org_id; let added_org_id;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data

View File

@ -17,11 +17,11 @@ beforeAll(async () => {
describe('Update runner name after adding', () => { describe('Update runner name after adding', () => {
let added_org; let added_org;
let added_runner; let added_runner;
let updated_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
delete res1.data.registrationEnabled;
added_org = res1.data added_org = res1.data
expect(res1.status).toEqual(200); expect(res1.status).toEqual(200);
expect(res1.headers['content-type']).toContain("application/json") expect(res1.headers['content-type']).toContain("application/json")
@ -43,11 +43,13 @@ describe('Update runner name after adding', () => {
const res3 = await axios.put(base + '/api/runners/' + added_runner.id, runnercopy, axios_config); const res3 = await axios.put(base + '/api/runners/' + added_runner.id, runnercopy, axios_config);
expect(res3.status).toEqual(200); expect(res3.status).toEqual(200);
expect(res3.headers['content-type']).toContain("application/json") expect(res3.headers['content-type']).toContain("application/json")
updated_runner = res3.data;
delete added_org.contact; delete added_org.contact;
delete added_org.teams; delete added_org.teams;
runnercopy.group = added_org; runnercopy.group = added_org;
expect(updated_runner).toEqual(runnercopy); delete res3.data.group.key;
delete res3.data.group.registrationEnabled;
delete runnercopy.group.registrationEnabled;
expect(res3.data).toEqual(runnercopy);
}); });
}); });
// --------------- // ---------------
@ -56,7 +58,7 @@ describe('Update runner group after adding', () => {
let added_org_2; let added_org_2;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data
@ -75,7 +77,7 @@ describe('Update runner group after adding', () => {
expect(res2.headers['content-type']).toContain("application/json") expect(res2.headers['content-type']).toContain("application/json")
}); });
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res3 = await axios.post(base + '/api/organisations', { const res3 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org_2 = res3.data added_org_2 = res3.data
@ -86,9 +88,12 @@ describe('Update runner group after adding', () => {
}); });
it('valid group update should return 200', async () => { it('valid group update should return 200', async () => {
added_runner.group = added_org_2.id; added_runner.group = added_org_2.id;
delete added_org_2.registrationEnabled;
const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, axios_config); const res3 = await axios.put(base + '/api/runners/' + added_runner.id, added_runner, axios_config);
expect(res3.status).toEqual(200); expect(res3.status).toEqual(200);
expect(res3.headers['content-type']).toContain("application/json") expect(res3.headers['content-type']).toContain("application/json")
delete res3.data.group.key;
delete res3.data.group.registrationEnabled;
expect(res3.data.group).toEqual(added_org_2); expect(res3.data.group).toEqual(added_org_2);
}); });
}); });
@ -98,7 +103,7 @@ describe('Update runner id after adding(should fail)', () => {
let added_runner; let added_runner;
let added_runner_id; let added_runner_id;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res1.data
@ -130,7 +135,7 @@ describe('Update runner group with invalid group after adding', () => {
let added_org; let added_org;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -19,7 +19,7 @@ describe('POST /api/scans illegally', () => {
let added_org; let added_org;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -70,7 +70,7 @@ describe('POST /api/scans successfully', () => {
let added_org; let added_org;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -144,7 +144,7 @@ describe('POST /api/scans successfully via scan station', () => {
let added_track; let added_track;
let added_station; let added_station;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -21,7 +21,7 @@ describe('DELETE scan', () => {
let added_runner; let added_runner;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -35,7 +35,7 @@ describe('adding + getting scans', () => {
let added_runner; let added_runner;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -19,7 +19,7 @@ describe('adding + updating illegally', () => {
let added_runner; let added_runner;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -86,7 +86,7 @@ describe('adding + updating successfilly', () => {
let added_runner2; let added_runner2;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -0,0 +1,43 @@
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
let access_token;
let axios_config;
beforeAll(async () => {
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {
headers: { "authorization": "Bearer " + access_token },
validateStatus: undefined
};
});
describe('GET /api/runners/me invalid should return fail', () => {
it('get with invalid jwt should return 401', async () => {
const res = await axios.get(base + '/api/runners/me/123.123', axios_config);
expect(res.status).toEqual(401);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('register + get should return 200', () => {
let added_runner;
it('registering as citizen should return 200', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com"
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
added_runner = res.data;
});
it('get with valid jwt should return 200', async () => {
const res = await axios.get(base + '/api/runners/me/' + added_runner.token, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
});

View File

@ -0,0 +1,248 @@
import axios from 'axios';
import { config } from '../../config';
const base = "http://localhost:" + config.internal_port
let access_token;
let axios_config;
beforeAll(async () => {
const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" });
access_token = res.data["access_token"];
axios_config = {
headers: { "authorization": "Bearer " + access_token },
validateStatus: undefined
};
});
describe('register invalid citizen', () => {
it('registering as citizen without mail should return 406', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
}, axios_config);
expect(res.status).toEqual(406);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering as citizen with invalid mail should return 400', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user"
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering as citizen without fist name should return 400', async () => {
const res = await axios.post(base + '/api/runners/register', {
"middlename": "string",
"lastname": "string",
"email": "user@example.com"
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering as citizen without last name should return 400', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"email": "user@example.com"
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering as citizen with invalid mail should return 400', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"phone": "peter",
"email": "user@example.com"
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('register citizen valid', () => {
it('registering as citizen with minimal params should return 200', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"lastname": "string",
"email": "user@example.com"
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering as citizen with all params should return 200', async () => {
const res = await axios.post(base + '/api/runners/register', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
address2: "Testapartement",
postalcode: "91074",
city: "Herzo",
country: "Germany"
}
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('register invalid company', () => {
let added_org;
it('creating a new org with just a name and registration enabled should return 200', async () => {
const res = await axios.post(base + '/api/organizations', {
"name": "test123",
"registrationEnabled": true
}, axios_config);
added_org = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('registering with bs token should return 404', async () => {
const res = await axios.post(base + '/api/runners/register/4040404', {
"firstname": "string",
"middlename": "string",
"lastname": "string",
}, axios_config);
expect(res.status).toEqual(404);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering without firstname should return 400', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"middlename": "string",
"lastname": "string",
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering without lastname should return 400', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"middlename": "string",
"firstname": "string",
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering with bs mail should return 400', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "true"
}, axios_config);
expect(res.status).toEqual(400);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering with invalid team should return 404', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"lastname": "string",
"team": 9999999999999999999999
}, axios_config);
expect(res.status).toEqual(404);
expect(res.headers['content-type']).toContain("application/json");
});
});
// ---------------
describe('register valid company', () => {
let added_org;
let added_team;
it('creating a new org with just a name and registration enabled should return 200', async () => {
const res = await axios.post(base + '/api/organizations', {
"name": "test123",
"registrationEnabled": true
}, axios_config);
added_org = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('creating a new team with a parent org should return 200', async () => {
const res = await axios.post(base + '/api/teams', {
"name": "test_team",
"parentGroup": added_org.id
}, axios_config);
added_team = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('registering with minimal params should return 200', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"lastname": "string",
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering with all params except team should return 200', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
address2: "Testapartement",
postalcode: "91074",
city: "Herzo",
country: "Germany"
}
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering with minimal params and team should return 200', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"lastname": "string",
"team": added_team.id
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering with all params except team should return 200', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
address2: "Testapartement",
postalcode: "91074",
city: "Herzo",
country: "Germany"
}
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
it('registering with all params and team should return 200', async () => {
const res = await axios.post(base + '/api/runners/register/' + added_org.registrationKey, {
"firstname": "string",
"middlename": "string",
"lastname": "string",
"email": "user@example.com",
"phone": "+4909132123456",
"address": {
address1: "Teststreet 1",
address2: "Testapartement",
postalcode: "91074",
city: "Herzo",
country: "Germany"
},
"team": added_team.id
}, axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
});
});

View File

@ -22,7 +22,7 @@ describe('POST /api/scans illegally', () => {
let added_track; let added_track;
let added_station; let added_station;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -109,7 +109,7 @@ describe('POST /api/scans successfully', () => {
let added_track; let added_track;
let added_station; let added_station;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -179,7 +179,7 @@ describe('POST /api/scans successfully via scan station', () => {
let added_track; let added_track;
let added_station; let added_station;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -24,7 +24,7 @@ describe('DELETE scan', () => {
let added_station; let added_station;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -38,7 +38,7 @@ describe('adding + getting scans', () => {
let added_station; let added_station;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data

View File

@ -22,7 +22,7 @@ describe('adding + updating illegally', () => {
let added_station; let added_station;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data
@ -123,7 +123,7 @@ describe('adding + updating successfilly', () => {
let added_station2; let added_station2;
let added_scan; let added_scan;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organisations', { const res1 = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
added_org = res1.data added_org = res1.data