From d291cf0d1bf375e96fda822543d5ceb29dc67010 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 30 Jan 2021 18:32:01 +0100 Subject: [PATCH 1/9] Added address class and errors ref #1 --- src/errors/AddressErrors.ts | 57 ++++++++++++++++++++++++++ src/models/Address.ts | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/errors/AddressErrors.ts create mode 100644 src/models/Address.ts diff --git a/src/errors/AddressErrors.ts b/src/errors/AddressErrors.ts new file mode 100644 index 0000000..300bb31 --- /dev/null +++ b/src/errors/AddressErrors.ts @@ -0,0 +1,57 @@ +import { IsString } from 'class-validator'; +import { BadRequestError } from 'routing-controllers'; + +/** + * Error to throw when an address's postal code fails validation. + */ +export class AddressPostalCodeInvalidError extends BadRequestError { + @IsString() + name = "AddressPostalCodeInvalidError" + + @IsString() + message = "The postal code you provided is invalid. \n Please check if your postal code follows the postal code validation guidelines." +} + +/** + * Error to throw when an non-empty address's first line isn't set. + */ +export class AddressFirstLineEmptyError extends BadRequestError { + @IsString() + name = "AddressFirstLineEmptyError" + + @IsString() + message = "You provided a empty first address line. \n If you want an empty address please set all propertys to null. \n For non-empty addresses the following fields have to be set: address1, postalcode, city, country" +} + +/** + * Error to throw when an non-empty address's postal code isn't set. + */ +export class AddressPostalCodeEmptyError extends BadRequestError { + @IsString() + name = "AddressPostalCodeEmptyError" + + @IsString() + message = "You provided a empty postal code. \n If you want an empty address please set all propertys to null. \n For non-empty addresses the following fields have to be set: address1, postalcode, city, country" +} + +/** + * Error to throw when an non-empty address's city isn't set. + */ +export class AddressCityEmptyError extends BadRequestError { + @IsString() + name = "AddressCityEmptyError" + + @IsString() + message = "You provided a empty city. \n If you want an empty address please set all propertys to null. \n For non-empty addresses the following fields have to be set: address1, postalcode, city, country" +} + +/** + * Error to throw when an non-empty address's country isn't set. + */ +export class AddressCountryEmptyError extends BadRequestError { + @IsString() + name = "AddressCountryEmptyError" + + @IsString() + message = "You provided a empty country. \n If you want an empty address please set all propertys to null. \n For non-empty addresses the following fields have to be set: address1, postalcode, city, country" +} \ No newline at end of file diff --git a/src/models/Address.ts b/src/models/Address.ts new file mode 100644 index 0000000..dc66f10 --- /dev/null +++ b/src/models/Address.ts @@ -0,0 +1,80 @@ +import { + IsPostalCode, + IsString +} from "class-validator"; +import ValidatorJS from 'validator'; +import { config } from '../../config'; +import { AddressCityEmptyError, AddressCountryEmptyError, AddressFirstLineEmptyError, AddressPostalCodeEmptyError, AddressPostalCodeInvalidError } from '../../errors/AddressErrors'; + +/** + * Defines the Address class. + * Implemented this way to prevent any formatting differences. +*/ +export class Address { + /** + * The address's first line. + * Containing the street and house number. + */ + @IsString() + address1?: string; + + /** + * The address's second line. + * Containing optional information. + */ + @IsString() + address2?: string; + + /** + * The address's postal code. + * This will get checked against the postal code syntax for the configured country. + */ + @IsString() + @IsPostalCode(config.postalcode_validation_countrycode) + postalcode: string; + + /** + * The address's city. + */ + @IsString() + city: string; + + /** + * The address's country. + */ + @IsString() + country: string; + + public reset() { + this.address1 = null; + this.address2 = null; + this.city = null; + this.country = null; + this.postalcode = null; + } + + /** + * Checks if this is a valid address + */ + public static isValidAddress(address: Address): Boolean { + if (address == null) { return false; } + if (address.address1 == null || address.city == null || address.country == null || address.postalcode == null) { return false; } + if (ValidatorJS.isPostalCode(address.postalcode, config.postalcode_validation_countrycode) == false) { return false; } + return true; + } + + /** + * This function validates addresses. + * This is a workaround for non-existant class validation for embedded entities. + * @param address The address that shall get validated. + */ + public static validate(address: Address) { + if (address == null) { return; } + if (address.address1 == null && address.city == null && address.country == null && address.postalcode == null) { return; } + if (address.address1 == null) { throw new AddressFirstLineEmptyError(); } + if (address.postalcode == null) { throw new AddressPostalCodeEmptyError(); } + if (address.city == null) { throw new AddressCityEmptyError(); } + if (address.country == null) { throw new AddressCountryEmptyError(); } + if (ValidatorJS.isPostalCode(address.postalcode.toString(), config.postalcode_validation_countrycode) == false) { throw new AddressPostalCodeInvalidError(); } + } +} From 63f952376698c3561754bfb206a64c58c1ae86f1 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 30 Jan 2021 18:32:28 +0100 Subject: [PATCH 2/9] Added input class for contract generation ref #1 --- src/models/ContractRunner.ts | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/models/ContractRunner.ts diff --git a/src/models/ContractRunner.ts b/src/models/ContractRunner.ts new file mode 100644 index 0000000..eda52f7 --- /dev/null +++ b/src/models/ContractRunner.ts @@ -0,0 +1,39 @@ +import { + IsInt, + IsString +} from "class-validator"; + +/** + * Defines the contract runner class (from which the runner sponsoring contracts get generated). +*/ +export class ContractRunner { + /** + * The runner's id. + */ + @IsInt() + id: number; + + /** + * The runner's first name. + */ + @IsString() + firstname: string; + + /** + * The runner's middle name. + */ + @IsString() + middlename?: string; + + /** + * The runner's last name. + */ + @IsString() + lastname: string; + + /** + * The runner's group. + */ + @IsString() + group: string; +} From e29c17a29a6ee84944f8d67d7b6f3c4292763c10 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 08:49:18 +0100 Subject: [PATCH 3/9] Added a simplified runnergroup class ref #1 --- src/models/RunnerGroup.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/models/RunnerGroup.ts diff --git a/src/models/RunnerGroup.ts b/src/models/RunnerGroup.ts new file mode 100644 index 0000000..f50a179 --- /dev/null +++ b/src/models/RunnerGroup.ts @@ -0,0 +1,36 @@ +import { IsInt, IsNotEmpty, IsObject, IsOptional, IsString } from "class-validator"; + +/** + * Defines the runner group class - a simplified version of the backend's ResponseRunnerTeam/-Organization +*/ +export abstract class RunnerGroup { + /** + * The group's id. + */ + @IsInt() + @IsNotEmpty() + id: number;; + + /** + * The group's name. + */ + @IsString() + @IsNotEmpty() + name: string; + + /** + * The group's parent group. + * If it is set this implies that the object is a team. + */ + @IsObject() + @IsOptional() + parentGroup?: RunnerGroup + + /** + * Returns the groups full name in the format: org.name/team.name (or just org). + */ + public get fullName(): string { + if (!this.parentGroup) { return this.name; } + return `${this.name}/${this.parentGroup.fullName}`; + } +} From cb7325bbf906b405955bd81e199abae5edc27d91 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 08:49:41 +0100 Subject: [PATCH 4/9] Added a runnercard class ref #1 --- src/models/RunnerCard.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/models/RunnerCard.ts diff --git a/src/models/RunnerCard.ts b/src/models/RunnerCard.ts new file mode 100644 index 0000000..89f2687 --- /dev/null +++ b/src/models/RunnerCard.ts @@ -0,0 +1,33 @@ +import { + IsEAN, + IsInt, + IsNotEmpty, + IsObject, + IsString +} from "class-validator"; +import { ContractRunner } from './ContractRunner'; + +/** + * Defines the runner card class (used to create runner card pdfs). +*/ +export class RunnerCard { + /** + * The cards's id. + */ + @IsInt() + id: number; + + /** + * The card's associated runner. + */ + @IsObject() + runner: ContractRunner | null; + + /** + * The card's code. + */ + @IsEAN() + @IsString() + @IsNotEmpty() + code: string; +} From aae4f507eafbfd51cd9972cf0fac4c5afafbb45a Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 08:50:31 +0100 Subject: [PATCH 5/9] Runners now use the runnergroup class instead of strings ref #1 --- src/models/{ContractRunner.ts => Runner.ts} | 8 +++++--- src/models/RunnerCard.ts | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) rename src/models/{ContractRunner.ts => Runner.ts} (81%) diff --git a/src/models/ContractRunner.ts b/src/models/Runner.ts similarity index 81% rename from src/models/ContractRunner.ts rename to src/models/Runner.ts index eda52f7..fec6235 100644 --- a/src/models/ContractRunner.ts +++ b/src/models/Runner.ts @@ -1,12 +1,14 @@ import { IsInt, + IsObject, IsString } from "class-validator"; +import { RunnerGroup } from './RunnerGroup'; /** * Defines the contract runner class (from which the runner sponsoring contracts get generated). */ -export class ContractRunner { +export class Runner { /** * The runner's id. */ @@ -34,6 +36,6 @@ export class ContractRunner { /** * The runner's group. */ - @IsString() - group: string; + @IsObject() + group: RunnerGroup; } diff --git a/src/models/RunnerCard.ts b/src/models/RunnerCard.ts index 89f2687..3a4cffb 100644 --- a/src/models/RunnerCard.ts +++ b/src/models/RunnerCard.ts @@ -5,7 +5,7 @@ import { IsObject, IsString } from "class-validator"; -import { ContractRunner } from './ContractRunner'; +import { Runner } from './Runner'; /** * Defines the runner card class (used to create runner card pdfs). @@ -21,7 +21,7 @@ export class RunnerCard { * The card's associated runner. */ @IsObject() - runner: ContractRunner | null; + runner: Runner | null; /** * The card's code. From d08bdfd961f4128981b969cf149df7397a257193 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 08:59:30 +0100 Subject: [PATCH 6/9] Added a certificaterunner class ref #1 --- src/models/CertificateRunner.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/models/CertificateRunner.ts diff --git a/src/models/CertificateRunner.ts b/src/models/CertificateRunner.ts new file mode 100644 index 0000000..937536e --- /dev/null +++ b/src/models/CertificateRunner.ts @@ -0,0 +1,23 @@ +import { + IsArray, + IsInt +} from "class-validator"; +import { Runner } from './Runner'; + +/** + * Defines the certificate runner class (from which the runner certificates get generated). +*/ +export class CertificateRunner extends Runner { + + /** + * The total distance ran by the runner. + */ + @IsInt() + distance: number; + + /** + * Array containing all distance donations associated with the runner. + */ + @IsArray() + distanceDonations: any[]; +} From 1d1fa50327927328ce77af33c1abbf994df9ac8b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 09:05:02 +0100 Subject: [PATCH 7/9] Moved distance to the main runner object ref #1 --- src/models/CertificateRunner.ts | 13 +++---------- src/models/Runner.ts | 6 ++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/models/CertificateRunner.ts b/src/models/CertificateRunner.ts index 937536e..a30b356 100644 --- a/src/models/CertificateRunner.ts +++ b/src/models/CertificateRunner.ts @@ -1,23 +1,16 @@ import { - IsArray, - IsInt + IsArray } from "class-validator"; +import { DistanceDonation } from './DistanceDonation'; import { Runner } from './Runner'; /** * Defines the certificate runner class (from which the runner certificates get generated). */ export class CertificateRunner extends Runner { - - /** - * The total distance ran by the runner. - */ - @IsInt() - distance: number; - /** * Array containing all distance donations associated with the runner. */ @IsArray() - distanceDonations: any[]; + distanceDonations: DistanceDonation[]; } diff --git a/src/models/Runner.ts b/src/models/Runner.ts index fec6235..826941a 100644 --- a/src/models/Runner.ts +++ b/src/models/Runner.ts @@ -38,4 +38,10 @@ export class Runner { */ @IsObject() group: RunnerGroup; + + /** + * The total distance ran by the runner. + */ + @IsInt() + distance: number; } From 1d73e4ed9ccb3dfb7709cb89957ed5bbcefad870 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 09:05:21 +0100 Subject: [PATCH 8/9] Added the donation classes ref #1 --- src/models/DistanceDonation.ts | 40 ++++++++++++++++++++++++++++++++++ src/models/Donation.ts | 32 +++++++++++++++++++++++++++ src/models/FixedDonation.ts | 16 ++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/models/DistanceDonation.ts create mode 100644 src/models/Donation.ts create mode 100644 src/models/FixedDonation.ts diff --git a/src/models/DistanceDonation.ts b/src/models/DistanceDonation.ts new file mode 100644 index 0000000..a4e35e1 --- /dev/null +++ b/src/models/DistanceDonation.ts @@ -0,0 +1,40 @@ +import { IsInt, IsNotEmpty, IsObject, IsPositive } from "class-validator"; +import { Donation } from "./Donation"; +import { Runner } from "./Runner"; + +/** + * Defines the DistanceDonation class. + * For distanceDonations a donor pledges to donate a certain amount for each kilometer ran by a runner. +*/ +export class DistanceDonation extends Donation { + /** + * The donation's associated runner. + * Used as the source of the donation's distance. + */ + @IsObject() + @IsNotEmpty() + runner: Runner; + + /** + * The donation's amount donated per distance. + * The amount the donor set to be donated per kilometer that the runner ran. + */ + @IsInt() + @IsPositive() + amountPerDistance: number; + + /** + * The donation's amount in cents (or whatever your currency's smallest unit is.). + * Get's calculated from the runner's distance ran and the amount donated per kilometer. + */ + public get amount(): number { + let calculatedAmount = 0; + try { + calculatedAmount = this.amountPerDistance * (this.runner.distance / 1000); + } catch (error) { + throw error; + } + return calculatedAmount; + } + +} diff --git a/src/models/Donation.ts b/src/models/Donation.ts new file mode 100644 index 0000000..1beaf0c --- /dev/null +++ b/src/models/Donation.ts @@ -0,0 +1,32 @@ +import { + IsInt, + IsNotEmpty, + IsObject +} from "class-validator"; +import { Donor } from './Donor'; + +/** + * Defines the Donation base calss. + * A donation just associates a donor with a donation amount. + * The specifics of the amoun's determination has to be implemented in child classes. +*/ +export abstract class Donation { + /** + * Autogenerated unique id (primary key). + */ + @IsInt() + id: number; + + /** + * The donations's donor. + */ + @IsNotEmpty() + @IsObject() + donor: Donor; + + /** + * The donation's amount in cents (or whatever your currency's smallest unit is.). + * The exact implementation may differ for each type of donation. + */ + public abstract get amount(): number; +} \ No newline at end of file diff --git a/src/models/FixedDonation.ts b/src/models/FixedDonation.ts new file mode 100644 index 0000000..18c8a23 --- /dev/null +++ b/src/models/FixedDonation.ts @@ -0,0 +1,16 @@ +import { IsInt, IsPositive } from "class-validator"; +import { Donation } from "./Donation"; + +/** + * Defines the FixedDonation entity. + * In the past there was no easy way to track fixed donations (eg. for creating donation receipts). +*/ +export class FixedDonation extends Donation { + + /** + * The donation's amount in cents (or whatever your currency's smallest unit is.). + */ + @IsInt() + @IsPositive() + amount: number; +} \ No newline at end of file From cfa65e83cafcefbd6261a99ab7a4eaf099665a81 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 2 Feb 2021 09:09:10 +0100 Subject: [PATCH 9/9] Added a basic donor class ref #1 --- src/models/Donor.ts | 37 +++++++++++++++++++++++++++++++++++++ src/models/Runner.ts | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/models/Donor.ts diff --git a/src/models/Donor.ts b/src/models/Donor.ts new file mode 100644 index 0000000..cb9d9df --- /dev/null +++ b/src/models/Donor.ts @@ -0,0 +1,37 @@ +import { + + IsInt, + + + + IsString +} from "class-validator"; + +/** + * Defines the Donor class. +*/ +export class Donor { + /** + * The donor's id. + */ + @IsInt() + id: number; + + /** + * The donor's first name. + */ + @IsString() + firstname: string; + + /** + * The donor's middle name. + */ + @IsString() + middlename?: string; + + /** + * The donor's last name. + */ + @IsString() + lastname: string; +} diff --git a/src/models/Runner.ts b/src/models/Runner.ts index 826941a..f7968a8 100644 --- a/src/models/Runner.ts +++ b/src/models/Runner.ts @@ -6,7 +6,7 @@ import { import { RunnerGroup } from './RunnerGroup'; /** - * Defines the contract runner class (from which the runner sponsoring contracts get generated). + * Defines the runner class (from which the runner sponsoring contracts get generated). */ export class Runner { /**