Merge branch 'dev' into feature/79-profile_pics
Some checks failed
continuous-integration/drone/pr Build is failing
Some checks failed
continuous-integration/drone/pr Build is failing
This commit is contained in:
59
src/models/actions/CreateScan.ts
Normal file
59
src/models/actions/CreateScan.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { IsBoolean, IsInt, IsOptional, IsPositive } from 'class-validator';
|
||||
import { getConnection } from 'typeorm';
|
||||
import { RunnerNotFoundError } from '../../errors/RunnerErrors';
|
||||
import { Runner } from '../entities/Runner';
|
||||
import { Scan } from '../entities/Scan';
|
||||
|
||||
/**
|
||||
* This class is used to create a new Scan entity from a json body (post request).
|
||||
*/
|
||||
export abstract class CreateScan {
|
||||
/**
|
||||
* The scan's associated runner.
|
||||
* This is important to link ran distances to runners.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
runner: number;
|
||||
|
||||
/**
|
||||
* Is the scan valid (for fraud reasons).
|
||||
* The determination of validity will work differently for every child class.
|
||||
* Default: true
|
||||
*/
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
valid?: boolean = true;
|
||||
|
||||
/**
|
||||
* The scan's distance in meters.
|
||||
* Can be set manually or derived from another object.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
public distance: number;
|
||||
|
||||
/**
|
||||
* Creates a new Scan entity from this.
|
||||
*/
|
||||
public async toScan(): Promise<Scan> {
|
||||
let newScan = new Scan();
|
||||
|
||||
newScan.distance = this.distance;
|
||||
newScan.valid = this.valid;
|
||||
newScan.runner = await this.getRunner();
|
||||
|
||||
return newScan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a runner based on the runner id provided via this.runner.
|
||||
*/
|
||||
public async getRunner(): Promise<Runner> {
|
||||
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
|
||||
if (!runner) {
|
||||
throw new RunnerNotFoundError();
|
||||
}
|
||||
return runner;
|
||||
}
|
||||
}
|
||||
64
src/models/actions/CreateScanStation.ts
Normal file
64
src/models/actions/CreateScanStation.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import * as argon2 from "argon2";
|
||||
import { IsBoolean, IsInt, IsOptional, IsPositive, IsString } from 'class-validator';
|
||||
import crypto from 'crypto';
|
||||
import { getConnection } from 'typeorm';
|
||||
import * as uuid from 'uuid';
|
||||
import { TrackNotFoundError } from '../../errors/TrackErrors';
|
||||
import { ScanStation } from '../entities/ScanStation';
|
||||
import { Track } from '../entities/Track';
|
||||
|
||||
/**
|
||||
* This class is used to create a new StatsClient entity from a json body (post request).
|
||||
*/
|
||||
export class CreateScanStation {
|
||||
/**
|
||||
* The new station's description.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* The station's associated track.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
track: number;
|
||||
|
||||
/**
|
||||
* Is this station enabled?
|
||||
*/
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
enabled?: boolean = true;
|
||||
|
||||
/**
|
||||
* Converts this to a ScanStation entity.
|
||||
*/
|
||||
public async toEntity(): Promise<ScanStation> {
|
||||
let newStation: ScanStation = new ScanStation();
|
||||
|
||||
newStation.description = this.description;
|
||||
newStation.enabled = this.enabled;
|
||||
newStation.track = await this.getTrack();
|
||||
|
||||
let newUUID = uuid.v4().toUpperCase();
|
||||
newStation.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
|
||||
newStation.key = await argon2.hash(newStation.prefix + "." + newUUID);
|
||||
newStation.cleartextkey = newStation.prefix + "." + newUUID;
|
||||
|
||||
return newStation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get's a track by it's id provided via this.track.
|
||||
* Used to link the new station to a track.
|
||||
*/
|
||||
public async getTrack(): Promise<Track> {
|
||||
const track = await getConnection().getRepository(Track).findOne({ id: this.track });
|
||||
if (!track) {
|
||||
throw new TrackNotFoundError();
|
||||
}
|
||||
return track;
|
||||
}
|
||||
}
|
||||
84
src/models/actions/CreateTrackScan.ts
Normal file
84
src/models/actions/CreateTrackScan.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { IsNotEmpty } from 'class-validator';
|
||||
import { getConnection } from 'typeorm';
|
||||
import { RunnerNotFoundError } from '../../errors/RunnerErrors';
|
||||
import { RunnerCard } from '../entities/RunnerCard';
|
||||
import { ScanStation } from '../entities/ScanStation';
|
||||
import { TrackScan } from '../entities/TrackScan';
|
||||
import { CreateScan } from './CreateScan';
|
||||
|
||||
/**
|
||||
* This classed is used to create a new Scan entity from a json body (post request).
|
||||
*/
|
||||
export class CreateTrackScan extends CreateScan {
|
||||
|
||||
/**
|
||||
* The scan's associated track.
|
||||
* This is used to determine the scan's distance.
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
track: number;
|
||||
|
||||
/**
|
||||
* The runnerCard associated with the scan.
|
||||
* This get's saved for documentation and management purposes.
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
card: number;
|
||||
|
||||
/**
|
||||
* The scanning station that created the scan.
|
||||
* Mainly used for logging and traceing back scans (or errors)
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
station: number;
|
||||
|
||||
/**
|
||||
* Creates a new Track entity from this.
|
||||
*/
|
||||
public async toScan(): Promise<TrackScan> {
|
||||
let newScan: TrackScan = new TrackScan();
|
||||
|
||||
newScan.station = await this.getStation();
|
||||
newScan.card = await this.getCard();
|
||||
|
||||
newScan.track = newScan.station.track;
|
||||
newScan.runner = newScan.card.runner;
|
||||
|
||||
if (!newScan.runner) {
|
||||
throw new RunnerNotFoundError();
|
||||
}
|
||||
|
||||
newScan.timestamp = new Date(Date.now()).toString();
|
||||
newScan.valid = await this.validateScan(newScan);
|
||||
|
||||
return newScan;
|
||||
}
|
||||
|
||||
public async getCard(): Promise<RunnerCard> {
|
||||
const track = await getConnection().getRepository(RunnerCard).findOne({ id: this.card }, { relations: ["runner"] });
|
||||
if (!track) {
|
||||
throw new Error();
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
public async getStation(): Promise<ScanStation> {
|
||||
const track = await getConnection().getRepository(ScanStation).findOne({ id: this.card }, { relations: ["track"] });
|
||||
if (!track) {
|
||||
throw new Error();
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
public async validateScan(scan: TrackScan): Promise<boolean> {
|
||||
const scans = await getConnection().getRepository(TrackScan).find({ where: { runner: scan.runner }, relations: ["track"] });
|
||||
if (scans.length == 0) { return true; }
|
||||
|
||||
const newestScan = scans[0];
|
||||
if ((new Date(scan.timestamp).getTime() - new Date(newestScan.timestamp).getTime()) > scan.track.minimumLapTime) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
62
src/models/actions/UpdateScan.ts
Normal file
62
src/models/actions/UpdateScan.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { IsBoolean, IsInt, IsOptional, IsPositive } from 'class-validator';
|
||||
import { getConnection } from 'typeorm';
|
||||
import { RunnerNotFoundError } from '../../errors/RunnerErrors';
|
||||
import { Runner } from '../entities/Runner';
|
||||
import { Scan } from '../entities/Scan';
|
||||
|
||||
/**
|
||||
* This class is used to update a Scan entity (via put request)
|
||||
*/
|
||||
export abstract class UpdateScan {
|
||||
/**
|
||||
* The updated scan'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 scan's associated runner.
|
||||
* This is important to link ran distances to runners.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
runner: number;
|
||||
|
||||
/**
|
||||
* Is the updated scan valid (for fraud reasons).
|
||||
*/
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
valid?: boolean = true;
|
||||
|
||||
/**
|
||||
* The updated scan's distance in meters.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
public distance: number;
|
||||
|
||||
/**
|
||||
* Update a Scan entity based on this.
|
||||
* @param scan The scan that shall be updated.
|
||||
*/
|
||||
public async updateScan(scan: Scan): Promise<Scan> {
|
||||
scan.distance = this.distance;
|
||||
scan.valid = this.valid;
|
||||
scan.runner = await this.getRunner();
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a runner based on the runner id provided via this.runner.
|
||||
*/
|
||||
public async getRunner(): Promise<Runner> {
|
||||
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
|
||||
if (!runner) {
|
||||
throw new RunnerNotFoundError();
|
||||
}
|
||||
return runner;
|
||||
}
|
||||
}
|
||||
39
src/models/actions/UpdateScanStation.ts
Normal file
39
src/models/actions/UpdateScanStation.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { IsBoolean, IsInt, IsOptional, IsString } from 'class-validator';
|
||||
import { ScanStation } from '../entities/ScanStation';
|
||||
|
||||
/**
|
||||
* This class is used to update a ScanStation entity (via put request)
|
||||
*/
|
||||
export class UpdateScanStation {
|
||||
/**
|
||||
* The updated station'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 station's description.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Is this station enabled?
|
||||
*/
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
enabled?: boolean = true;
|
||||
|
||||
/**
|
||||
* Update a ScanStation entity based on this.
|
||||
* @param station The station that shall be updated.
|
||||
*/
|
||||
public async updateStation(station: ScanStation): Promise<ScanStation> {
|
||||
station.description = this.description;
|
||||
station.enabled = this.enabled;
|
||||
|
||||
return station;
|
||||
}
|
||||
}
|
||||
@@ -80,4 +80,11 @@ export class Address {
|
||||
*/
|
||||
@OneToMany(() => IAddressUser, addressUser => addressUser.address, { nullable: true })
|
||||
addressUsers: IAddressUser[];
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,11 @@ export class DistanceDonation extends Donation {
|
||||
}
|
||||
return calculatedAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,11 @@ export abstract class Donation {
|
||||
* The exact implementation may differ for each type of donation.
|
||||
*/
|
||||
abstract amount: number;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IsBoolean } from "class-validator";
|
||||
import { ChildEntity, Column, OneToMany } from "typeorm";
|
||||
import { ResponseDonor } from '../responses/ResponseDonor';
|
||||
import { Donation } from './Donation';
|
||||
import { Participant } from "./Participant";
|
||||
|
||||
@@ -22,4 +23,11 @@ export class Donor extends Participant {
|
||||
*/
|
||||
@OneToMany(() => Donation, donation => donation.donor, { nullable: true })
|
||||
donations: Donation[];
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseDonor {
|
||||
return new ResponseDonor(this);
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,11 @@ export class FixedDonation extends Donation {
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
amount: number;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
@@ -81,4 +81,11 @@ export class GroupContact implements IAddressUser {
|
||||
*/
|
||||
@OneToMany(() => RunnerGroup, group => group.contact, { nullable: true })
|
||||
groups: RunnerGroup[];
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,9 @@ export abstract class IAddressUser {
|
||||
|
||||
@ManyToOne(() => Address, address => address.addressUsers, { nullable: true })
|
||||
address?: Address
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public abstract toResponse();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from "class-validator";
|
||||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
|
||||
import { config } from '../../config';
|
||||
import { ResponseParticipant } from '../responses/ResponseParticipant';
|
||||
import { Address } from "./Address";
|
||||
import { IAddressUser } from './IAddressUser';
|
||||
|
||||
@@ -74,4 +75,9 @@ export abstract class Participant implements IAddressUser {
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
email?: string;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public abstract toResponse(): ResponseParticipant;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { PermissionAction } from '../enums/PermissionAction';
|
||||
import { PermissionTarget } from '../enums/PermissionTargets';
|
||||
import { ResponsePermission } from '../responses/ResponsePermission';
|
||||
import { Principal } from './Principal';
|
||||
/**
|
||||
* Defines the Permission entity.
|
||||
@@ -51,4 +52,11 @@ export class Permission {
|
||||
public toString(): string {
|
||||
return this.target + ":" + this.action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponsePermission {
|
||||
return new ResponsePermission(this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IsInt, IsNotEmpty } from "class-validator";
|
||||
import { ChildEntity, ManyToOne, OneToMany } from "typeorm";
|
||||
import { ResponseRunner } from '../responses/ResponseRunner';
|
||||
import { DistanceDonation } from "./DistanceDonation";
|
||||
import { Participant } from "./Participant";
|
||||
import { RunnerCard } from "./RunnerCard";
|
||||
@@ -47,7 +48,7 @@ export class Runner extends Participant {
|
||||
* This is implemented here to avoid duplicate code in other files.
|
||||
*/
|
||||
public get validScans(): Scan[] {
|
||||
return this.scans.filter(scan => { scan.valid === true });
|
||||
return this.scans.filter(scan => scan.valid == true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,4 +67,11 @@ export class Runner extends Participant {
|
||||
public get distanceDonationAmount(): number {
|
||||
return this.distanceDonations.reduce((sum, current) => sum + current.amountPerDistance, 0) * this.distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseRunner {
|
||||
return new ResponseRunner(this);
|
||||
}
|
||||
}
|
||||
@@ -57,4 +57,11 @@ export class RunnerCard {
|
||||
*/
|
||||
@OneToMany(() => TrackScan, scan => scan.track, { nullable: true })
|
||||
scans: TrackScan[];
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
IsString
|
||||
} from "class-validator";
|
||||
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
|
||||
import { ResponseRunnerGroup } from '../responses/ResponseRunnerGroup';
|
||||
import { GroupContact } from "./GroupContact";
|
||||
import { Runner } from "./Runner";
|
||||
|
||||
@@ -60,4 +61,9 @@ export abstract class RunnerGroup {
|
||||
public get distanceDonationAmount(): number {
|
||||
return this.runners.reduce((sum, current) => sum + current.distanceDonationAmount, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public abstract toResponse(): ResponseRunnerGroup;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IsInt, IsOptional } from "class-validator";
|
||||
import { ChildEntity, ManyToOne, OneToMany } from "typeorm";
|
||||
import { ResponseRunnerOrganisation } from '../responses/ResponseRunnerOrganisation';
|
||||
import { Address } from './Address';
|
||||
import { IAddressUser } from './IAddressUser';
|
||||
import { Runner } from './Runner';
|
||||
@@ -54,4 +55,11 @@ export class RunnerOrganisation extends RunnerGroup implements IAddressUser {
|
||||
public get distanceDonationAmount(): number {
|
||||
return this.allRunners.reduce((sum, current) => sum + current.distanceDonationAmount, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseRunnerOrganisation {
|
||||
return new ResponseRunnerOrganisation(this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IsNotEmpty } from "class-validator";
|
||||
import { ChildEntity, ManyToOne } from "typeorm";
|
||||
import { ResponseRunnerTeam } from '../responses/ResponseRunnerTeam';
|
||||
import { RunnerGroup } from "./RunnerGroup";
|
||||
import { RunnerOrganisation } from "./RunnerOrganisation";
|
||||
|
||||
@@ -17,4 +18,11 @@ export class RunnerTeam extends RunnerGroup {
|
||||
@IsNotEmpty()
|
||||
@ManyToOne(() => RunnerOrganisation, org => org.teams, { nullable: true })
|
||||
parentGroup?: RunnerOrganisation;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseRunnerTeam {
|
||||
return new ResponseRunnerTeam(this);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
IsPositive
|
||||
} from "class-validator";
|
||||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
|
||||
import { ResponseScan } from '../responses/ResponseScan';
|
||||
import { Runner } from "./Runner";
|
||||
|
||||
/**
|
||||
@@ -14,7 +15,7 @@ import { Runner } from "./Runner";
|
||||
*/
|
||||
@Entity()
|
||||
@TableInheritance({ column: { name: "type", type: "varchar" } })
|
||||
export abstract class Scan {
|
||||
export class Scan {
|
||||
/**
|
||||
* Autogenerated unique id (primary key).
|
||||
*/
|
||||
@@ -30,14 +31,6 @@ export abstract class Scan {
|
||||
@ManyToOne(() => Runner, runner => runner.scans, { nullable: false })
|
||||
runner: Runner;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* The determination of validity will work differently for every child class.
|
||||
@@ -46,4 +39,37 @@ export abstract class Scan {
|
||||
@Column()
|
||||
@IsBoolean()
|
||||
valid: boolean = true;
|
||||
|
||||
/**
|
||||
* The scan's distance in meters.
|
||||
* This is the "real" value used by "normal" scans..
|
||||
*/
|
||||
@Column({ nullable: true })
|
||||
@IsInt()
|
||||
private _distance?: number;
|
||||
|
||||
/**
|
||||
* The scan's distance in meters.
|
||||
* Can be set manually or derived from another object.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
public get distance(): number {
|
||||
return this._distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The scan's distance in meters.
|
||||
* Can be set manually or derived from another object.
|
||||
*/
|
||||
public set distance(value: number) {
|
||||
this._distance = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseScan {
|
||||
return new ResponseScan(this);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
IsString
|
||||
} from "class-validator";
|
||||
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { ResponseScanStation } from '../responses/ResponseScanStation';
|
||||
import { Track } from "./Track";
|
||||
import { TrackScan } from "./TrackScan";
|
||||
|
||||
@@ -39,6 +40,14 @@ export class ScanStation {
|
||||
@ManyToOne(() => Track, track => track.stations, { nullable: false })
|
||||
track: Track;
|
||||
|
||||
/**
|
||||
* The client's api key prefix.
|
||||
* This is used identitfy a client by it's api key.
|
||||
*/
|
||||
@Column({ unique: true })
|
||||
@IsString()
|
||||
prefix: string;
|
||||
|
||||
/**
|
||||
* The station's api key.
|
||||
* This is used to authorize a station against the api (not implemented yet).
|
||||
@@ -49,16 +58,30 @@ export class ScanStation {
|
||||
key: string;
|
||||
|
||||
/**
|
||||
* Is the station enabled (for fraud and setup reasons)?
|
||||
* Default: true
|
||||
* The client's api key in plain text.
|
||||
* This will only be used to display the full key on creation and updates.
|
||||
*/
|
||||
@Column()
|
||||
@IsBoolean()
|
||||
enabled: boolean = true;
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
cleartextkey?: string;
|
||||
|
||||
/**
|
||||
* Used to link track scans to a scan station.
|
||||
*/
|
||||
@OneToMany(() => TrackScan, scan => scan.track, { nullable: true })
|
||||
scans: TrackScan[];
|
||||
|
||||
/**
|
||||
* Is this station enabled?
|
||||
*/
|
||||
@Column({ nullable: true })
|
||||
@IsBoolean()
|
||||
enabled?: boolean = true;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseScanStation {
|
||||
return new ResponseScanStation(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IsInt, IsOptional, IsString } from "class-validator";
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { ResponseStatsClient } from '../responses/ResponseStatsClient';
|
||||
/**
|
||||
* Defines the StatsClient entity.
|
||||
* StatsClients can be used to access the protected parts of the stats api (top runners, donators and so on).
|
||||
@@ -45,4 +46,11 @@ export class StatsClient {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
cleartextkey?: string;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseStatsClient {
|
||||
return new ResponseStatsClient(this);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
IsString
|
||||
} from "class-validator";
|
||||
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { ResponseTrack } from '../responses/ResponseTrack';
|
||||
import { ScanStation } from "./ScanStation";
|
||||
import { TrackScan } from "./TrackScan";
|
||||
|
||||
@@ -61,4 +62,11 @@ export class Track {
|
||||
*/
|
||||
@OneToMany(() => TrackScan, scan => scan.track, { nullable: true })
|
||||
scans: TrackScan[];
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseTrack {
|
||||
return new ResponseTrack(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
IsPositive
|
||||
} from "class-validator";
|
||||
import { ChildEntity, Column, ManyToOne } from "typeorm";
|
||||
import { ResponseTrackScan } from '../responses/ResponseTrackScan';
|
||||
import { RunnerCard } from "./RunnerCard";
|
||||
import { Scan } from "./Scan";
|
||||
import { ScanStation } from "./ScanStation";
|
||||
@@ -59,4 +60,11 @@ export class TrackScan extends Scan {
|
||||
@IsDateString()
|
||||
@IsNotEmpty()
|
||||
timestamp: string;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse(): ResponseTrackScan {
|
||||
return new ResponseTrackScan(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,11 @@ export class UserAction {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
changed: string;
|
||||
|
||||
/**
|
||||
* Turns this entity into it's response class.
|
||||
*/
|
||||
public toResponse() {
|
||||
return new Error("NotImplemented");
|
||||
}
|
||||
}
|
||||
@@ -10,5 +10,7 @@ export enum PermissionTarget {
|
||||
USERGROUP = 'USERGROUP',
|
||||
PERMISSION = 'PERMISSION',
|
||||
STATSCLIENT = 'STATSCLIENT',
|
||||
DONOR = 'DONOR'
|
||||
DONOR = 'DONOR',
|
||||
SCAN = 'SCAN',
|
||||
STATION = 'STATION'
|
||||
}
|
||||
@@ -29,7 +29,8 @@ export class ResponseRunner extends ResponseParticipant {
|
||||
*/
|
||||
public constructor(runner: Runner) {
|
||||
super(runner);
|
||||
this.distance = runner.scans.filter(scan => { scan.valid === true }).reduce((sum, current) => sum + current.distance, 0);
|
||||
if (!runner.scans) { this.distance = 0 }
|
||||
else { this.distance = runner.validScans.reduce((sum, current) => sum + current.distance, 0); }
|
||||
this.group = runner.group;
|
||||
}
|
||||
}
|
||||
|
||||
46
src/models/responses/ResponseScan.ts
Normal file
46
src/models/responses/ResponseScan.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { IsBoolean, IsInt, IsNotEmpty, IsPositive } from "class-validator";
|
||||
import { Scan } from '../entities/Scan';
|
||||
import { ResponseRunner } from './ResponseRunner';
|
||||
|
||||
/**
|
||||
* Defines the scan response.
|
||||
*/
|
||||
export class ResponseScan {
|
||||
/**
|
||||
* The scans's id.
|
||||
*/
|
||||
@IsInt()
|
||||
id: number;;
|
||||
|
||||
/**
|
||||
* The scan's associated runner.
|
||||
* This is important to link ran distances to runners.
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
runner: ResponseRunner;
|
||||
|
||||
/**
|
||||
* Is the scan valid (for fraud reasons).
|
||||
* The determination of validity will work differently for every child class.
|
||||
*/
|
||||
@IsBoolean()
|
||||
valid: boolean = true;
|
||||
|
||||
/**
|
||||
* The scans's length/distance in meters.
|
||||
*/
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
distance: number;
|
||||
|
||||
/**
|
||||
* Creates a ResponseScan object from a scan.
|
||||
* @param scan The scan the response shall be build for.
|
||||
*/
|
||||
public constructor(scan: Scan) {
|
||||
this.id = scan.id;
|
||||
this.runner = scan.runner.toResponse();
|
||||
this.distance = scan.distance;
|
||||
this.valid = scan.valid;
|
||||
}
|
||||
}
|
||||
70
src/models/responses/ResponseScanStation.ts
Normal file
70
src/models/responses/ResponseScanStation.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
|
||||
IsBoolean,
|
||||
IsInt,
|
||||
|
||||
IsNotEmpty,
|
||||
|
||||
IsObject,
|
||||
|
||||
IsOptional,
|
||||
IsString
|
||||
} from "class-validator";
|
||||
import { ScanStation } from '../entities/ScanStation';
|
||||
import { ResponseTrack } from './ResponseTrack';
|
||||
|
||||
/**
|
||||
* Defines the statsClient response.
|
||||
*/
|
||||
export class ResponseScanStation {
|
||||
/**
|
||||
* The client's id.
|
||||
*/
|
||||
@IsInt()
|
||||
id: number;
|
||||
|
||||
/**
|
||||
* The client's description.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* The client's api key.
|
||||
* Only visible on creation or regeneration.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
key: string;
|
||||
|
||||
/**
|
||||
* The client's api key prefix.
|
||||
*/
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
prefix: string;
|
||||
|
||||
@IsObject()
|
||||
@IsNotEmpty()
|
||||
track: ResponseTrack;
|
||||
|
||||
/**
|
||||
* Is this station enabled?
|
||||
*/
|
||||
@IsBoolean()
|
||||
enabled?: boolean = true;
|
||||
|
||||
/**
|
||||
* Creates a ResponseStatsClient object from a statsClient.
|
||||
* @param client The statsClient the response shall be build for.
|
||||
*/
|
||||
public constructor(station: ScanStation) {
|
||||
this.id = station.id;
|
||||
this.description = station.description;
|
||||
this.prefix = station.prefix;
|
||||
this.key = "Only visible on creation.";
|
||||
this.track = station.track;
|
||||
this.enabled = station.enabled;
|
||||
}
|
||||
}
|
||||
48
src/models/responses/ResponseTrackScan.ts
Normal file
48
src/models/responses/ResponseTrackScan.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { IsDateString, IsNotEmpty } from "class-validator";
|
||||
import { RunnerCard } from '../entities/RunnerCard';
|
||||
import { ScanStation } from '../entities/ScanStation';
|
||||
import { TrackScan } from '../entities/TrackScan';
|
||||
import { ResponseScan } from './ResponseScan';
|
||||
import { ResponseTrack } from './ResponseTrack';
|
||||
|
||||
/**
|
||||
* Defines the trackScan response.
|
||||
*/
|
||||
export class ResponseTrackScan extends ResponseScan {
|
||||
/**
|
||||
* The scan's associated track.
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
track: ResponseTrack;
|
||||
|
||||
/**
|
||||
* The runnerCard associated with the scan.
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
card: RunnerCard;
|
||||
|
||||
/**
|
||||
* The scanning station that created the scan.
|
||||
*/
|
||||
@IsNotEmpty()
|
||||
station: ScanStation;
|
||||
|
||||
/**
|
||||
* The scan's creation timestamp.
|
||||
*/
|
||||
@IsDateString()
|
||||
@IsNotEmpty()
|
||||
timestamp: string;
|
||||
|
||||
/**
|
||||
* Creates a ResponseTrackScan object from a scan.
|
||||
* @param scan The trackSscan the response shall be build for.
|
||||
*/
|
||||
public constructor(scan: TrackScan) {
|
||||
super(scan);
|
||||
this.track = new ResponseTrack(scan.track);
|
||||
this.card = scan.card;
|
||||
this.station = scan.station;
|
||||
this.timestamp = scan.timestamp;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user