First part of the action comment refactoring

ref #39
Why did i volunteer for this? It's just a glorified sleeping aid 😴
This commit is contained in:
Nicolai Ort 2020-12-21 16:08:10 +01:00
parent d20d738218
commit 1d0d79f3da
9 changed files with 123 additions and 32 deletions

View File

@ -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<Auth> {
let newAuth: Auth = new Auth();

View File

@ -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<Logout> {
let logout: Logout = new Logout();
if (!this.token || this.token === undefined) {

View File

@ -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<CreateRunner> {
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<RunnerGroup> {
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);
}

View File

@ -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<Auth> {
let newAuth: Auth = new Auth();
if (!this.token || this.token === undefined) {

View File

@ -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> {
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<Principal> {
if (this.principal === undefined || this.principal === null) {

View File

@ -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> {
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<RunnerGroup> {
if (this.group === undefined || this.group === null) {

View File

@ -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<Address> {
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<RunnerOrganisation> {

View File

@ -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<RunnerOrganisation> {
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<RunnerTeam> {

View File

@ -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> {
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<UserGroup>();