Merge branch 'dev' into feature/6-documentation
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -136,4 +136,5 @@ build
 | 
			
		||||
/docs
 | 
			
		||||
lib
 | 
			
		||||
/oss-attribution
 | 
			
		||||
*.tmp
 | 
			
		||||
*.tmp
 | 
			
		||||
*.pdf
 | 
			
		||||
@@ -45,6 +45,7 @@
 | 
			
		||||
    "cors": "^2.8.5",
 | 
			
		||||
    "dotenv": "^8.2.0",
 | 
			
		||||
    "express": "^4.17.1",
 | 
			
		||||
    "html-pdf": "^2.2.0",
 | 
			
		||||
    "reflect-metadata": "^0.1.13",
 | 
			
		||||
    "routing-controllers": "^0.9.0-alpha.6",
 | 
			
		||||
    "routing-controllers-openapi": "^2.2.0"
 | 
			
		||||
@@ -72,4 +73,4 @@
 | 
			
		||||
      "publish": false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								src/PdfCreator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/PdfCreator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
import fs from "fs";
 | 
			
		||||
import pdf_converter from "html-pdf";
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import { Stream } from 'stream';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is responsible for all things pdf creation.
 | 
			
		||||
 * This uses the html templates from src/templates.
 | 
			
		||||
 */
 | 
			
		||||
export class PdfCreator {
 | 
			
		||||
    private templateDir = path.join(__dirname, '/templates');
 | 
			
		||||
 | 
			
		||||
    //TODO: Accept the runner class
 | 
			
		||||
    public async generateSponsoringContract(): Promise<Pdf> {
 | 
			
		||||
        let template = fs.readFileSync(`${this.templateDir}/sponsoring_contract.html`, 'utf8');
 | 
			
		||||
        template = template.replace("{{Runner Name}}", "lelele");
 | 
			
		||||
        return new Pdf(await pdf_converter.create(template, { format: "A5", orientation: "landscape" }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class is a wrapper for the pdf objects created by html-pdf.
 | 
			
		||||
 * It offers typed conversion to Buffer and Stream.
 | 
			
		||||
 */
 | 
			
		||||
export class Pdf {
 | 
			
		||||
    content: any;
 | 
			
		||||
 | 
			
		||||
    constructor(pdf: any) {
 | 
			
		||||
        this.content = pdf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Promise wrapper function that resolves the toBuffer promise for pdf generation.
 | 
			
		||||
     */
 | 
			
		||||
    public async toBuffer(): Promise<Buffer> {
 | 
			
		||||
        let promise = await new Promise<Buffer>((resolve, reject) => {
 | 
			
		||||
            this.content.toBuffer(function (err, buffer: Buffer) {
 | 
			
		||||
                resolve(buffer);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        return await promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Promise wrapper function that resolves the toStream promise for pdf generation.
 | 
			
		||||
     */
 | 
			
		||||
    public async toStream(): Promise<Stream> {
 | 
			
		||||
        let promise = await new Promise<Stream>((resolve, reject) => {
 | 
			
		||||
            this.content.toStream(function (err, stream: Stream) {
 | 
			
		||||
                resolve(stream);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        return await promise;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/controllers/PdfController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/controllers/PdfController.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import { ContentType, Controller, Get } from 'routing-controllers';
 | 
			
		||||
import { OpenAPI } from 'routing-controllers-openapi';
 | 
			
		||||
import { PdfCreator } from '../PdfCreator';
 | 
			
		||||
 | 
			
		||||
@Controller()
 | 
			
		||||
export class PdfController {
 | 
			
		||||
    private pdf: PdfCreator;
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.pdf = new PdfCreator();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Get('/contracts')
 | 
			
		||||
    @ContentType("application/pdf")
 | 
			
		||||
    @OpenAPI({ description: "Generate Sponsoring contract pdfs from runner objects." })
 | 
			
		||||
    async generateContracts() {
 | 
			
		||||
        //TODO: Accept the real classes
 | 
			
		||||
        const contracts = await this.pdf.generateSponsoringContract();
 | 
			
		||||
        return await contracts.toBuffer();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								src/errors/AddressErrors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/errors/AddressErrors.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								src/models/Address.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/models/Address.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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(); }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/models/CertificateRunner.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/models/CertificateRunner.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
import {
 | 
			
		||||
    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 {
 | 
			
		||||
    /**
 | 
			
		||||
     * Array containing all distance donations associated with the runner.
 | 
			
		||||
     */
 | 
			
		||||
    @IsArray()
 | 
			
		||||
    distanceDonations: DistanceDonation[];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/models/DistanceDonation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/models/DistanceDonation.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/models/Donation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/models/Donation.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/models/Donor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/models/Donor.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/models/FixedDonation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/models/FixedDonation.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/models/Runner.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/models/Runner.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
import {
 | 
			
		||||
    IsInt,
 | 
			
		||||
    IsObject,
 | 
			
		||||
    IsString
 | 
			
		||||
} from "class-validator";
 | 
			
		||||
import { RunnerGroup } from './RunnerGroup';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Defines the runner class (from which the runner sponsoring contracts get generated).
 | 
			
		||||
*/
 | 
			
		||||
export class Runner {
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.
 | 
			
		||||
     */
 | 
			
		||||
    @IsObject()
 | 
			
		||||
    group: RunnerGroup;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The total distance ran by the runner.
 | 
			
		||||
     */
 | 
			
		||||
    @IsInt()
 | 
			
		||||
    distance: number;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								src/models/RunnerCard.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/models/RunnerCard.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
import {
 | 
			
		||||
    IsEAN,
 | 
			
		||||
    IsInt,
 | 
			
		||||
    IsNotEmpty,
 | 
			
		||||
    IsObject,
 | 
			
		||||
    IsString
 | 
			
		||||
} from "class-validator";
 | 
			
		||||
import { Runner } from './Runner';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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: Runner | null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The card's code.
 | 
			
		||||
     */
 | 
			
		||||
    @IsEAN()
 | 
			
		||||
    @IsString()
 | 
			
		||||
    @IsNotEmpty()
 | 
			
		||||
    code: string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								src/models/RunnerGroup.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/models/RunnerGroup.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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}`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								src/templates/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/templates/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										45
									
								
								src/templates/sponsoring_contract.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/templates/sponsoring_contract.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
<html>
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="utf8">
 | 
			
		||||
    <title>Sponsoring contract</title>
 | 
			
		||||
    <style>
 | 
			
		||||
      html, body {
 | 
			
		||||
        margin: 0;
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        font-family: 'Sackers Gothic Std';
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        background: rgb(241,241,241);
 | 
			
		||||
        -webkit-print-color-adjust: exact;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .page {
 | 
			
		||||
        position: relative;
 | 
			
		||||
        height: 148mm;
 | 
			
		||||
        width: 210mm;
 | 
			
		||||
        display: block;
 | 
			
		||||
        background: white;
 | 
			
		||||
        page-break-after: auto;
 | 
			
		||||
        margin: 50px;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @media print {
 | 
			
		||||
        body {
 | 
			
		||||
          background: white;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .page {
 | 
			
		||||
          margin: 0;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          width: 100%;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    </style>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <div class="page">
 | 
			
		||||
      <p style="font-size: 100vw;">{{Runner Name}}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user