From 3850bd968173fb2a701ff02327c38a662ee0c40b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:17:30 +0100 Subject: [PATCH 01/32] Renamed function to better reflect it's function ref #39 --- src/controllers/UserController.ts | 2 +- src/models/actions/UpdateUser.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index cdc91af..6a782bf 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -84,7 +84,7 @@ export class UserController { if (oldUser.id != updateUser.id) { throw new UserIdsNotMatchingError(); } - await this.userRepository.save(await updateUser.toUser(oldUser)); + await this.userRepository.save(await updateUser.updateUser(oldUser)); return new ResponseUser(await this.userRepository.findOne({ id: id }, { relations: ['permissions', 'groups'] })); } diff --git a/src/models/actions/UpdateUser.ts b/src/models/actions/UpdateUser.ts index abd489a..e50436d 100644 --- a/src/models/actions/UpdateUser.ts +++ b/src/models/actions/UpdateUser.ts @@ -85,7 +85,7 @@ export class UpdateUser { /** * Creates a User entity from this. */ - public async toUser(user: User): Promise { + public async updateUser(user: User): Promise { user.email = this.email; user.username = this.username; if (user.email === undefined && user.username === undefined) { From adec2bcc5b56fe7139eaada4f66398f20ae9212f Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:17:42 +0100 Subject: [PATCH 02/32] removed useless deletes ref #39 --- src/controllers/UserController.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 6a782bf..e4a8e89 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -73,9 +73,6 @@ export class UserController { @OpenAPI({ description: "Update a user object (id can't be changed)." }) async put(@Param('id') id: number, @Body({ validate: true }) updateUser: UpdateUser) { let oldUser = await this.userRepository.findOne({ id: id }); - delete oldUser.permissions; - delete oldUser.groups; - delete oldUser.actions; if (!oldUser) { throw new UserNotFoundError(); From b55d210affbe19a07d1859064a8d58f9562d3319 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:18:16 +0100 Subject: [PATCH 03/32] Fixed wrong error type ref #39 --- src/models/actions/UpdateUser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/actions/UpdateUser.ts b/src/models/actions/UpdateUser.ts index e50436d..14d3ca8 100644 --- a/src/models/actions/UpdateUser.ts +++ b/src/models/actions/UpdateUser.ts @@ -3,7 +3,7 @@ import { IsBoolean, IsEmail, IsInt, IsOptional, IsPhoneNumber, IsString } from ' import { getConnectionManager } from 'typeorm'; import { config } from '../../config'; import { UsernameOrEmailNeededError } from '../../errors/AuthError'; -import { RunnerGroupNotFoundError } from '../../errors/RunnerGroupErrors'; +import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; import { User } from '../entities/User'; import { UserGroup } from '../entities/UserGroup'; @@ -115,7 +115,7 @@ export class UpdateUser { } for (let group of this.groups) { let found = await getConnectionManager().get().getRepository(UserGroup).findOne({ id: group.id }); - if (!found) { throw new RunnerGroupNotFoundError(); } + if (!found) { throw new UserGroupNotFoundError(); } groups.push(found); } return groups; From cf583a22fad8de5967bd0a1be93a693a935ef1c1 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:19:33 +0100 Subject: [PATCH 04/32] Added missing username property to the responseuser ref #39 --- src/models/responses/ResponseUser.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/models/responses/ResponseUser.ts b/src/models/responses/ResponseUser.ts index 9ec729a..0927106 100644 --- a/src/models/responses/ResponseUser.ts +++ b/src/models/responses/ResponseUser.ts @@ -47,6 +47,13 @@ export class ResponseUser extends ResponsePrincipal { @IsString() email?: string; + /** + * The user's username. + * Optional. + */ + @IsString() + username?: string; + /** * is user enabled? */ @@ -81,6 +88,7 @@ export class ResponseUser extends ResponsePrincipal { this.lastname = user.lastname; this.phone = user.phone; this.email = user.email; + this.username = user.username; this.enabled = user.enabled; this.profilePic = user.profilePic; this.groups = user.groups; From 24de82f6dff1ff07cab5b5a851519a290b642266 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:25:41 +0100 Subject: [PATCH 05/32] Moved runner teams to the new put mechanism ref #39 --- src/controllers/RunnerTeamController.ts | 2 +- src/models/actions/UpdateRunnerTeam.ts | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/controllers/RunnerTeamController.ts b/src/controllers/RunnerTeamController.ts index e02098a..5040e8c 100644 --- a/src/controllers/RunnerTeamController.ts +++ b/src/controllers/RunnerTeamController.ts @@ -82,7 +82,7 @@ export class RunnerTeamController { throw new RunnerTeamIdsNotMatchingError(); } - await this.runnerTeamRepository.update(oldRunnerTeam, await runnerTeam.toRunnerTeam()); + await this.runnerTeamRepository.save(await runnerTeam.updateRunnerTeam(oldRunnerTeam)); return new ResponseRunnerTeam(await this.runnerTeamRepository.findOne({ id: runnerTeam.id }, { relations: ['parentGroup', 'contact'] })); } diff --git a/src/models/actions/UpdateRunnerTeam.ts b/src/models/actions/UpdateRunnerTeam.ts index 0028cf8..8eaee39 100644 --- a/src/models/actions/UpdateRunnerTeam.ts +++ b/src/models/actions/UpdateRunnerTeam.ts @@ -37,14 +37,12 @@ export class UpdateRunnerTeam extends CreateRunnerGroup { /** * Creates a RunnerTeam entity from this. */ - public async toRunnerTeam(): Promise { - let newRunnerTeam: RunnerTeam = new RunnerTeam(); + public async updateRunnerTeam(team: RunnerTeam): Promise { - newRunnerTeam.id = this.id; - newRunnerTeam.name = this.name; - newRunnerTeam.parentGroup = await this.getParent(); - newRunnerTeam.contact = await this.getContact() + team.name = this.name; + team.parentGroup = await this.getParent(); + team.contact = await this.getContact() - return newRunnerTeam; + return team; } } \ No newline at end of file From cc68948a205b7e983f4c6f8e21b47d9b60c008bc Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:27:21 +0100 Subject: [PATCH 06/32] Moved runners to the new put mechanism ref #39 --- src/controllers/RunnerController.ts | 2 +- src/models/actions/UpdateRunner.ts | 21 +++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 8d70c30..12569d0 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -81,7 +81,7 @@ export class RunnerController { throw new RunnerIdsNotMatchingError(); } - await this.runnerRepository.update(oldRunner, await runner.toRunner()); + await this.runnerRepository.save(await runner.updateRunner(oldRunner)); return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group'] })); } diff --git a/src/models/actions/UpdateRunner.ts b/src/models/actions/UpdateRunner.ts index 5ade74f..cd38961 100644 --- a/src/models/actions/UpdateRunner.ts +++ b/src/models/actions/UpdateRunner.ts @@ -24,19 +24,16 @@ export class UpdateRunner extends CreateParticipant { /** * Creates a Runner entity from this. */ - public async toRunner(): Promise { - let newRunner: Runner = new Runner(); + public async updateRunner(runner: Runner): Promise { + runner.firstname = this.firstname; + runner.middlename = this.middlename; + runner.lastname = this.lastname; + runner.phone = this.phone; + runner.email = this.email; + runner.group = await this.getGroup(); + runner.address = await this.getAddress(); - newRunner.id = this.id; - 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(); - newRunner.address = await this.getAddress(); - - return newRunner; + return runner; } /** From b2bd6173a5b2c2fab5a259e0136486aeb92fd833 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:29:04 +0100 Subject: [PATCH 07/32] Moved permissions to the new put mechanism ref #39 --- src/controllers/PermissionController.ts | 2 +- src/models/actions/UpdatePermission.ts | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/controllers/PermissionController.ts b/src/controllers/PermissionController.ts index 6be00fd..208fe6f 100644 --- a/src/controllers/PermissionController.ts +++ b/src/controllers/PermissionController.ts @@ -96,7 +96,7 @@ export class PermissionController { return new ResponsePermission(existingPermission); } - await this.permissionRepository.update(oldPermission, await permission.toPermission()); + await this.permissionRepository.save(await permission.updatePermission(oldPermission)); return new ResponsePermission(await this.permissionRepository.findOne({ id: permission.id }, { relations: ['principal'] })); } diff --git a/src/models/actions/UpdatePermission.ts b/src/models/actions/UpdatePermission.ts index 26c2a83..dec0ad8 100644 --- a/src/models/actions/UpdatePermission.ts +++ b/src/models/actions/UpdatePermission.ts @@ -37,14 +37,12 @@ export class UpdatePermission { /** * Converts a Permission object based on this. */ - public async toPermission(): Promise { - let newPermission: Permission = new Permission(); + public async updatePermission(permission: Permission): Promise { + permission.principal = await this.getPrincipal(); + permission.target = this.target; + permission.action = this.action; - newPermission.principal = await this.getPrincipal(); - newPermission.target = this.target; - newPermission.action = this.action; - - return newPermission; + return permission; } /** From ec4d75128b284fb5530dc76b7ae99df3efcaba75 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:36:22 +0100 Subject: [PATCH 08/32] Fixed some weired toString beviour ref #39 #6 --- src/models/enums/PermissionTargets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/enums/PermissionTargets.ts b/src/models/enums/PermissionTargets.ts index 7b18eb0..4f88eac 100644 --- a/src/models/enums/PermissionTargets.ts +++ b/src/models/enums/PermissionTargets.ts @@ -4,6 +4,6 @@ export enum PermissionTarget { TEAM = 'TEAM', TRACK = 'TRACK', USER = 'USER', - GROUP = 'USERGROUP', + USERGROUP = 'USERGROUP', PERMISSION = 'PERMISSION' } \ No newline at end of file From 18ede29ea544000abd9bffdfa35d82a62b6733a4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 17:37:20 +0100 Subject: [PATCH 09/32] Moved usergroups to the new put mechanism ref #39 --- src/controllers/UserGroupController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/UserGroupController.ts b/src/controllers/UserGroupController.ts index 3297f50..ea3ab16 100644 --- a/src/controllers/UserGroupController.ts +++ b/src/controllers/UserGroupController.ts @@ -73,7 +73,7 @@ export class UserGroupController { throw new UserGroupIdsNotMatchingError(); } - await this.userGroupsRepository.update(oldUserGroup, userGroup); + await this.userGroupsRepository.save(userGroup); return userGroup; } From 532b5a56a5226d524f864bb8e965b4f57483101b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:07:33 +0100 Subject: [PATCH 10/32] Switched runner orgs to the cleaner syntax via a update entity ref #39 --- .../RunnerOrganisationController.ts | 11 ++-- .../actions/UpdateRunnerOrganisation.ts | 52 +++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 src/models/actions/UpdateRunnerOrganisation.ts diff --git a/src/controllers/RunnerOrganisationController.ts b/src/controllers/RunnerOrganisationController.ts index 5504dbb..fb86cf2 100644 --- a/src/controllers/RunnerOrganisationController.ts +++ b/src/controllers/RunnerOrganisationController.ts @@ -1,9 +1,9 @@ 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 { EntityFromBody } from 'typeorm-routing-controllers-extensions'; import { RunnerOrganisationHasRunnersError, RunnerOrganisationHasTeamsError, RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors'; import { CreateRunnerOrganisation } from '../models/actions/CreateRunnerOrganisation'; +import { UpdateRunnerOrganisation } from '../models/actions/UpdateRunnerOrganisation'; import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseRunnerOrganisation } from '../models/responses/ResponseRunnerOrganisation'; @@ -71,21 +71,20 @@ export class RunnerOrganisationController { @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) @ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 }) @OpenAPI({ description: "Update a runnerOrganisation object (id can't be changed)." }) - async put(@Param('id') id: number, @EntityFromBody() runnerOrganisation: RunnerOrganisation) { + 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 != runnerOrganisation.id) { + if (oldRunnerOrganisation.id != updateOrganisation.id) { throw new RunnerOrganisationIdsNotMatchingError(); } - await this.runnerOrganisationRepository.update(oldRunnerOrganisation, runnerOrganisation); + await this.runnerOrganisationRepository.save(await updateOrganisation.updateRunnerOrganisation(oldRunnerOrganisation)); - runnerOrganisation = await this.runnerOrganisationRepository.findOne(runnerOrganisation, { relations: ['address', 'contact', 'teams'] }); - return new ResponseRunnerOrganisation(runnerOrganisation); + return new ResponseRunnerOrganisation(await this.runnerOrganisationRepository.findOne(id, { relations: ['address', 'contact', 'teams'] })); } @Delete('/:id') diff --git a/src/models/actions/UpdateRunnerOrganisation.ts b/src/models/actions/UpdateRunnerOrganisation.ts new file mode 100644 index 0000000..19d5d34 --- /dev/null +++ b/src/models/actions/UpdateRunnerOrganisation.ts @@ -0,0 +1,52 @@ +import { IsInt, IsOptional } from 'class-validator'; +import { getConnectionManager } from 'typeorm'; +import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; +import { Address } from '../entities/Address'; +import { RunnerOrganisation } from '../entities/RunnerOrganisation'; +import { CreateRunnerGroup } from './CreateRunnerGroup'; + +export class UpdateRunnerOrganisation extends CreateRunnerGroup { + + /** + * The updated orgs's id. + */ + @IsInt() + id: number; + + /** + * The updated organisation's address. + * Must be of type number (address id). + * Optional. + */ + @IsInt() + @IsOptional() + address?: number; + + /** + * Get's this org's address from this.address. + */ + public async getAddress(): Promise
{ + if (this.address === undefined) { + return null; + } + if (!isNaN(this.address)) { + let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); + if (!address) { throw new AddressNotFoundError; } + return address; + } + + throw new AddressWrongTypeError; + } + + /** + * Creates a RunnerTeam entity from this. + */ + public async updateRunnerOrganisation(organisation: RunnerOrganisation): Promise { + + organisation.name = this.name; + organisation.contact = await this.getContact(); + organisation.address = await this.getAddress(); + + return organisation; + } +} \ No newline at end of file From fbe2b358bd349456f2f4ac3413ab8b82d6f4bbe3 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:07:45 +0100 Subject: [PATCH 11/32] Moved tracks to the new put mechanism ref #39 --- src/controllers/TrackController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index 4691c86..d5746ff 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -72,7 +72,7 @@ export class TrackController { throw new TrackIdsNotMatchingError(); } - await this.trackRepository.update(oldTrack, track); + await this.trackRepository.save(track); return new ResponseTrack(track); } From 7a4238f1f7e54de2c0ec91b3dc67656c2f1f7ec8 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:18:32 +0100 Subject: [PATCH 12/32] Fixed some stuff not getting checked against null ref #39 gosh i sometimes hate js types --- src/models/actions/CreateGroupContact.ts | 2 +- src/models/actions/CreateParticipant.ts | 2 +- src/models/actions/CreateRunner.ts | 2 +- src/models/actions/CreateRunnerOrganisation.ts | 2 +- src/models/actions/CreateRunnerTeam.ts | 2 +- src/models/actions/UpdatePermission.ts | 2 +- src/models/actions/UpdateRunner.ts | 2 +- src/models/actions/UpdateRunnerOrganisation.ts | 16 ++++++---------- src/models/actions/UpdateRunnerTeam.ts | 2 +- src/models/actions/UpdateUser.ts | 2 +- 10 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/models/actions/CreateGroupContact.ts b/src/models/actions/CreateGroupContact.ts index 5f49879..747f29d 100644 --- a/src/models/actions/CreateGroupContact.ts +++ b/src/models/actions/CreateGroupContact.ts @@ -56,7 +56,7 @@ export class CreateGroupContact { * Get's this participant's address from this.address. */ public async getAddress(): Promise
{ - if (this.address === undefined) { + if (this.address === undefined || this.address === null) { return null; } if (!isNaN(this.address)) { diff --git a/src/models/actions/CreateParticipant.ts b/src/models/actions/CreateParticipant.ts index b3827d1..49cba30 100644 --- a/src/models/actions/CreateParticipant.ts +++ b/src/models/actions/CreateParticipant.ts @@ -58,7 +58,7 @@ export abstract class CreateParticipant { * Get's this participant's address from this.address. */ public async getAddress(): Promise
{ - if (this.address === undefined) { + if (this.address === undefined || this.address === null) { return null; } if (!isNaN(this.address)) { diff --git a/src/models/actions/CreateRunner.ts b/src/models/actions/CreateRunner.ts index 2b9f128..28ccaae 100644 --- a/src/models/actions/CreateRunner.ts +++ b/src/models/actions/CreateRunner.ts @@ -36,7 +36,7 @@ export class CreateRunner extends CreateParticipant { * Manages all the different ways a group can be provided. */ public async getGroup(): Promise { - if (this.group === undefined) { + if (this.group === undefined || this.group === null) { throw new RunnerTeamNeedsParentError(); } if (!isNaN(this.group)) { diff --git a/src/models/actions/CreateRunnerOrganisation.ts b/src/models/actions/CreateRunnerOrganisation.ts index 46fc72e..ffef4a3 100644 --- a/src/models/actions/CreateRunnerOrganisation.ts +++ b/src/models/actions/CreateRunnerOrganisation.ts @@ -19,7 +19,7 @@ export class CreateRunnerOrganisation extends CreateRunnerGroup { * Get's this org's address from this.address. */ public async getAddress(): Promise
{ - if (this.address === undefined) { + if (this.address === undefined || this.address === null) { return null; } if (!isNaN(this.address)) { diff --git a/src/models/actions/CreateRunnerTeam.ts b/src/models/actions/CreateRunnerTeam.ts index 0a4941f..0a6f992 100644 --- a/src/models/actions/CreateRunnerTeam.ts +++ b/src/models/actions/CreateRunnerTeam.ts @@ -16,7 +16,7 @@ export class CreateRunnerTeam extends CreateRunnerGroup { parentGroup: number; public async getParent(): Promise { - if (this.parentGroup === undefined) { + if (this.parentGroup === undefined || this.parentGroup === null) { throw new RunnerTeamNeedsParentError(); } if (!isNaN(this.parentGroup)) { diff --git a/src/models/actions/UpdatePermission.ts b/src/models/actions/UpdatePermission.ts index dec0ad8..8c31bbe 100644 --- a/src/models/actions/UpdatePermission.ts +++ b/src/models/actions/UpdatePermission.ts @@ -49,7 +49,7 @@ export class UpdatePermission { * Manages all the different ways a group can be provided. */ public async getPrincipal(): Promise { - if (this.principal === undefined) { + if (this.principal === undefined || this.principal === null) { throw new PermissionNeedsPrincipalError(); } if (!isNaN(this.principal.id)) { diff --git a/src/models/actions/UpdateRunner.ts b/src/models/actions/UpdateRunner.ts index cd38961..62667ec 100644 --- a/src/models/actions/UpdateRunner.ts +++ b/src/models/actions/UpdateRunner.ts @@ -40,7 +40,7 @@ export class UpdateRunner extends CreateParticipant { * Manages all the different ways a group can be provided. */ public async getGroup(): Promise { - if (this.group === undefined) { + if (this.group === undefined || this.group === null) { throw new RunnerTeamNeedsParentError(); } if (!isNaN(this.group.id)) { diff --git a/src/models/actions/UpdateRunnerOrganisation.ts b/src/models/actions/UpdateRunnerOrganisation.ts index 19d5d34..6917698 100644 --- a/src/models/actions/UpdateRunnerOrganisation.ts +++ b/src/models/actions/UpdateRunnerOrganisation.ts @@ -1,6 +1,6 @@ import { IsInt, IsOptional } from 'class-validator'; import { getConnectionManager } from 'typeorm'; -import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; +import { AddressNotFoundError } from '../../errors/AddressErrors'; import { Address } from '../entities/Address'; import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { CreateRunnerGroup } from './CreateRunnerGroup'; @@ -20,22 +20,18 @@ export class UpdateRunnerOrganisation extends CreateRunnerGroup { */ @IsInt() @IsOptional() - address?: number; + address?: Address; /** * Get's this org's address from this.address. */ public async getAddress(): Promise
{ - if (this.address === undefined) { + if (this.address === undefined || this.address === null) { return null; } - if (!isNaN(this.address)) { - let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address }); - if (!address) { throw new AddressNotFoundError; } - return address; - } - - throw new AddressWrongTypeError; + let address = await getConnectionManager().get().getRepository(Address).findOne({ id: this.address.id }); + if (!address) { throw new AddressNotFoundError; } + return address; } /** diff --git a/src/models/actions/UpdateRunnerTeam.ts b/src/models/actions/UpdateRunnerTeam.ts index 8eaee39..62b71d5 100644 --- a/src/models/actions/UpdateRunnerTeam.ts +++ b/src/models/actions/UpdateRunnerTeam.ts @@ -22,7 +22,7 @@ export class UpdateRunnerTeam extends CreateRunnerGroup { parentGroup: RunnerOrganisation; public async getParent(): Promise { - if (this.parentGroup === undefined) { + if (this.parentGroup === undefined || this.parentGroup === null) { throw new RunnerTeamNeedsParentError(); } if (!isNaN(this.parentGroup.id)) { diff --git a/src/models/actions/UpdateUser.ts b/src/models/actions/UpdateUser.ts index 14d3ca8..f91e7a5 100644 --- a/src/models/actions/UpdateUser.ts +++ b/src/models/actions/UpdateUser.ts @@ -88,7 +88,7 @@ export class UpdateUser { public async updateUser(user: User): Promise { user.email = this.email; user.username = this.username; - if (user.email === undefined && user.username === undefined) { + if ((user.email === undefined || user.email === null) && (user.username === undefined || user.username === null)) { throw new UsernameOrEmailNeededError(); } if (this.password) { From 4ca85a1f224ae48fc5c358e8e044b86f054c9d3d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:41:25 +0100 Subject: [PATCH 13/32] Fixed messages and comments for AuthErrors ref #39 --- src/errors/AuthError.ts | 43 ++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index 7687371..c2eff13 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -1,63 +1,57 @@ import { IsString } from 'class-validator'; import { ForbiddenError, NotAcceptableError, NotFoundError, UnauthorizedError } from 'routing-controllers'; -/** - * Error to throw when a jwt is expired. - */ -export class ExpiredJWTError extends UnauthorizedError { - @IsString() - name = "ExpiredJWTError" - - @IsString() - message = "your provided jwt is expired" -} - /** * Error to throw when a jwt could not be parsed. + * For example: Wrong signature or expired. */ export class IllegalJWTError extends UnauthorizedError { @IsString() name = "IllegalJWTError" @IsString() - message = "your provided jwt could not be parsed" + message = "Your provided jwt could not be parsed." } /** * Error to throw when user is nonexistant or refreshtoken is invalid. + * This can happen if someone provides a JWT with a invalid user id or the refreshTokenCount of the user is higher that the provided jwt's is. */ export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError { @IsString() name = "UserNonexistantOrRefreshtokenInvalidError" @IsString() - message = "user is nonexistant or refreshtoken is invalid" + message = "User is nonexistant or refreshtoken is invalid." } /** * Error to throw when provided credentials are invalid. + * We don't have seperate errors for username/mail and passwords to protect against guessing attacks. */ export class InvalidCredentialsError extends UnauthorizedError { @IsString() name = "InvalidCredentialsError" @IsString() - message = "your provided credentials are invalid" + message = "Your provided credentials are invalid." } /** * Error to throw when a jwt does not have permission for this route/action. + * Mainly used be the @Authorized decorator (via the authchecker). */ export class NoPermissionError extends ForbiddenError { @IsString() name = "NoPermissionError" @IsString() - message = "your provided jwt does not have permission for this route/ action" + message = "Your provided jwt does not have permission for this route/ action." } /** * Error to throw when no username and no email is set. + * Because we have to identify users somehow. */ export class UsernameOrEmailNeededError extends NotAcceptableError { @IsString() @@ -68,47 +62,48 @@ export class UsernameOrEmailNeededError extends NotAcceptableError { } /** - * Error to throw when no password is provided. + * Error to throw when no password is provided for a new user. + * Passwords are the minimum we need for user security. */ export class PasswordNeededError extends NotAcceptableError { @IsString() name = "PasswordNeededError" @IsString() - message = "no password is provided - you need to provide it" + message = "No password is provided - you need to provide it." } /** - * Error to throw when no user could be found mating the provided credential. + * Error to throw when no user could be found for a certain query. */ export class UserNotFoundError extends NotFoundError { @IsString() name = "UserNotFoundError" @IsString() - message = "no user could be found for provided credential" + message = "The user you provided couldn't be located in the system. \n Please check your request." } /** - * Error to throw when no jwt token was provided (but one had to be). + * Error to throw when no jwt was provided (but one had to be). */ export class JwtNotProvidedError extends NotAcceptableError { @IsString() name = "JwtNotProvidedError" @IsString() - message = "no jwt token was provided" + message = "No jwt was provided." } /** - * Error to throw when user was not found or refresh token count was invalid. + * Error to throw when user was not found or the jwt's refresh token count was invalid. */ export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableError { @IsString() name = "UserNotFoundOrRefreshTokenCountInvalidError" @IsString() - message = "user was not found or refresh token count was invalid" + message = "User was not found or the refresh token count is invalid." } /** @@ -119,5 +114,5 @@ export class RefreshTokenCountInvalidError extends NotAcceptableError { name = "RefreshTokenCountInvalidError" @IsString() - message = "refresh token count was invalid" + message = "Refresh token count is invalid." } \ No newline at end of file From c1d784e29c80b71a499d5bdd08b897561e235979 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:42:57 +0100 Subject: [PATCH 14/32] Fixed messages and comments for PermissionErrors ref #39 --- src/errors/PermissionErrors.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/errors/PermissionErrors.ts b/src/errors/PermissionErrors.ts index c2492b4..fdd7215 100644 --- a/src/errors/PermissionErrors.ts +++ b/src/errors/PermissionErrors.ts @@ -13,7 +13,7 @@ export class PermissionNotFoundError extends NotFoundError { } /** - * Error to throw when two permission' ids don't match. + * Error to throw when two permissions' ids don't match. * Usually occurs when a user tries to change a permission's id. */ export class PermissionIdsNotMatchingError extends NotAcceptableError { @@ -21,11 +21,11 @@ export class PermissionIdsNotMatchingError extends NotAcceptableError { name = "PermissionIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a permission's id: This isn't allowed" + message = "The id's don't match!! \n And if you wanted to change a permission's id: This isn't allowed!" } /** - * Error to throw when a permission get's provided without a principal. + * Error to throw when a permission gets provided without a principal. */ export class PermissionNeedsPrincipalError extends NotAcceptableError { @IsString() From 5de81ad0939cd870ff960c303930147f81144781 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:45:10 +0100 Subject: [PATCH 15/32] Fixed messages and comments for RunnerErrors ref #39 --- src/errors/RunnerErrors.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts index 06dc78f..b73b593 100644 --- a/src/errors/RunnerErrors.ts +++ b/src/errors/RunnerErrors.ts @@ -3,7 +3,6 @@ import { NotAcceptableError, NotFoundError } from 'routing-controllers'; /** * Error to throw when a runner couldn't be found. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class RunnerNotFoundError extends NotFoundError { @IsString() @@ -16,14 +15,13 @@ export class RunnerNotFoundError extends NotFoundError { /** * Error to throw when two runners' ids don't match. * Usually occurs when a user tries to change a runner's id. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class RunnerIdsNotMatchingError extends NotAcceptableError { @IsString() name = "RunnerIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" + message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed!" } /** From 82ced34750222f733e30ab42fa6cabe00c6dbba0 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:45:33 +0100 Subject: [PATCH 16/32] Fixed messages and comments for RunnerGroupErrors ref #39 --- src/errors/RunnerGroupErrors.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/errors/RunnerGroupErrors.ts b/src/errors/RunnerGroupErrors.ts index ed9624c..524ec87 100644 --- a/src/errors/RunnerGroupErrors.ts +++ b/src/errors/RunnerGroupErrors.ts @@ -3,7 +3,6 @@ import { NotFoundError } from 'routing-controllers'; /** * Error to throw when a runner group couldn't be found. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class RunnerGroupNotFoundError extends NotFoundError { @IsString() From 37afc10e44b4beed4563bd67bbba0fbbe42c1c75 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:46:43 +0100 Subject: [PATCH 17/32] Fixed messages and comments for RunnerOrganisationErrors ref #39 --- src/errors/RunnerOrganisationErrors.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/errors/RunnerOrganisationErrors.ts b/src/errors/RunnerOrganisationErrors.ts index 040befb..db524df 100644 --- a/src/errors/RunnerOrganisationErrors.ts +++ b/src/errors/RunnerOrganisationErrors.ts @@ -3,7 +3,6 @@ import { NotAcceptableError, NotFoundError } from 'routing-controllers'; /** * Error to throw when a runner organisation couldn't be found. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class RunnerOrganisationNotFoundError extends NotFoundError { @IsString() @@ -15,39 +14,36 @@ export class RunnerOrganisationNotFoundError extends NotFoundError { /** * Error to throw when two runner organisations' ids don't match. - * Usually occurs when a user tries to change a runner's id. - * Implemented this way to work with the json-schema conversion for openapi. + * Usually occurs when a user tries to change a runner organisation's id. */ export class RunnerOrganisationIdsNotMatchingError extends NotAcceptableError { @IsString() name = "RunnerOrganisationIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" + message = "The id's 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. - * Implemented this waysto work with the json-schema conversion for openapi. */ 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 ass `?force` to your query." + 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 runners associated. - * Implemented this waysto work with the json-schema conversion for openapi. + * 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 ass `?force` to your query." + 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." } /** From 389f6347c367c04e8e6b45cf42f2d54f1bc28084 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:47:42 +0100 Subject: [PATCH 18/32] Fixed messages and comments for RunnerTeamErrors ref #39 --- src/errors/RunnerTeamErrors.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/errors/RunnerTeamErrors.ts b/src/errors/RunnerTeamErrors.ts index 33fbea5..0b86707 100644 --- a/src/errors/RunnerTeamErrors.ts +++ b/src/errors/RunnerTeamErrors.ts @@ -3,7 +3,6 @@ import { NotAcceptableError, NotFoundError } from 'routing-controllers'; /** * Error to throw when a runner team couldn't be found. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class RunnerTeamNotFoundError extends NotFoundError { @IsString() @@ -15,32 +14,29 @@ export class RunnerTeamNotFoundError extends NotFoundError { /** * Error to throw when two runner teams' ids don't match. - * Usually occurs when a user tries to change a runner's id. - * Implemented this way to work with the json-schema conversion for openapi. + * Usually occurs when a user tries to change a runner team's id. */ export class RunnerTeamIdsNotMatchingError extends NotAcceptableError { @IsString() name = "RunnerTeamIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" + message = "The ids don't match!! \n And if you wanted to change a runner's id: This isn't allowed" } /** * Error to throw when a team still has runners associated. - * Implemented this waysto work with the json-schema conversion for openapi. */ export class RunnerTeamHasRunnersError extends NotAcceptableError { @IsString() name = "RunnerTeamHasRunnersError" @IsString() - message = "This team still has runners associated with it. \n If you want to delete this team with all it's runners and teams ass `?force` to your query." + message = "This team still has runners associated with it. \n If you want to delete this team with all it's runners and teams add `?force` to your query." } /** * Error to throw when a team still has runners associated. - * Implemented this waysto work with the json-schema conversion for openapi. */ export class RunnerTeamNeedsParentError extends NotAcceptableError { @IsString() From 75b6489f8dc91c0c268bf46158ccf5375cfa674d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:48:59 +0100 Subject: [PATCH 19/32] Fixed messages and comments for TrackErrors + spelling for some other errors ref #39 --- src/errors/PermissionErrors.ts | 2 +- src/errors/RunnerErrors.ts | 2 +- src/errors/RunnerOrganisationErrors.ts | 2 +- src/errors/TrackErrors.ts | 8 +++----- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/errors/PermissionErrors.ts b/src/errors/PermissionErrors.ts index fdd7215..b3c406d 100644 --- a/src/errors/PermissionErrors.ts +++ b/src/errors/PermissionErrors.ts @@ -21,7 +21,7 @@ export class PermissionIdsNotMatchingError extends NotAcceptableError { name = "PermissionIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a permission's id: This isn't allowed!" + message = "The ids don't match! \n And if you wanted to change a permission's id: This isn't allowed!" } /** diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts index b73b593..6ef12c5 100644 --- a/src/errors/RunnerErrors.ts +++ b/src/errors/RunnerErrors.ts @@ -21,7 +21,7 @@ export class RunnerIdsNotMatchingError extends NotAcceptableError { name = "RunnerIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed!" + message = "The ids don't match! \n And if you wanted to change a runner's id: This isn't allowed!" } /** diff --git a/src/errors/RunnerOrganisationErrors.ts b/src/errors/RunnerOrganisationErrors.ts index db524df..b004acf 100644 --- a/src/errors/RunnerOrganisationErrors.ts +++ b/src/errors/RunnerOrganisationErrors.ts @@ -21,7 +21,7 @@ export class RunnerOrganisationIdsNotMatchingError extends NotAcceptableError { name = "RunnerOrganisationIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a runner organisation's id: This isn't allowed!" + message = "The ids don't match! \n And if you wanted to change a runner organisation's id: This isn't allowed!" } /** diff --git a/src/errors/TrackErrors.ts b/src/errors/TrackErrors.ts index 6c0d803..7d4cfa9 100644 --- a/src/errors/TrackErrors.ts +++ b/src/errors/TrackErrors.ts @@ -1,9 +1,8 @@ -import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers'; -import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; +import { IsString } from 'class-validator'; +import { NotAcceptableError, NotFoundError } from 'routing-controllers'; /** * Error to throw when a track couldn't be found. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class TrackNotFoundError extends NotFoundError { @IsString() @@ -16,12 +15,11 @@ export class TrackNotFoundError extends NotFoundError { /** * Error to throw when two tracks' ids don't match. * Usually occurs when a user tries to change a track's id. - * Implemented this ways to work with the json-schema conversion for openapi. */ export class TrackIdsNotMatchingError extends NotAcceptableError { @IsString() name = "TrackIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a track's id: This isn't allowed" + message = "The ids don't match! \n And if you wanted to change a track's id: This isn't allowed" } \ No newline at end of file From ee76f1c0e8d9f93a9a98871fbfeedbc55fc0cbc1 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:50:06 +0100 Subject: [PATCH 20/32] Fixed messages and comments for UserErrors ref #39 --- src/errors/UserErrors.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/errors/UserErrors.ts b/src/errors/UserErrors.ts index cfceff1..37f2987 100644 --- a/src/errors/UserErrors.ts +++ b/src/errors/UserErrors.ts @@ -3,14 +3,15 @@ import { NotAcceptableError, NotFoundError } from 'routing-controllers'; /** - * Error to throw when no username or email is set + * Error to throw when no username or email is set. + * We somehow need to identify you :) */ export class UsernameOrEmailNeededError extends NotFoundError { @IsString() name = "UsernameOrEmailNeededError" @IsString() - message = "no username or email is set!" + message = "No username or email is set!" } /** @@ -33,5 +34,5 @@ export class UserIdsNotMatchingError extends NotAcceptableError { name = "UserIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n And if you wanted to change a user's id: This isn't allowed" + message = "The ids don't match!! \n And if you wanted to change a user's id: This isn't allowed!" } \ No newline at end of file From 2199cb0aef340034644d7b9204a215e539fd6005 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:50:45 +0100 Subject: [PATCH 21/32] Fixed messages and comments for UserGroupErrors ref #39 --- src/errors/UserGroupErrors.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/errors/UserGroupErrors.ts b/src/errors/UserGroupErrors.ts index 15495b9..7edd6fd 100644 --- a/src/errors/UserGroupErrors.ts +++ b/src/errors/UserGroupErrors.ts @@ -2,14 +2,14 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; /** - * Error to throw when no groupname is set + * Error to throw when no groupname is set. */ export class GroupNameNeededError extends NotFoundError { @IsString() name = "GroupNameNeededError" @IsString() - message = "no groupname is set!" + message = "No name is set for this group!" } /** @@ -32,5 +32,5 @@ export class UserGroupIdsNotMatchingError extends NotAcceptableError { name = "UserGroupIdsNotMatchingError" @IsString() - message = "The id's don't match!! \n If you wanted to change a usergroup's id: This isn't allowed" + message = "The ids don't match!! \n If you wanted to change a usergroup's id: This isn't allowed!" } \ No newline at end of file From de91d491e561881ba5a54d920dba28fe486fce61 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 18:55:52 +0100 Subject: [PATCH 22/32] Added a missing poiunt/exclamation mark ref #39 --- src/errors/RunnerTeamErrors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/errors/RunnerTeamErrors.ts b/src/errors/RunnerTeamErrors.ts index 0b86707..a00a9be 100644 --- a/src/errors/RunnerTeamErrors.ts +++ b/src/errors/RunnerTeamErrors.ts @@ -21,7 +21,7 @@ export class RunnerTeamIdsNotMatchingError extends NotAcceptableError { name = "RunnerTeamIdsNotMatchingError" @IsString() - message = "The ids don't match!! \n And if you wanted to change a runner's id: This isn't allowed" + message = "The ids don't match! \n And if you wanted to change a runner's id: This isn't allowed!" } /** From 43a4f1118da324016f9038451484f3b8e6764729 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 19:01:03 +0100 Subject: [PATCH 23/32] Updated loader comments and descriptions ref #39 --- src/loaders/database.ts | 1 + src/loaders/express.ts | 2 +- src/loaders/index.ts | 1 + src/loaders/openapi.ts | 6 ++++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/loaders/database.ts b/src/loaders/database.ts index 806b286..9dda78d 100644 --- a/src/loaders/database.ts +++ b/src/loaders/database.ts @@ -4,6 +4,7 @@ import { User } from '../models/entities/User'; import SeedUsers from '../seeds/SeedUsers'; /** * Loader for the database that creates the database connection and initializes the database tabels. + * It also triggers the seeding process if no users got detected in the database. */ export default async () => { const connection = await createConnection(); diff --git a/src/loaders/express.ts b/src/loaders/express.ts index fc3dbc4..416f3ea 100644 --- a/src/loaders/express.ts +++ b/src/loaders/express.ts @@ -2,7 +2,7 @@ import cookieParser from "cookie-parser"; import { Application } from "express"; /** * Loader for express related configurations. - * Currently only enables the proxy trust. + * Configures proxy trusts, globally used middlewares and other express features. */ export default async (app: Application) => { app.enable('trust proxy'); diff --git a/src/loaders/index.ts b/src/loaders/index.ts index 802a732..3057cf3 100644 --- a/src/loaders/index.ts +++ b/src/loaders/index.ts @@ -5,6 +5,7 @@ import openapiLoader from "./openapi"; /** * Index Loader that executes the other loaders in the right order. + * This basicly exists for abstraction and a overall better dev experience. */ export default async (app: Application) => { await databaseLoader(); diff --git a/src/loaders/openapi.ts b/src/loaders/openapi.ts index 9c270ed..44c6f34 100644 --- a/src/loaders/openapi.ts +++ b/src/loaders/openapi.ts @@ -5,7 +5,8 @@ import { routingControllersToSpec } from "routing-controllers-openapi"; import * as swaggerUiExpress from "swagger-ui-express"; /** - * Loader for everything openapi related - from creating the schema to serving it via a static route. + * Loader for everything openapi related - from creating the schema to serving it via a static route and swaggerUiExpress. + * All auth schema related stuff also has to be configured here */ export default async (app: Application) => { const storage = getMetadataArgsStorage(); @@ -26,7 +27,8 @@ export default async (app: Application) => { "AuthToken": { "type": "http", "scheme": "bearer", - "bearerFormat": "JWT" + "bearerFormat": "JWT", + description: "A JWT based access token. Use /api/auth/login or /api/auth/refresh to get one." } } }, From a88c0389c1dc6862fe1a10b03c1345a1196869c5 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 19:08:02 +0100 Subject: [PATCH 24/32] Code + Comment cleanup for the middlewares ref #39 --- src/middlewares/ErrorHandler.ts | 2 +- src/middlewares/RawBody.ts | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/middlewares/ErrorHandler.ts b/src/middlewares/ErrorHandler.ts index 40c1ff6..71ef2db 100644 --- a/src/middlewares/ErrorHandler.ts +++ b/src/middlewares/ErrorHandler.ts @@ -1,7 +1,7 @@ import { ExpressErrorMiddlewareInterface, Middleware } from "routing-controllers"; /** - * Our Error handling middlware that returns our custom httperrors to the user + * Our Error handling middlware that returns our custom httperrors to the user. */ @Middleware({ type: "after" }) export class ErrorHandler implements ExpressErrorMiddlewareInterface { diff --git a/src/middlewares/RawBody.ts b/src/middlewares/RawBody.ts index 58ff67d..57efefa 100644 --- a/src/middlewares/RawBody.ts +++ b/src/middlewares/RawBody.ts @@ -1,5 +1,10 @@ import { Request, Response } from 'express'; +/** + * Custom express middleware that appends the raw body to the request obeject. + * Mainly used for parsing csvs from boddies. + */ + const RawBodyMiddleware = (req: Request, res: Response, next: () => void) => { const body = [] req.on('data', chunk => { @@ -8,15 +13,6 @@ const RawBodyMiddleware = (req: Request, res: Response, next: () => void) => { req.on('end', () => { const rawBody = Buffer.concat(body) req['rawBody'] = rawBody - /* - switch (req.header('content-type')) { - case 'application/json': - req.body = JSON.parse(rawBody.toString()) - break - // add more body parsing if needs be - default: - } - */ next() }) req.on('error', () => { From a85d52437b7e448c8e35741eb71ed28ab3147f3b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 19:11:28 +0100 Subject: [PATCH 25/32] Code + comment cleanup for the seeds ref #39 --- src/seeds/SeedUsers.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/seeds/SeedUsers.ts b/src/seeds/SeedUsers.ts index 38027dd..c393a10 100644 --- a/src/seeds/SeedUsers.ts +++ b/src/seeds/SeedUsers.ts @@ -9,6 +9,10 @@ import { UserGroup } from '../models/entities/UserGroup'; import { PermissionAction } from '../models/enums/PermissionAction'; import { PermissionTarget } from '../models/enums/PermissionTargets'; +/** + * Seeds a admin group with a demo user into the database for initial setup and auto recovery. + * We know that the nameing isn't perfectly fitting. Feel free to change it. + */ export default class SeedUsers implements Seeder { public async run(factory: Factory, connection: Connection): Promise { let adminGroup: UserGroup = await this.createAdminGroup(connection); @@ -19,7 +23,7 @@ export default class SeedUsers implements Seeder { public async createAdminGroup(connection: Connection) { let adminGroup = new CreateUserGroup(); adminGroup.name = "ADMINS"; - adminGroup.description = "Has all possible permissions"; + adminGroup.description = "Have all possible permissions"; return await connection.getRepository(UserGroup).save(await adminGroup.toUserGroup()); } From 75332983c2b6eec549af8b479c864277102e3f7d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 19:38:22 +0100 Subject: [PATCH 26/32] Code + comment cleanup for the response models ref #39 --- src/models/responses/ResponseAuth.ts | 13 +++++--- src/models/responses/ResponseEmpty.ts | 2 +- src/models/responses/ResponseLogout.ts | 4 +-- src/models/responses/ResponseParticipant.ts | 19 ++++------- src/models/responses/ResponsePermission.ts | 8 +++-- src/models/responses/ResponsePrincipal.ts | 8 +++-- src/models/responses/ResponseRunner.ts | 7 ++-- src/models/responses/ResponseRunnerGroup.ts | 33 +++++-------------- .../responses/ResponseRunnerOrganisation.ts | 12 ++++--- src/models/responses/ResponseRunnerTeam.ts | 14 ++++---- src/models/responses/ResponseTrack.ts | 14 ++++---- src/models/responses/ResponseUser.ts | 18 +++++----- src/models/responses/ResponseUserGroup.ts | 22 +++++-------- 13 files changed, 83 insertions(+), 91 deletions(-) diff --git a/src/models/responses/ResponseAuth.ts b/src/models/responses/ResponseAuth.ts index 39a16ef..5a8aa9e 100644 --- a/src/models/responses/ResponseAuth.ts +++ b/src/models/responses/ResponseAuth.ts @@ -1,26 +1,29 @@ import { IsInt, IsString } from 'class-validator'; /** - * Defines a auth object + * Defines the repsonse auth. */ export class Auth { /** - * access_token - JWT shortterm access token + * The access_token - JWT shortterm access token. */ @IsString() access_token: string; + /** - * refresh_token - longterm refresh token (used for requesting new access tokens) + * The refresh_token - longterm refresh token (used for requesting new access tokens). */ @IsString() refresh_token: string; + /** - * access_token_expires_at - unix timestamp of access token expiry + * The unix timestamp for access the token's expiry. */ @IsInt() access_token_expires_at: number; + /** - * refresh_token_expires_at - unix timestamp of access token expiry + * The unix unix timestamp for the access token's expiry. */ @IsInt() refresh_token_expires_at: number; diff --git a/src/models/responses/ResponseEmpty.ts b/src/models/responses/ResponseEmpty.ts index 7787b2a..57b0543 100644 --- a/src/models/responses/ResponseEmpty.ts +++ b/src/models/responses/ResponseEmpty.ts @@ -1,7 +1,7 @@ import { IsString } from 'class-validator'; /** - * Defines a empty response object + * Defines a empty response object. */ export class ResponseEmpty { @IsString() diff --git a/src/models/responses/ResponseLogout.ts b/src/models/responses/ResponseLogout.ts index f0c109d..fdb8d49 100644 --- a/src/models/responses/ResponseLogout.ts +++ b/src/models/responses/ResponseLogout.ts @@ -1,11 +1,11 @@ import { IsString } from 'class-validator'; /** - * Defines a Logout object + * Defines the logout response. */ export class Logout { /** - * timestamp of logout + * The logout's timestamp. */ @IsString() timestamp: number; diff --git a/src/models/responses/ResponseParticipant.ts b/src/models/responses/ResponseParticipant.ts index 0647efe..148bcff 100644 --- a/src/models/responses/ResponseParticipant.ts +++ b/src/models/responses/ResponseParticipant.ts @@ -1,18 +1,12 @@ -import { - IsInt, - - - - IsString -} from "class-validator"; +import { IsInt, IsString } from "class-validator"; import { Participant } from '../entities/Participant'; /** - * Defines a participant response. + * Defines the participant response. */ export abstract class ResponseParticipant { /** - * Autogenerated unique id (primary key). + * The participant's id. */ @IsInt() id: number; @@ -25,7 +19,6 @@ export abstract class ResponseParticipant { /** * The participant's middle name. - * Optional. */ @IsString() middlename?: string; @@ -38,18 +31,20 @@ export abstract class ResponseParticipant { /** * The participant's phone number. - * Optional. */ @IsString() phone?: string; /** * The participant's e-mail address. - * Optional. */ @IsString() email?: string; + /** + * Creates a ResponseParticipant object from a participant. + * @param participant The participant the response shall be build for. + */ public constructor(participant: Participant) { this.id = participant.id; this.firstname = participant.firstname; diff --git a/src/models/responses/ResponsePermission.ts b/src/models/responses/ResponsePermission.ts index 23a3686..a6b0bc1 100644 --- a/src/models/responses/ResponsePermission.ts +++ b/src/models/responses/ResponsePermission.ts @@ -10,11 +10,11 @@ import { PermissionTarget } from '../enums/PermissionTargets'; import { ResponsePrincipal } from './ResponsePrincipal'; /** - * Defines a track of given length. + * Defines the permission response. */ export class ResponsePermission { /** - * Autogenerated unique id (primary key). + * The permission's id. */ @IsInt() id: number;; @@ -40,6 +40,10 @@ export class ResponsePermission { @IsEnum(PermissionAction) action: PermissionAction; + /** + * Creates a ResponsePermission object from a permission. + * @param permission The permission the response shall be build for. + */ public constructor(permission: Permission) { this.id = permission.id; this.principal = permission.principal.toResponse(); diff --git a/src/models/responses/ResponsePrincipal.ts b/src/models/responses/ResponsePrincipal.ts index 920bac2..afd4dd1 100644 --- a/src/models/responses/ResponsePrincipal.ts +++ b/src/models/responses/ResponsePrincipal.ts @@ -4,16 +4,20 @@ import { import { Principal } from '../entities/Principal'; /** - * Defines Principal's response class. + * Defines the principal response. */ export abstract class ResponsePrincipal { /** - * Autogenerated unique id (primary key). + * The principal's id. */ @IsInt() id: number; + /** + * Creates a ResponsePrincipal object from a principal. + * @param principal The principal the response shall be build for. + */ public constructor(principal: Principal) { this.id = principal.id; } diff --git a/src/models/responses/ResponseRunner.ts b/src/models/responses/ResponseRunner.ts index 01327c2..5fae2ee 100644 --- a/src/models/responses/ResponseRunner.ts +++ b/src/models/responses/ResponseRunner.ts @@ -7,13 +7,12 @@ import { RunnerGroup } from '../entities/RunnerGroup'; import { ResponseParticipant } from './ResponseParticipant'; /** - * Defines RunnerTeam's response class. + * Defines the runner response. */ export class ResponseRunner extends ResponseParticipant { /** * The runner's currently ran distance in meters. - * Optional. */ @IsInt() distance: number; @@ -24,6 +23,10 @@ export class ResponseRunner extends ResponseParticipant { @IsObject() group: RunnerGroup; + /** + * Creates a ResponseRunner object from a runner. + * @param runner The user the response shall be build for. + */ public constructor(runner: Runner) { super(runner); this.distance = runner.scans.filter(scan => { scan.valid === true }).reduce((sum, current) => sum + current.distance, 0); diff --git a/src/models/responses/ResponseRunnerGroup.ts b/src/models/responses/ResponseRunnerGroup.ts index 922f141..7be35a6 100644 --- a/src/models/responses/ResponseRunnerGroup.ts +++ b/src/models/responses/ResponseRunnerGroup.ts @@ -1,38 +1,20 @@ -import { - IsInt, - - - - IsNotEmpty, - - - - IsObject, - - - - IsOptional, - - - - IsString -} from "class-validator"; +import { IsInt, IsNotEmpty, IsObject, IsOptional, IsString } from "class-validator"; import { GroupContact } from '../entities/GroupContact'; import { RunnerGroup } from '../entities/RunnerGroup'; /** - * Defines a track of given length. + * Defines the runnerGroup response. */ export abstract class ResponseRunnerGroup { /** - * Autogenerated unique id (primary key). + * The runnerGroup's id. */ @IsInt() @IsNotEmpty() id: number;; /** - * The groups's name. + * The runnerGroup's name. */ @IsString() @IsNotEmpty() @@ -40,13 +22,16 @@ export abstract class ResponseRunnerGroup { /** - * The group's contact. - * Optional. + * The runnerGroup's contact. */ @IsObject() @IsOptional() contact?: GroupContact; + /** + * Creates a ResponseRunnerGroup object from a runnerGroup. + * @param group The runnerGroup the response shall be build for. + */ public constructor(group: RunnerGroup) { this.id = group.id; this.name = group.name; diff --git a/src/models/responses/ResponseRunnerOrganisation.ts b/src/models/responses/ResponseRunnerOrganisation.ts index e8b7b9a..edc1ff0 100644 --- a/src/models/responses/ResponseRunnerOrganisation.ts +++ b/src/models/responses/ResponseRunnerOrganisation.ts @@ -9,25 +9,27 @@ import { RunnerTeam } from '../entities/RunnerTeam'; import { ResponseRunnerGroup } from './ResponseRunnerGroup'; /** - * Defines RunnerOrgs's response class. + * Defines the runnerOrganisation response. */ export class ResponseRunnerOrganisation extends ResponseRunnerGroup { /** - * The orgs's address. - * Optional. + * The runnerOrganisation's address. */ @IsObject() @IsNotEmpty() address?: Address; /** - * The orgs associated teams. + * 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; diff --git a/src/models/responses/ResponseRunnerTeam.ts b/src/models/responses/ResponseRunnerTeam.ts index b26e2c2..0a15302 100644 --- a/src/models/responses/ResponseRunnerTeam.ts +++ b/src/models/responses/ResponseRunnerTeam.ts @@ -1,24 +1,24 @@ -import { - IsNotEmpty, - IsObject -} from "class-validator"; +import { IsNotEmpty, IsObject } from "class-validator"; import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerTeam } from '../entities/RunnerTeam'; import { ResponseRunnerGroup } from './ResponseRunnerGroup'; /** - * Defines RunnerTeam's response class. + * Defines the runnerTeam response. */ export class ResponseRunnerTeam extends ResponseRunnerGroup { /** - * The team's parent group (organisation). - * Optional. + * The runnerTeam's parent group (organisation). */ @IsObject() @IsNotEmpty() parentGroup: RunnerOrganisation; + /** + * Creates a ResponseRunnerTeam object from a runnerTeam. + * @param team The team the response shall be build for. + */ public constructor(team: RunnerTeam) { super(team); this.parentGroup = team.parentGroup; diff --git a/src/models/responses/ResponseTrack.ts b/src/models/responses/ResponseTrack.ts index ce1d74d..83da863 100644 --- a/src/models/responses/ResponseTrack.ts +++ b/src/models/responses/ResponseTrack.ts @@ -1,16 +1,12 @@ -import { - IsInt, - - IsString -} from "class-validator"; +import { IsInt, IsString } from "class-validator"; import { Track } from '../entities/Track'; /** - * Defines a track of given length. + * Defines the track response. */ export class ResponseTrack { /** - * Autogenerated unique id (primary key). + * The track's id. */ @IsInt() id: number;; @@ -27,6 +23,10 @@ export class ResponseTrack { @IsInt() distance: number; + /** + * Creates a ResponseTrack object from a track. + * @param track The track the response shall be build for. + */ public constructor(track: Track) { this.id = track.id; this.name = track.name; diff --git a/src/models/responses/ResponseUser.ts b/src/models/responses/ResponseUser.ts index 0927106..67fad20 100644 --- a/src/models/responses/ResponseUser.ts +++ b/src/models/responses/ResponseUser.ts @@ -11,7 +11,7 @@ import { UserGroup } from '../entities/UserGroup'; import { ResponsePrincipal } from './ResponsePrincipal'; /** - * Defines a user response. + * Defines the user response. */ export class ResponseUser extends ResponsePrincipal { /** @@ -22,7 +22,6 @@ export class ResponseUser extends ResponsePrincipal { /** * The user's middle name. - * Optional. */ @IsString() middlename?: string; @@ -35,52 +34,53 @@ export class ResponseUser extends ResponsePrincipal { /** * The user's phone number. - * Optional. */ @IsString() phone?: string; /** * The user's e-mail address. - * Optional. */ @IsString() email?: string; /** * The user's username. - * Optional. */ @IsString() username?: string; /** - * is user enabled? + * Is user enabled? */ @IsBoolean() enabled: boolean = true; /** - * profilepic + * The user's profile pic. */ @IsString() @IsOptional() profilePic?: string; /** - * Groups + * The groups that the user is a part of. */ @IsArray() @IsOptional() groups: UserGroup[]; /** - * permissions + * The user's permissions. */ @IsArray() @IsOptional() permissions: Permission[]; + /** + * Creates a ResponseUser object from a user. + * @param user The user the response shall be build for. + */ public constructor(user: User) { super(user); this.firstname = user.firstname; diff --git a/src/models/responses/ResponseUserGroup.ts b/src/models/responses/ResponseUserGroup.ts index 1317c8f..6dd428d 100644 --- a/src/models/responses/ResponseUserGroup.ts +++ b/src/models/responses/ResponseUserGroup.ts @@ -1,41 +1,37 @@ -import { - IsArray, - - - IsNotEmpty, - - IsOptional, - IsString -} from "class-validator"; +import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator"; import { Permission } from '../entities/Permission'; import { UserGroup } from '../entities/UserGroup'; import { ResponsePrincipal } from './ResponsePrincipal'; /** - * Defines a user response. + * Defines the userGroup response. */ export class ResponseUserGroup extends ResponsePrincipal { /** - * The group's name + * The userGroup's name. */ @IsNotEmpty() @IsString() name: string; /** - * The group's description + * The userGroup's description. */ @IsOptional() @IsString() description?: string; /** - * permissions + * The userGroup's permissions. */ @IsArray() @IsOptional() permissions: Permission[]; + /** + * Creates a ResponseUserGroup object from a userGroup. + * @param group The userGroup the response shall be build for. + */ public constructor(group: UserGroup) { super(group); this.name = group.name; From a03f1a438d1e15cb68015a0a90c7e9ebbc2def95 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sun, 20 Dec 2020 19:39:13 +0100 Subject: [PATCH 27/32] Code + comment cleanup for the enums ref #39 --- src/models/enums/PermissionAction.ts | 3 +++ src/models/enums/PermissionTargets.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/models/enums/PermissionAction.ts b/src/models/enums/PermissionAction.ts index 0e984bf..69b990f 100644 --- a/src/models/enums/PermissionAction.ts +++ b/src/models/enums/PermissionAction.ts @@ -1,3 +1,6 @@ +/** + * This enum contains all posible actions for permissions. + */ export enum PermissionAction { GET = 'GET', CREATE = 'CREATE', diff --git a/src/models/enums/PermissionTargets.ts b/src/models/enums/PermissionTargets.ts index 4f88eac..d31ce37 100644 --- a/src/models/enums/PermissionTargets.ts +++ b/src/models/enums/PermissionTargets.ts @@ -1,3 +1,6 @@ +/** + * This enum contains all posible targets for permissions. + */ export enum PermissionTarget { RUNNER = 'RUNNER', ORGANISATION = 'ORGANISATION', From d20d7382180b798ecf96ba30d7171a870be682f5 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 21 Dec 2020 15:29:32 +0100 Subject: [PATCH 28/32] Code + comment cleanup for the entities ref #39 --- src/models/entities/Address.ts | 6 +++- src/models/entities/DistanceDonation.ts | 12 ++++--- src/models/entities/Donation.ts | 4 ++- src/models/entities/Donor.ts | 6 ++-- src/models/entities/FixedDonation.ts | 3 +- src/models/entities/GroupContact.ts | 14 ++++---- src/models/entities/Participant.ts | 11 ++++--- src/models/entities/Permission.ts | 15 ++++++--- src/models/entities/Principal.ts | 12 ++++--- src/models/entities/Runner.ts | 18 ++++++++--- src/models/entities/RunnerCard.ts | 12 ++++--- src/models/entities/RunnerGroup.ts | 6 ++-- src/models/entities/RunnerOrganisation.ts | 9 +++--- src/models/entities/RunnerTeam.ts | 5 +-- src/models/entities/Scan.ts | 14 +++++--- src/models/entities/ScanStation.ts | 8 +++-- src/models/entities/Track.ts | 9 ++++-- src/models/entities/TrackScan.ts | 14 +++++--- src/models/entities/User.ts | 39 ++++++++++++++--------- src/models/entities/UserAction.ts | 20 +++++++----- src/models/entities/UserGroup.ts | 6 +++- 21 files changed, 156 insertions(+), 87 deletions(-) diff --git a/src/models/entities/Address.ts b/src/models/entities/Address.ts index 6cc1d11..54c490e 100644 --- a/src/models/entities/Address.ts +++ b/src/models/entities/Address.ts @@ -10,7 +10,8 @@ import { Participant } from "./Participant"; import { RunnerOrganisation } from "./RunnerOrganisation"; /** - * Defines a address (to be used for contact information). + * Defines the Address entity. + * Implemented this way to prevent any formatting differences. */ @Entity() export class Address { @@ -23,6 +24,7 @@ export class Address { /** * The address's description. + * Optional and mostly for UX. */ @Column({ nullable: true }) @IsString() @@ -49,6 +51,8 @@ export class Address { /** * The address's postal code. + * This will get checked against the postal code syntax for the configured country. + * TODO: Implement the config option. */ @Column() @IsString() diff --git a/src/models/entities/DistanceDonation.ts b/src/models/entities/DistanceDonation.ts index 3103865..d263e90 100644 --- a/src/models/entities/DistanceDonation.ts +++ b/src/models/entities/DistanceDonation.ts @@ -4,19 +4,21 @@ import { Donation } from "./Donation"; import { Runner } from "./Runner"; /** - * Defines a distance based donation. - * Here people donate a certain amout per kilometer + * Defines the DistanceDonation entity. + * For distanceDonations a donor pledges to donate a certain amount for each kilometer ran by a runner. */ @ChildEntity() export class DistanceDonation extends Donation { /** - * The runner associated. + * The donation's associated runner. + * Used as the source of the donation's distance. */ @IsNotEmpty() @ManyToOne(() => Runner, runner => runner.distanceDonations) runner: Runner; /** + * The donation's amount donated per distance. * The amount the donor set to be donated per kilometer that the runner ran. */ @Column() @@ -26,12 +28,12 @@ export class DistanceDonation extends Donation { /** * The donation's amount in cents (or whatever your currency's smallest unit is.). - * The exact implementation may differ for each type of donation. + * Get's calculated from the runner's distance ran and the amount donated per kilometer. */ public get amount(): number { let calculatedAmount = -1; try { - calculatedAmount = this.amountPerDistance * this.runner.distance; + calculatedAmount = this.amountPerDistance * (this.runner.distance / 1000); } catch (error) { throw error; } diff --git a/src/models/entities/Donation.ts b/src/models/entities/Donation.ts index 4af3485..100f0bb 100644 --- a/src/models/entities/Donation.ts +++ b/src/models/entities/Donation.ts @@ -6,7 +6,9 @@ import { Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typ import { Participant } from "./Participant"; /** - * Defines the donation interface. + * Defines the Donation entity. + * A donation just associates a donor with a donation amount. + * The specifics of the amoun's determination has to be implemented in child classes. */ @Entity() @TableInheritance({ column: { name: "type", type: "varchar" } }) diff --git a/src/models/entities/Donor.ts b/src/models/entities/Donor.ts index b92b06a..c0f914e 100644 --- a/src/models/entities/Donor.ts +++ b/src/models/entities/Donor.ts @@ -3,13 +3,13 @@ import { ChildEntity, Column } from "typeorm"; import { Participant } from "./Participant"; /** - * Defines a donor. + * Defines the Donor entity. */ @ChildEntity() export class Donor extends Participant { /** - * Does this donor need a receipt?. - * Default: false + * Does this donor need a receipt? + * Will later be used to automaticly generate donation receipts. */ @Column() @IsBoolean() diff --git a/src/models/entities/FixedDonation.ts b/src/models/entities/FixedDonation.ts index 8ab366d..db53e2f 100644 --- a/src/models/entities/FixedDonation.ts +++ b/src/models/entities/FixedDonation.ts @@ -3,7 +3,8 @@ import { ChildEntity, Column } from "typeorm"; import { Donation } from "./Donation"; /** - * Defines a fixed donation. + * Defines the FixedDonation entity. + * In the past there was no easy way to track fixed donations (eg. for creating donation receipts). */ @ChildEntity() export class FixedDonation extends Donation { diff --git a/src/models/entities/GroupContact.ts b/src/models/entities/GroupContact.ts index d2dd367..f524863 100644 --- a/src/models/entities/GroupContact.ts +++ b/src/models/entities/GroupContact.ts @@ -13,13 +13,14 @@ import { Address } from "./Address"; import { RunnerGroup } from "./RunnerGroup"; /** - * Defines a group's contact. + * Defines the GroupContact entity. + * Mainly it's own class to reduce duplicate code and enable contact's to be associated with multiple groups. */ @Entity() export class GroupContact { /** - * Autogenerated unique id (primary key). - */ + * Autogenerated unique id (primary key). + */ @PrimaryGeneratedColumn() @IsInt() id: number; @@ -34,7 +35,6 @@ export class GroupContact { /** * The contact's middle name. - * Optional */ @Column({ nullable: true }) @IsOptional() @@ -51,7 +51,7 @@ export class GroupContact { /** * The contact's address. - * Optional + * This is a address object to prevent any formatting differences. */ @IsOptional() @ManyToOne(() => Address, address => address.participants, { nullable: true }) @@ -59,7 +59,7 @@ export class GroupContact { /** * The contact's phone number. - * Optional + * This will be validated against the configured country phone numer syntax (default: international). */ @Column({ nullable: true }) @IsOptional() @@ -68,7 +68,7 @@ export class GroupContact { /** * The contact's email address. - * Optional + * Could later be used to automaticly send mails concerning the contact's associated groups. */ @Column({ nullable: true }) @IsOptional() diff --git a/src/models/entities/Participant.ts b/src/models/entities/Participant.ts index 6f3554a..e2e2263 100644 --- a/src/models/entities/Participant.ts +++ b/src/models/entities/Participant.ts @@ -13,7 +13,8 @@ import { Address } from "./Address"; import { Donation } from "./Donation"; /** - * Defines the participant interface. + * Defines the Participant entity. + * Participans can donate and therefor be associated with donation entities. */ @Entity() @TableInheritance({ column: { name: "type", type: "varchar" } }) @@ -35,7 +36,6 @@ export abstract class Participant { /** * The participant's middle name. - * Optional */ @Column({ nullable: true }) @IsOptional() @@ -52,14 +52,14 @@ export abstract class Participant { /** * The participant's address. - * Optional + * This is a address object to prevent any formatting differences. */ @ManyToOne(() => Address, address => address.participants, { nullable: true }) address?: Address; /** * The participant's phone number. - * Optional + * This will be validated against the configured country phone numer syntax (default: international). */ @Column({ nullable: true }) @IsOptional() @@ -68,7 +68,7 @@ export abstract class Participant { /** * The participant's email address. - * Optional + * Can be used to contact the participant. */ @Column({ nullable: true }) @IsOptional() @@ -77,6 +77,7 @@ export abstract class Participant { /** * Used to link the participant as the donor of a donation. + * Attention: Only runner's can be associated as a distanceDonations distance source. */ @OneToMany(() => Donation, donation => donation.donor, { nullable: true }) donations: Donation[]; diff --git a/src/models/entities/Permission.ts b/src/models/entities/Permission.ts index b95bb84..6a07312 100644 --- a/src/models/entities/Permission.ts +++ b/src/models/entities/Permission.ts @@ -8,7 +8,9 @@ import { PermissionAction } from '../enums/PermissionAction'; import { PermissionTarget } from '../enums/PermissionTargets'; import { Principal } from './Principal'; /** - * Defines the Permission interface. + * Defines the Permission entity. + * Permissions can be granted to principals. + * The permissions possible targets and actions are defined in enums. */ @Entity() export class Permission { @@ -20,13 +22,14 @@ export class Permission { id: number; /** - * The permissions principal + * The permission's principal. */ @ManyToOne(() => Principal, principal => principal.permissions) principal: Principal; /** - * The target + * The permission's target. + * This get's stored as the enum value's string representation for compatability reasons. */ @Column({ type: 'varchar' }) @IsNotEmpty() @@ -34,14 +37,16 @@ export class Permission { target: PermissionTarget; /** - * The action type + * The permission's action. + * This get's stored as the enum value's string representation for compatability reasons. */ @Column({ type: 'varchar' }) @IsEnum(PermissionAction) action: PermissionAction; /** - * Turn this into a string for exporting (and jwts). + * Turn this into a string for exporting and jwts. + * Mainly used to shrink the size of jwts (otherwise the would contain entire objects). */ public toString(): string { return this.target + ":" + this.action; diff --git a/src/models/entities/Principal.ts b/src/models/entities/Principal.ts index 618e3db..f33d0be 100644 --- a/src/models/entities/Principal.ts +++ b/src/models/entities/Principal.ts @@ -4,23 +4,27 @@ import { ResponsePrincipal } from '../responses/ResponsePrincipal'; import { Permission } from './Permission'; /** - * Defines a admin user. + * Defines the principal entity. + * A principal basicly is any entity that can receive permissions for the api (users and their groups). */ @Entity() @TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Principal { /** - * autogenerated unique id (primary key). + * Autogenerated unique id (primary key). */ @PrimaryGeneratedColumn() @IsInt() id: number; /** -* permissions -*/ + * The participant's permissions. + */ @OneToMany(() => Permission, permission => permission.principal, { nullable: true }) permissions: Permission[]; + /** + * Turns this entity into it's response class. + */ public abstract toResponse(): ResponsePrincipal; } \ No newline at end of file diff --git a/src/models/entities/Runner.ts b/src/models/entities/Runner.ts index 6f4033a..def167d 100644 --- a/src/models/entities/Runner.ts +++ b/src/models/entities/Runner.ts @@ -7,44 +7,52 @@ import { RunnerGroup } from "./RunnerGroup"; import { Scan } from "./Scan"; /** - * Defines a runner. + * Defines the runner entity. + * Runners differ from participants in being able to actually accumulate a ran distance through scans. + * Runner's get organized in groups. */ @ChildEntity() export class Runner extends Participant { /** * The runner's associated group. + * Can be a runner team or organisation. */ @IsNotEmpty() @ManyToOne(() => RunnerGroup, group => group.runners, { nullable: false }) group: RunnerGroup; /** - * Used to link runners to donations. + * The runner's associated distanceDonations. + * Used to link runners to distanceDonations in order to calculate the donation's amount based on the distance the runner ran. */ @OneToMany(() => DistanceDonation, distanceDonation => distanceDonation.runner, { nullable: true }) distanceDonations: DistanceDonation[]; /** - * Used to link runners to cards. + * The runner's associated cards. + * Used to link runners to cards - yes a runner be associated with multiple cards this came in handy in the past. */ @OneToMany(() => RunnerCard, card => card.runner, { nullable: true }) cards: RunnerCard[]; /** - * Used to link runners to a scans + * The runner's associated scans. + * Used to link runners to scans (valid and fraudulant). */ @OneToMany(() => Scan, scan => scan.runner, { nullable: true }) scans: Scan[]; /** * Returns all valid scans associated with this runner. + * This is implemented here to avoid duplicate code in other files. */ public get validScans(): Scan[] { return this.scans.filter(scan => { scan.valid === true }); } /** - * Returns the total distance ran by this runner. + * Returns the total distance ran by this runner based on all his valid scans. + * This is implemented here to avoid duplicate code in other files. */ @IsInt() public get distance(): number { diff --git a/src/models/entities/RunnerCard.ts b/src/models/entities/RunnerCard.ts index 49ea0da..5f48257 100644 --- a/src/models/entities/RunnerCard.ts +++ b/src/models/entities/RunnerCard.ts @@ -11,7 +11,9 @@ import { Runner } from "./Runner"; import { TrackScan } from "./TrackScan"; /** - * Defines a card that can be scanned via a scanner station. + * Defines the RunnerCard entity. + * A runnerCard is a physical representation for a runner. + * It can be associated with a runner to create scans via the scan station's. */ @Entity() export class RunnerCard { @@ -23,7 +25,8 @@ export class RunnerCard { id: number; /** - * The runner that is currently associated with this card. + * The card's currently associated runner. + * To increase reusability a card can be reassigned. */ @IsOptional() @ManyToOne(() => Runner, runner => runner.cards, { nullable: true }) @@ -32,7 +35,7 @@ export class RunnerCard { /** * The card's code. * This has to be able to being converted to something barcode compatible. - * could theoretically be autogenerated + * Will get automaticlly generated (not implemented yet). */ @Column() @IsEAN() @@ -49,7 +52,8 @@ export class RunnerCard { enabled: boolean = true; /** - * Used to link cards to a track scans. + * The card's associated scans. + * Used to link cards to track scans. */ @OneToMany(() => TrackScan, scan => scan.track, { nullable: true }) scans: TrackScan[]; diff --git a/src/models/entities/RunnerGroup.ts b/src/models/entities/RunnerGroup.ts index a2bd585..4256f6e 100644 --- a/src/models/entities/RunnerGroup.ts +++ b/src/models/entities/RunnerGroup.ts @@ -9,7 +9,8 @@ import { GroupContact } from "./GroupContact"; import { Runner } from "./Runner"; /** - * Defines the runnerGroup interface. + * Defines the RunnerGroup entity. + * This is used to group runners together (as the name suggests). */ @Entity() @TableInheritance({ column: { name: "type", type: "varchar" } }) @@ -31,13 +32,14 @@ export abstract class RunnerGroup { /** * The group's contact. - * Optional + * This is mostly a feature for the group managers and public relations. */ @IsOptional() @ManyToOne(() => GroupContact, contact => contact.groups, { nullable: true }) contact?: GroupContact; /** + * The group's associated runners. * Used to link runners to a runner group. */ @OneToMany(() => Runner, runner => runner.group, { nullable: true }) diff --git a/src/models/entities/RunnerOrganisation.ts b/src/models/entities/RunnerOrganisation.ts index 28b90d8..8d24077 100644 --- a/src/models/entities/RunnerOrganisation.ts +++ b/src/models/entities/RunnerOrganisation.ts @@ -5,22 +5,23 @@ import { RunnerGroup } from "./RunnerGroup"; import { RunnerTeam } from "./RunnerTeam"; /** - * Defines a runner organisation (business or school for example). + * Defines the RunnerOrganisation entity. + * This usually is a school, club or company. */ @ChildEntity() export class RunnerOrganisation extends RunnerGroup { /** * The organisations's address. - * Optional */ @IsOptional() @ManyToOne(() => Address, address => address.groups, { nullable: true }) address?: Address; /** - * Used to link teams to runner groups. - */ + * The organisation's teams. + * Used to link teams to a organisation. + */ @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true }) teams: RunnerTeam[]; } \ No newline at end of file diff --git a/src/models/entities/RunnerTeam.ts b/src/models/entities/RunnerTeam.ts index bcae3fd..e84ee9b 100644 --- a/src/models/entities/RunnerTeam.ts +++ b/src/models/entities/RunnerTeam.ts @@ -4,14 +4,15 @@ import { RunnerGroup } from "./RunnerGroup"; import { RunnerOrganisation } from "./RunnerOrganisation"; /** - * Defines a runner team (class or deparment for example). + * Defines the RunnerTeam entity. + * This usually is a school class or department in a company. */ @ChildEntity() export class RunnerTeam extends RunnerGroup { /** * The team's parent group. - * Optional + * Every team has to be part of a runnerOrganisation - this get's checked on creation and update. */ @IsNotEmpty() @ManyToOne(() => RunnerOrganisation, org => org.teams, { nullable: true }) diff --git a/src/models/entities/Scan.ts b/src/models/entities/Scan.ts index b8fc079..1b66851 100644 --- a/src/models/entities/Scan.ts +++ b/src/models/entities/Scan.ts @@ -9,7 +9,8 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } f import { Runner } from "./Runner"; /** - * Defines the scan interface. + * Defines the Scan entity. + * A scan basicly adds a certain distance to a runner's total ran distance. */ @Entity() @TableInheritance({ column: { name: "type", type: "varchar" } }) @@ -22,7 +23,8 @@ export abstract class Scan { id: number; /** - * The associated runner. + * The scan's associated runner. + * This is important to link ran distances to runners. */ @IsNotEmpty() @ManyToOne(() => Runner, runner => runner.scans, { nullable: false }) @@ -30,15 +32,17 @@ export abstract class Scan { /** * The scan's distance in meters. + * Can be set manually or derived from another object. */ @IsInt() @IsPositive() abstract distance: number; /** - * Is the scan valid (for fraud reasons). - * Default: true - */ + * Is the scan valid (for fraud reasons). + * The determination of validity will work differently for every child class. + * Default: true + */ @Column() @IsBoolean() valid: boolean = true; diff --git a/src/models/entities/ScanStation.ts b/src/models/entities/ScanStation.ts index f014da8..1df5abf 100644 --- a/src/models/entities/ScanStation.ts +++ b/src/models/entities/ScanStation.ts @@ -10,7 +10,8 @@ import { Track } from "./Track"; import { TrackScan } from "./TrackScan"; /** - * ScannerStations have the ability to create scans for specific tracks. + * Defines the ScanStation entity. + * ScanStations get used to create TrackScans for runners based on a scan of their runnerCard. */ @Entity() export class ScanStation { @@ -23,6 +24,7 @@ export class ScanStation { /** * The station's description. + * Mostly for better UX when traceing back stuff. */ @Column({ nullable: true }) @IsOptional() @@ -31,6 +33,7 @@ export class ScanStation { /** * The track this station is associated with. + * All scans created by this station will also be associated with this track. */ @IsNotEmpty() @ManyToOne(() => Track, track => track.stations, { nullable: false }) @@ -38,6 +41,7 @@ export class ScanStation { /** * The station's api key. + * This is used to authorize a station against the api (not implemented yet). */ @Column() @IsNotEmpty() @@ -45,7 +49,7 @@ export class ScanStation { key: string; /** - * Is the station enabled (for fraud reasons)? + * Is the station enabled (for fraud and setup reasons)? * Default: true */ @Column() diff --git a/src/models/entities/Track.ts b/src/models/entities/Track.ts index 34f3bb6..22544d0 100644 --- a/src/models/entities/Track.ts +++ b/src/models/entities/Track.ts @@ -1,7 +1,6 @@ import { IsInt, IsNotEmpty, - IsPositive, IsString } from "class-validator"; @@ -10,7 +9,7 @@ import { ScanStation } from "./ScanStation"; import { TrackScan } from "./TrackScan"; /** - * Defines a track of given length. + * Defines the Track entity. */ @Entity() export class Track { @@ -23,6 +22,7 @@ export class Track { /** * The track's name. + * Mainly here for UX. */ @Column() @IsString() @@ -31,6 +31,7 @@ export class Track { /** * The track's length/distance in meters. + * Will be used to calculate runner's ran distances. */ @Column() @IsInt() @@ -38,13 +39,15 @@ export class Track { distance: number; /** - * Used to link scan stations to track. + * Used to link scan stations to a certain track. + * This makes the configuration of the scan stations easier. */ @OneToMany(() => ScanStation, station => station.track, { nullable: true }) stations: ScanStation[]; /** * Used to link track scans to a track. + * The scan will derive it's distance from the track's distance. */ @OneToMany(() => TrackScan, scan => scan.track, { nullable: true }) scans: TrackScan[]; diff --git a/src/models/entities/TrackScan.ts b/src/models/entities/TrackScan.ts index 759c3d7..45be379 100644 --- a/src/models/entities/TrackScan.ts +++ b/src/models/entities/TrackScan.ts @@ -12,26 +12,30 @@ import { ScanStation } from "./ScanStation"; import { Track } from "./Track"; /** - * Defines the scan interface. + * Defines the TrackScan entity. + * A track scan usaually get's generated by a scan station. */ @ChildEntity() export class TrackScan extends Scan { /** - * The associated track. + * The scan's associated track. + * This is used to determine the scan's distance. */ @IsNotEmpty() @ManyToOne(() => Track, track => track.scans, { nullable: true }) track: Track; /** - * The associated card. + * The runnerCard associated with the scan. + * This get's saved for documentation and management purposes. */ @IsNotEmpty() @ManyToOne(() => RunnerCard, card => card.scans, { nullable: true }) card: RunnerCard; /** - * The scanning station. + * The scanning station that created the scan. + * Mainly used for logging and traceing back scans (or errors) */ @IsNotEmpty() @ManyToOne(() => ScanStation, station => station.scans, { nullable: true }) @@ -39,6 +43,7 @@ export class TrackScan extends Scan { /** * The scan's distance in meters. + * This just get's loaded from it's track. */ @IsInt() @IsPositive() @@ -48,6 +53,7 @@ export class TrackScan extends Scan { /** * The scan's creation timestamp. + * Will be used to implement fraud detection. */ @Column() @IsDateString() diff --git a/src/models/entities/User.ts b/src/models/entities/User.ts index 21970c4..4cafa8d 100644 --- a/src/models/entities/User.ts +++ b/src/models/entities/User.ts @@ -8,26 +8,29 @@ import { UserAction } from './UserAction'; import { UserGroup } from './UserGroup'; /** - * Defines a admin user. + * Defines the User entity. + * Users are the ones that can use the "admin" webui and do stuff in the backend. */ @ChildEntity() export class User extends Principal { /** - * uuid + * The user's uuid. + * Mainly gets used as a per-user salt for the password hash. */ @Column({ unique: true }) @IsUUID(4) uuid: string; /** - * user email + * The user's e-mail address. + * Either username or email has to be set (otherwise the user couldn't log in). */ @Column({ nullable: true, unique: true }) @IsEmail() email?: string; /** - * user phone + * The user's phone number. */ @Column({ nullable: true }) @IsOptional() @@ -35,14 +38,15 @@ export class User extends Principal { phone?: string; /** - * username + * The user's username. + * Either username or email has to be set (otherwise the user couldn't log in). */ @Column({ nullable: true, unique: true }) @IsString() username?: string; /** - * firstname + * The user's first name. */ @Column() @IsString() @@ -50,7 +54,7 @@ export class User extends Principal { firstname: string; /** - * middlename + * The user's middle name. */ @Column({ nullable: true }) @IsString() @@ -58,7 +62,7 @@ export class User extends Principal { middlename?: string; /** - * lastname + * The user's last name. */ @Column() @IsString() @@ -66,7 +70,8 @@ export class User extends Principal { lastname: string; /** - * password + * The user's password. + * This is a argon2 hash salted with the user's uuid. */ @Column() @IsString() @@ -74,7 +79,8 @@ export class User extends Principal { password: string; /** - * groups + * The groups this user is a part of. + * The user will inherit the groups permissions (without overwriting his own). */ @IsOptional() @ManyToMany(() => UserGroup, { nullable: true }) @@ -82,21 +88,23 @@ export class User extends Principal { groups: UserGroup[]; /** - * is user enabled? + * Is this user enabled? */ @Column() @IsBoolean() enabled: boolean = true; /** - * jwt refresh count + * The user's jwt refresh token count. + * Used to invalidate jwts. */ @IsInt() @Column({ default: 1 }) refreshTokenCount?: number; /** - * profilepic + * The user's profile picture. + * We haven't decided yet if this will be a bas64 encoded image or just a link to the profile picture. */ @Column({ nullable: true, unique: true }) @IsString() @@ -104,14 +112,15 @@ export class User extends Principal { profilePic?: string; /** - * actions + * The actions performed by this user. + * For documentation purposes only, will be implemented later. */ @IsOptional() @OneToMany(() => UserAction, action => action.user, { nullable: true }) actions: UserAction[] /** - * Turn this into a response. + * Turns this entity into it's response class. */ public toResponse(): ResponsePrincipal { return new ResponseUser(this); diff --git a/src/models/entities/UserAction.ts b/src/models/entities/UserAction.ts index 92c41f0..d22bd37 100644 --- a/src/models/entities/UserAction.ts +++ b/src/models/entities/UserAction.ts @@ -1,14 +1,17 @@ import { + IsEnum, IsInt, IsNotEmpty, IsOptional, IsString } from "class-validator"; import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { PermissionAction } from '../enums/PermissionAction'; import { User } from './User'; /** - * Defines the UserAction interface. + * Defines the UserAction entity. + * Will later be used to document a user's actions. */ @Entity() export class UserAction { @@ -20,7 +23,7 @@ export class UserAction { id: number; /** - * user + * The user that performed the action. */ @ManyToOne(() => User, user => user.actions) user: User @@ -34,15 +37,16 @@ export class UserAction { target: string; /** - * The actions's action (e.g. UPDATE) + * The actions's action (e.g. UPDATE). + * Directly pulled from the PermissionAction Enum. */ - @Column() - @IsNotEmpty() - @IsString() - action: string; + @Column({ type: 'varchar' }) + @IsEnum(PermissionAction) + action: PermissionAction; /** - * The description of change (before-> after; e.g. distance:15->17) + * The description of the change (before-> after; e.g. distance:15->17). + * Will later be defined in more detail. */ @Column({ nullable: true }) @IsOptional() diff --git a/src/models/entities/UserGroup.ts b/src/models/entities/UserGroup.ts index c14f8fb..4d45a3f 100644 --- a/src/models/entities/UserGroup.ts +++ b/src/models/entities/UserGroup.ts @@ -9,7 +9,8 @@ import { ResponseUserGroup } from '../responses/ResponseUserGroup'; import { Principal } from './Principal'; /** - * Defines the UserGroup interface. + * Defines the UserGroup entity. + * This entity describes a group of users with a set of permissions. */ @ChildEntity() export class UserGroup extends Principal { @@ -30,6 +31,9 @@ export class UserGroup extends Principal { @IsString() description?: string; + /** + * Turns this entity into it's response class. + */ public toResponse(): ResponsePrincipal { return new ResponseUserGroup(this); } From 1d0d79f3da52adb9e070812f2a8428bad0303f2e Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 21 Dec 2020 16:08:10 +0100 Subject: [PATCH 29/32] First part of the action comment refactoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #39 Why did i volunteer for this? It's just a glorified sleeping aid 😴 --- src/models/actions/CreateAuth.ts | 30 ++++++++++++++-- src/models/actions/HandleLogout.ts | 12 +++++++ src/models/actions/ImportRunner.ts | 34 +++++++++++++------ src/models/actions/RefreshAuth.ts | 12 +++++++ src/models/actions/UpdatePermission.ts | 13 ++++--- src/models/actions/UpdateRunner.ts | 9 +++-- .../actions/UpdateRunnerOrganisation.ts | 10 ++++-- src/models/actions/UpdateRunnerTeam.ts | 12 +++++-- src/models/actions/UpdateUser.ts | 23 ++++++++----- 9 files changed, 123 insertions(+), 32 deletions(-) diff --git a/src/models/actions/CreateAuth.ts b/src/models/actions/CreateAuth.ts index adec57c..375cf2f 100644 --- a/src/models/actions/CreateAuth.ts +++ b/src/models/actions/CreateAuth.ts @@ -1,5 +1,5 @@ import * as argon2 from "argon2"; -import { IsEmail, IsOptional, IsString } from 'class-validator'; +import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { getConnectionManager } from 'typeorm'; import { InvalidCredentialsError, PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; @@ -7,17 +7,41 @@ import { JwtCreator } from '../../jwtcreator'; import { User } from '../entities/User'; import { Auth } from '../responses/ResponseAuth'; +/** + * This class is used to create auth credentials. + * To be a little bit more exact: Is takes in a username/email + password and creates a new access and refresh token for the user. + * It of course checks for user existance, password validity and so on. + */ export class CreateAuth { + /** + * The username of the user that want's to login. + * Either username or email have to be provided. + */ @IsOptional() @IsString() username?: string; - @IsString() - password: string; + + /** + * The email address of the user that want's to login. + * Either username or email have to be provided. + */ @IsOptional() @IsEmail() @IsString() email?: string; + /** + * The user's password. + * Will be checked against an argon2 hash. + */ + @IsNotEmpty() + @IsString() + password: string; + + + /** + * Creates a new auth object based on this. + */ public async toAuth(): Promise { let newAuth: Auth = new Auth(); diff --git a/src/models/actions/HandleLogout.ts b/src/models/actions/HandleLogout.ts index 165c78e..40bd572 100644 --- a/src/models/actions/HandleLogout.ts +++ b/src/models/actions/HandleLogout.ts @@ -6,11 +6,23 @@ import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, Us import { User } from '../entities/User'; import { Logout } from '../responses/ResponseLogout'; +/** + * This class handels a user logging out of the system. + * Of course it check's the user's provided credential (token) before logging him out. + */ export class HandleLogout { + /** + * A stringyfied jwt access token. + * Will get checked for validity. + */ @IsString() @IsOptional() token?: string; + /** + * Logs the user out. + * This gets achived by increasing the user's refresh token count, thereby invalidateing all currently existing jwts for that user. + */ public async logout(): Promise { let logout: Logout = new Logout(); if (!this.token || this.token === undefined) { diff --git a/src/models/actions/ImportRunner.ts b/src/models/actions/ImportRunner.ts index 3f5d97e..b1da7f7 100644 --- a/src/models/actions/ImportRunner.ts +++ b/src/models/actions/ImportRunner.ts @@ -7,6 +7,10 @@ import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerTeam } from '../entities/RunnerTeam'; import { CreateRunner } from './CreateRunner'; +/** + * Special class used to import runners from csv files - or json arrays created from csv to be exact. + * Why you ask? Because the past has shown us that a non excel/csv based workflow is too much for most schools. + */ export class ImportRunner { /** @@ -18,7 +22,6 @@ export class ImportRunner { /** * The new runner's middle name. - * Optional. */ @IsString() @IsOptional() @@ -32,18 +35,26 @@ export class ImportRunner { lastname: string; /** - * The new runner's class (if not provided otherwise). + * The new runner's team's name (if not provided otherwise). + * The team will automaticly get generated if it doesn't exist in this org yet. */ @IsString() @IsOptional() team?: string; + /** + * Just an alias for team, because this is usually only used for importing data from schools. + */ @IsOptional() @IsString() public set class(value: string) { this.team = value; } + /** + * Creates a CreateRunner object based on this. + * @param groupID Either the id of the new runner's group or the id of the org that the new runner's team is a part of. + */ public async toCreateRunner(groupID: number): Promise { let newRunner: CreateRunner = new CreateRunner(); @@ -55,25 +66,28 @@ export class ImportRunner { return newRunner; } + /** + * Get's the new runners group. + * @param groupID Either the id of the new runner's group or the id of the org that the new runner's team is a part of. + */ public async getGroup(groupID: number): Promise { if (this.team === undefined && groupID === undefined) { throw new RunnerGroupNeededError(); } - let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: groupID }); - if (team) { return team; } - - let org = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: groupID }); - if (!org) { + let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: groupID }); + if (group instanceof RunnerTeam) { return group; } + if (!(group instanceof RunnerOrganisation) || !group) { throw new RunnerOrganisationNotFoundError(); } - if (this.team === undefined) { return org; } - team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: org }); + if (this.team === undefined) { return group; } + + let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: org }); if (!team) { let newRunnerTeam: RunnerTeam = new RunnerTeam(); newRunnerTeam.name = this.team; - newRunnerTeam.parentGroup = org; + newRunnerTeam.parentGroup = group; team = await getConnectionManager().get().getRepository(RunnerTeam).save(newRunnerTeam); } diff --git a/src/models/actions/RefreshAuth.ts b/src/models/actions/RefreshAuth.ts index 963c83c..12470c7 100644 --- a/src/models/actions/RefreshAuth.ts +++ b/src/models/actions/RefreshAuth.ts @@ -7,11 +7,23 @@ import { JwtCreator } from "../../jwtcreator"; import { User } from '../entities/User'; import { Auth } from '../responses/ResponseAuth'; +/** + * This class is used to create refreshed auth credentials. + * To be a little bit more exact: Is takes in a refresh token and creates a new access and refresh token for it's user. + * It of course checks for user existance, jwt validity and so on. + */ export class RefreshAuth { + /** + * A stringyfied jwt refresh token. + * Will get checked for validity. + */ @IsString() @IsOptional() token?: string; + /** + * Creates a new auth object based on this. + */ public async toAuth(): Promise { let newAuth: Auth = new Auth(); if (!this.token || this.token === undefined) { diff --git a/src/models/actions/UpdatePermission.ts b/src/models/actions/UpdatePermission.ts index 8c31bbe..5241a1b 100644 --- a/src/models/actions/UpdatePermission.ts +++ b/src/models/actions/UpdatePermission.ts @@ -7,16 +7,21 @@ import { Principal } from '../entities/Principal'; import { PermissionAction } from '../enums/PermissionAction'; import { PermissionTarget } from '../enums/PermissionTargets'; +/** + * This class is used to update a Permission entity (via put request). + */ export class UpdatePermission { /** - * The updated runner's id. + * The updated permission'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 permissions's principal's id. + * The updated permissions's principal. + * Just has to contain the principal's id -everything else won't be checked or changed. */ @IsObject() @IsNotEmpty() @@ -35,7 +40,7 @@ export class UpdatePermission { action: PermissionAction; /** - * Converts a Permission object based on this. + * Updates a provided Permission entity based on this. */ public async updatePermission(permission: Permission): Promise { permission.principal = await this.getPrincipal(); @@ -46,7 +51,7 @@ export class UpdatePermission { } /** - * Manages all the different ways a group can be provided. + * Loads the updated permission's principal based on it's id. */ public async getPrincipal(): Promise { if (this.principal === undefined || this.principal === null) { diff --git a/src/models/actions/UpdateRunner.ts b/src/models/actions/UpdateRunner.ts index 62667ec..abc71e0 100644 --- a/src/models/actions/UpdateRunner.ts +++ b/src/models/actions/UpdateRunner.ts @@ -7,22 +7,27 @@ import { Runner } from '../entities/Runner'; import { RunnerGroup } from '../entities/RunnerGroup'; import { CreateParticipant } from './CreateParticipant'; +/** + * This class is used to update a Runner entity (via put request). + */ export class UpdateRunner extends CreateParticipant { /** * The updated runner'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 runner's new team/org. + * Just has to contain the group's id -everything else won't be checked or changed. */ @IsObject() group: RunnerGroup; /** - * Creates a Runner entity from this. + * Updates a provided Runner entity based on this. */ public async updateRunner(runner: Runner): Promise { runner.firstname = this.firstname; @@ -37,7 +42,7 @@ export class UpdateRunner extends CreateParticipant { } /** - * Manages all the different ways a group can be provided. + * Loads the updated runner's group based on it's id. */ public async getGroup(): Promise { if (this.group === undefined || this.group === null) { diff --git a/src/models/actions/UpdateRunnerOrganisation.ts b/src/models/actions/UpdateRunnerOrganisation.ts index 6917698..3a5b1fb 100644 --- a/src/models/actions/UpdateRunnerOrganisation.ts +++ b/src/models/actions/UpdateRunnerOrganisation.ts @@ -5,17 +5,21 @@ import { Address } from '../entities/Address'; import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { CreateRunnerGroup } from './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. - * Must be of type number (address id). + * Just has to contain the address's id - everything else won't be checked or changed. * Optional. */ @IsInt() @@ -23,7 +27,7 @@ export class UpdateRunnerOrganisation extends CreateRunnerGroup { address?: Address; /** - * Get's this org's address from this.address. + * Loads the organisation's address based on it's id. */ public async getAddress(): Promise
{ if (this.address === undefined || this.address === null) { @@ -35,7 +39,7 @@ export class UpdateRunnerOrganisation extends CreateRunnerGroup { } /** - * Creates a RunnerTeam entity from this. + * Updates a provided RunnerOrganisation entity based on this. */ public async updateRunnerOrganisation(organisation: RunnerOrganisation): Promise { diff --git a/src/models/actions/UpdateRunnerTeam.ts b/src/models/actions/UpdateRunnerTeam.ts index 62b71d5..756d7df 100644 --- a/src/models/actions/UpdateRunnerTeam.ts +++ b/src/models/actions/UpdateRunnerTeam.ts @@ -6,21 +6,29 @@ import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerTeam } from '../entities/RunnerTeam'; import { CreateRunnerGroup } from './CreateRunnerGroup'; +/** + * This class is used to update a RunnerTeam entity (via put request). + */ export class UpdateRunnerTeam extends CreateRunnerGroup { /** * The updated team'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 team's parent group (organisation). + * The updated team's parentGroup. + * Just has to contain the organisation's id - everything else won't be checked or changed. */ @IsObject() @IsNotEmpty() parentGroup: RunnerOrganisation; + /** + * Loads the updated teams's parentGroup based on it's id. + */ public async getParent(): Promise { if (this.parentGroup === undefined || this.parentGroup === null) { throw new RunnerTeamNeedsParentError(); @@ -35,7 +43,7 @@ export class UpdateRunnerTeam extends CreateRunnerGroup { } /** - * Creates a RunnerTeam entity from this. + * Updates a provided RunnerTeam entity based on this. */ public async updateRunnerTeam(team: RunnerTeam): Promise { diff --git a/src/models/actions/UpdateUser.ts b/src/models/actions/UpdateUser.ts index f91e7a5..626b096 100644 --- a/src/models/actions/UpdateUser.ts +++ b/src/models/actions/UpdateUser.ts @@ -7,10 +7,14 @@ import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; import { User } from '../entities/User'; import { UserGroup } from '../entities/UserGroup'; +/** + * This class is used to update a User entity (via put request). + */ export class UpdateUser { /** - * The updated users's id. + * The updated user'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; @@ -23,7 +27,6 @@ export class UpdateUser { /** * The updated user's middle name. - * Optinal. */ @IsString() @IsOptional() @@ -54,14 +57,16 @@ export class UpdateUser { /** * The updated user's phone number. - * Optional + * This will be validated against the configured country phone numer syntax (default: international). */ @IsPhoneNumber(config.phone_validation_countrycode) @IsOptional() phone?: string; /** - * The new updated's password. Only provide if you want it updated. + * The new updated's password. + * Only provide it if you want it updated. + * Changeing the password will invalidate all of the user's jwts. * This will of course not be saved in plaintext :) */ @IsString() @@ -75,15 +80,14 @@ export class UpdateUser { enabled: boolean = true; /** - * The new user's groups' id(s). - * You can provide either one groupId or an array of groupIDs. - * Optional. + * The updated user's groups. + * This just has to contain the group's id - everything else won't be changed. */ @IsOptional() groups?: UserGroup[] /** - * Creates a User entity from this. + * Updates a provided User entity based on this. */ public async updateUser(user: User): Promise { user.email = this.email; @@ -107,6 +111,9 @@ export class UpdateUser { return user; } + /** + * Loads the updated user's groups based on their ids. + */ public async getGroups() { if (!this.groups) { return null; } let groups = new Array(); From 48bef8db608032375705b27aecc4c9ae7b75f655 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 21 Dec 2020 16:21:12 +0100 Subject: [PATCH 30/32] Second part of the action comment refactoring ref #39 --- src/models/actions/CreateAddress.ts | 21 ++++++++++------- src/models/actions/CreateAuth.ts | 2 +- src/models/actions/CreateGroupContact.ts | 23 ++++++++++--------- src/models/actions/CreateParticipant.ts | 10 ++++---- src/models/actions/CreatePermission.ts | 15 +++++++----- src/models/actions/CreateRunner.ts | 7 ++++-- src/models/actions/CreateRunnerGroup.ts | 9 +++++--- .../actions/CreateRunnerOrganisation.ts | 8 ++++--- src/models/actions/CreateRunnerTeam.ts | 10 ++++++-- src/models/actions/CreateTrack.ts | 9 +++++--- src/models/actions/CreateUser.ts | 9 ++++---- src/models/actions/CreateUserGroup.ts | 5 +++- 12 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/models/actions/CreateAddress.ts b/src/models/actions/CreateAddress.ts index ef78410..e912ba2 100644 --- a/src/models/actions/CreateAddress.ts +++ b/src/models/actions/CreateAddress.ts @@ -1,16 +1,19 @@ import { IsNotEmpty, IsOptional, IsPostalCode, IsString } from 'class-validator'; import { Address } from '../entities/Address'; +/** + * This classed is used to create a new Address entity from a json body (post request). + */ export class CreateAddress { /** - * The address's description. - */ + * The newaddress's description. + */ @IsString() @IsOptional() description?: string; /** - * The address's first line. + * The new address's first line. * Containing the street and house number. */ @IsString() @@ -18,7 +21,7 @@ export class CreateAddress { address1: string; /** - * The address's second line. + * The new address's second line. * Containing optional information. */ @IsString() @@ -26,7 +29,9 @@ export class CreateAddress { address2?: string; /** - * The address's postal code. + * The new address's postal code. + * This will get checked against the postal code syntax for the configured country. + * TODO: Implement the config option. */ @IsString() @IsNotEmpty() @@ -34,21 +39,21 @@ export class CreateAddress { postalcode: string; /** - * The address's city. + * The new address's city. */ @IsString() @IsNotEmpty() city: string; /** - * The address's country. + * The new address's country. */ @IsString() @IsNotEmpty() country: string; /** - * Creates a Address object based on this. + * Creates a new Address entity from this. */ public toAddress(): Address { let newAddress: Address = new Address(); diff --git a/src/models/actions/CreateAuth.ts b/src/models/actions/CreateAuth.ts index 375cf2f..dd9c3f3 100644 --- a/src/models/actions/CreateAuth.ts +++ b/src/models/actions/CreateAuth.ts @@ -8,7 +8,7 @@ import { User } from '../entities/User'; import { Auth } from '../responses/ResponseAuth'; /** - * This class is used to create auth credentials. + * This class is used to create auth credentials based on user credentials provided in a json body (post request). * To be a little bit more exact: Is takes in a username/email + password and creates a new access and refresh token for the user. * It of course checks for user existance, password validity and so on. */ diff --git a/src/models/actions/CreateGroupContact.ts b/src/models/actions/CreateGroupContact.ts index 747f29d..915f897 100644 --- a/src/models/actions/CreateGroupContact.ts +++ b/src/models/actions/CreateGroupContact.ts @@ -5,32 +5,34 @@ import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/Addres import { Address } from '../entities/Address'; import { GroupContact } from '../entities/GroupContact'; +/** + * This classed is used to create a new Group entity from a json body (post request). + */ export class CreateGroupContact { /** - * The contact's first name. - */ + * The new contact's first name. + */ @IsNotEmpty() @IsString() firstname: string; /** - * The contact's middle name. - * Optional + * The new contact's middle name. */ @IsOptional() @IsString() middlename?: string; /** - * The contact's last name. + * The new contact's last name. */ @IsNotEmpty() @IsString() lastname: string; /** - * The contact's address. - * Optional + * The new contact's address. + * Must be the address's id. */ @IsInt() @IsOptional() @@ -38,7 +40,7 @@ export class CreateGroupContact { /** * The contact's phone number. - * Optional + * This will be validated against the configured country phone numer syntax (default: international). */ @IsOptional() @IsPhoneNumber(config.phone_validation_countrycode) @@ -46,14 +48,13 @@ export class CreateGroupContact { /** * The contact's email address. - * Optional */ @IsOptional() @IsEmail() email?: string; /** - * Get's this participant's address from this.address. + * Gets the new contact's address by it's id. */ public async getAddress(): Promise
{ if (this.address === undefined || this.address === null) { @@ -69,7 +70,7 @@ export class CreateGroupContact { } /** - * Creates a Address object based on this. + * Creates a new Address entity from this. */ public async toGroupContact(): Promise { let contact: GroupContact = new GroupContact(); diff --git a/src/models/actions/CreateParticipant.ts b/src/models/actions/CreateParticipant.ts index 49cba30..165bddb 100644 --- a/src/models/actions/CreateParticipant.ts +++ b/src/models/actions/CreateParticipant.ts @@ -4,6 +4,9 @@ import { config } from '../../config'; import { AddressNotFoundError, AddressWrongTypeError } from '../../errors/AddressErrors'; import { Address } from '../entities/Address'; +/** + * This classed is used to create a new Participant entity from a json body (post request). + */ export abstract class CreateParticipant { /** * The new participant's first name. @@ -14,7 +17,6 @@ export abstract class CreateParticipant { /** * The new participant's middle name. - * Optional. */ @IsString() @IsOptional() @@ -29,7 +31,7 @@ export abstract class CreateParticipant { /** * The new participant's phone number. - * Optional. + * This will be validated against the configured country phone numer syntax (default: international). */ @IsString() @IsOptional() @@ -38,7 +40,6 @@ export abstract class CreateParticipant { /** * The new participant's e-mail address. - * Optional. */ @IsString() @IsOptional() @@ -48,14 +49,13 @@ export abstract class CreateParticipant { /** * The new participant's address. * Must be of type number (address id). - * Optional. */ @IsInt() @IsOptional() address?: number; /** - * Get's this participant's address from this.address. + * Gets the new participant's address by it's address. */ public async getAddress(): Promise
{ if (this.address === undefined || this.address === null) { diff --git a/src/models/actions/CreatePermission.ts b/src/models/actions/CreatePermission.ts index 7a49e03..5ee9582 100644 --- a/src/models/actions/CreatePermission.ts +++ b/src/models/actions/CreatePermission.ts @@ -11,33 +11,33 @@ import { PermissionAction } from '../enums/PermissionAction'; import { PermissionTarget } from '../enums/PermissionTargets'; /** - * Defines a track of given length. -*/ + * This classed is used to create a new Permission entity from a json body (post request). + */ export class CreatePermission { /** - * The permissions's principal's id. + * The new permissions's principal's id. */ @IsInt() @IsNotEmpty() principal: number; /** - * The permissions's target. + * The new permissions's target. */ @IsNotEmpty() @IsEnum(PermissionTarget) target: PermissionTarget; /** - * The permissions's action. + * The new permissions's action. */ @IsNotEmpty() @IsEnum(PermissionAction) action: PermissionAction; /** - * Converts a Permission object based on this. + * Creates a new Permission entity from this. */ public async toPermission(): Promise { let newPermission: Permission = new Permission(); @@ -49,6 +49,9 @@ export class CreatePermission { return newPermission; } + /** + * Gets the new permission's principal by it's id. + */ public async getPrincipal(): Promise { let principal = await getConnectionManager().get().getRepository(Principal).findOne({ id: this.principal }) if (!principal) { throw new PrincipalNotFoundError(); } diff --git a/src/models/actions/CreateRunner.ts b/src/models/actions/CreateRunner.ts index 28ccaae..ab2cc1f 100644 --- a/src/models/actions/CreateRunner.ts +++ b/src/models/actions/CreateRunner.ts @@ -7,6 +7,9 @@ import { Runner } from '../entities/Runner'; import { RunnerGroup } from '../entities/RunnerGroup'; import { CreateParticipant } from './CreateParticipant'; +/** + * This classed is used to create a new Runner entity from a json body (post request). + */ export class CreateRunner extends CreateParticipant { /** @@ -16,7 +19,7 @@ export class CreateRunner extends CreateParticipant { group: number; /** - * Creates a Runner entity from this. + * Creates a new Runner entity from this. */ public async toRunner(): Promise { let newRunner: Runner = new Runner(); @@ -33,7 +36,7 @@ export class CreateRunner extends CreateParticipant { } /** - * Manages all the different ways a group can be provided. + * Gets the new runner's group by it's id. */ public async getGroup(): Promise { if (this.group === undefined || this.group === null) { diff --git a/src/models/actions/CreateRunnerGroup.ts b/src/models/actions/CreateRunnerGroup.ts index f237f40..9f4c803 100644 --- a/src/models/actions/CreateRunnerGroup.ts +++ b/src/models/actions/CreateRunnerGroup.ts @@ -3,16 +3,19 @@ import { getConnectionManager } from 'typeorm'; import { GroupContactNotFoundError, GroupContactWrongTypeError } from '../../errors/GroupContactErrors'; import { GroupContact } from '../entities/GroupContact'; +/** + * This classed is used to create a new RunnerGroup entity from a json body (post request). + */ export abstract class CreateRunnerGroup { /** - * The group's name. + * The new group's name. */ @IsNotEmpty() @IsString() name: string; /** - * The group's contact. + * The new group's contact. * Optional */ @IsInt() @@ -20,7 +23,7 @@ export abstract class CreateRunnerGroup { contact?: number; /** - * Get's this group's contact from this.address. + * Gets the new group's contact by it's id. */ public async getContact(): Promise { if (this.contact === undefined || this.contact === null) { diff --git a/src/models/actions/CreateRunnerOrganisation.ts b/src/models/actions/CreateRunnerOrganisation.ts index ffef4a3..017675e 100644 --- a/src/models/actions/CreateRunnerOrganisation.ts +++ b/src/models/actions/CreateRunnerOrganisation.ts @@ -5,18 +5,20 @@ 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. * Must be of type number (address id). - * Optional. */ @IsInt() @IsOptional() address?: number; /** - * Get's this org's address from this.address. + * Gets the org's address by it's id. */ public async getAddress(): Promise
{ if (this.address === undefined || this.address === null) { @@ -32,7 +34,7 @@ export class CreateRunnerOrganisation extends CreateRunnerGroup { } /** - * Creates a RunnerOrganisation entity from this. + * Creates a new RunnerOrganisation entity from this. */ public async toRunnerOrganisation(): Promise { let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation(); diff --git a/src/models/actions/CreateRunnerTeam.ts b/src/models/actions/CreateRunnerTeam.ts index 0a6f992..30a27b3 100644 --- a/src/models/actions/CreateRunnerTeam.ts +++ b/src/models/actions/CreateRunnerTeam.ts @@ -6,15 +6,21 @@ import { RunnerOrganisation } from '../entities/RunnerOrganisation'; import { RunnerTeam } from '../entities/RunnerTeam'; import { CreateRunnerGroup } from './CreateRunnerGroup'; +/** + * This classed is used to create a new RunnerTeam entity from a json body (post request). + */ export class CreateRunnerTeam extends CreateRunnerGroup { /** - * The team's parent group (organisation). + * The new team's parent group (organisation). */ @IsInt() @IsNotEmpty() parentGroup: number; + /** + * Gets the new team's parent org based on it's id. + */ public async getParent(): Promise { if (this.parentGroup === undefined || this.parentGroup === null) { throw new RunnerTeamNeedsParentError(); @@ -29,7 +35,7 @@ export class CreateRunnerTeam extends CreateRunnerGroup { } /** - * Creates a RunnerTeam entity from this. + * Creates a new RunnerTeam entity from this. */ public async toRunnerTeam(): Promise { let newRunnerTeam: RunnerTeam = new RunnerTeam(); diff --git a/src/models/actions/CreateTrack.ts b/src/models/actions/CreateTrack.ts index 9994094..f04e55b 100644 --- a/src/models/actions/CreateTrack.ts +++ b/src/models/actions/CreateTrack.ts @@ -1,23 +1,26 @@ import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; import { Track } from '../entities/Track'; +/** + * This classed is used to create a new Track entity from a json body (post request). + */ export class CreateTrack { /** - * The track's name. + * The new track's name. */ @IsString() @IsNotEmpty() name: string; /** - * The track's distance in meters (must be greater than 0). + * The new track's distance in meters (must be greater than 0). */ @IsInt() @IsPositive() distance: number; /** - * Converts a Track object based on this. + * Creates a new Track entity from this. */ public toTrack(): Track { let newTrack: Track = new Track(); diff --git a/src/models/actions/CreateUser.ts b/src/models/actions/CreateUser.ts index 041bd8e..3839f11 100644 --- a/src/models/actions/CreateUser.ts +++ b/src/models/actions/CreateUser.ts @@ -8,6 +8,9 @@ import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; import { User } from '../entities/User'; import { UserGroup } from '../entities/UserGroup'; +/** + * This classed is used to create a new User entity from a json body (post request). + */ export class CreateUser { /** * The new user's first name. @@ -17,7 +20,6 @@ export class CreateUser { /** * The new user's middle name. - * Optinal. */ @IsString() @IsOptional() @@ -48,7 +50,7 @@ export class CreateUser { /** * The new user's phone number. - * Optional + * This will be validated against the configured country phone numer syntax (default: international). */ @IsPhoneNumber(config.phone_validation_countrycode) @IsOptional() @@ -64,7 +66,6 @@ export class CreateUser { /** * The new user's groups' id(s). * You can provide either one groupId or an array of groupIDs. - * Optional. */ @IsOptional() groups?: number[] | number @@ -72,7 +73,7 @@ export class CreateUser { //TODO: ProfilePics /** - * Converts this to a User Entity. + * Converts this to a User entity. */ public async toUser(): Promise { let newUser: User = new User(); diff --git a/src/models/actions/CreateUserGroup.ts b/src/models/actions/CreateUserGroup.ts index 959bea5..50ad15d 100644 --- a/src/models/actions/CreateUserGroup.ts +++ b/src/models/actions/CreateUserGroup.ts @@ -1,6 +1,9 @@ import { IsOptional, IsString } from 'class-validator'; import { UserGroup } from '../entities/UserGroup'; +/** + * This classed is used to create a new UserGroup entity from a json body (post request). + */ export class CreateUserGroup { /** * The new group's name. @@ -17,7 +20,7 @@ export class CreateUserGroup { description?: string; /** - * Converts this to a UserGroup entity. + * Creates a new UserGroup entity from this. */ public async toUserGroup(): Promise { let newUserGroup: UserGroup = new UserGroup(); From 0ef6d9cc4865a5eebd9458cdd51f8aff9f3590d2 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 21 Dec 2020 16:58:51 +0100 Subject: [PATCH 31/32] Small bugfix ref #39 --- src/models/actions/ImportRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/actions/ImportRunner.ts b/src/models/actions/ImportRunner.ts index b1da7f7..11cac35 100644 --- a/src/models/actions/ImportRunner.ts +++ b/src/models/actions/ImportRunner.ts @@ -83,7 +83,7 @@ export class ImportRunner { if (this.team === undefined) { return group; } - let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: org }); + let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: group }); if (!team) { let newRunnerTeam: RunnerTeam = new RunnerTeam(); newRunnerTeam.name = this.team; From 7d5f3b092f72de6cf97ee35735ece35c554ddc6d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 21 Dec 2020 17:22:07 +0100 Subject: [PATCH 32/32] Reverted simplification that created loops ref #39 --- src/models/actions/ImportRunner.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/models/actions/ImportRunner.ts b/src/models/actions/ImportRunner.ts index 11cac35..3155b0e 100644 --- a/src/models/actions/ImportRunner.ts +++ b/src/models/actions/ImportRunner.ts @@ -75,19 +75,20 @@ export class ImportRunner { throw new RunnerGroupNeededError(); } - let group = await getConnectionManager().get().getRepository(RunnerGroup).findOne({ id: groupID }); - if (group instanceof RunnerTeam) { return group; } - if (!(group instanceof RunnerOrganisation) || !group) { + let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: groupID }); + if (team) { return team; } + + let org = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: groupID }); + if (!org) { throw new RunnerOrganisationNotFoundError(); } + if (this.team === undefined) { return org; } - if (this.team === undefined) { return group; } - - let team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: group }); + team = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ name: this.team, parentGroup: org }); if (!team) { let newRunnerTeam: RunnerTeam = new RunnerTeam(); newRunnerTeam.name = this.team; - newRunnerTeam.parentGroup = group; + newRunnerTeam.parentGroup = org; team = await getConnectionManager().get().getRepository(RunnerTeam).save(newRunnerTeam); }