Code + comment cleanup for the entities

ref #39
This commit is contained in:
Nicolai Ort 2020-12-21 15:29:32 +01:00
parent a03f1a438d
commit d20d738218
21 changed files with 156 additions and 87 deletions

View File

@ -10,7 +10,8 @@ import { Participant } from "./Participant";
import { RunnerOrganisation } from "./RunnerOrganisation"; 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() @Entity()
export class Address { export class Address {
@ -23,6 +24,7 @@ export class Address {
/** /**
* The address's description. * The address's description.
* Optional and mostly for UX.
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsString() @IsString()
@ -49,6 +51,8 @@ export class Address {
/** /**
* The address's postal code. * The address's postal code.
* This will get checked against the postal code syntax for the configured country.
* TODO: Implement the config option.
*/ */
@Column() @Column()
@IsString() @IsString()

View File

@ -4,19 +4,21 @@ import { Donation } from "./Donation";
import { Runner } from "./Runner"; import { Runner } from "./Runner";
/** /**
* Defines a distance based donation. * Defines the DistanceDonation entity.
* Here people donate a certain amout per kilometer * For distanceDonations a donor pledges to donate a certain amount for each kilometer ran by a runner.
*/ */
@ChildEntity() @ChildEntity()
export class DistanceDonation extends Donation { export class DistanceDonation extends Donation {
/** /**
* The runner associated. * The donation's associated runner.
* Used as the source of the donation's distance.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => Runner, runner => runner.distanceDonations) @ManyToOne(() => Runner, runner => runner.distanceDonations)
runner: Runner; runner: Runner;
/** /**
* The donation's amount donated per distance.
* The amount the donor set to be donated per kilometer that the runner ran. * The amount the donor set to be donated per kilometer that the runner ran.
*/ */
@Column() @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 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 { public get amount(): number {
let calculatedAmount = -1; let calculatedAmount = -1;
try { try {
calculatedAmount = this.amountPerDistance * this.runner.distance; calculatedAmount = this.amountPerDistance * (this.runner.distance / 1000);
} catch (error) { } catch (error) {
throw error; throw error;
} }

View File

@ -6,7 +6,9 @@ import { Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typ
import { Participant } from "./Participant"; 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() @Entity()
@TableInheritance({ column: { name: "type", type: "varchar" } }) @TableInheritance({ column: { name: "type", type: "varchar" } })

View File

@ -3,13 +3,13 @@ import { ChildEntity, Column } from "typeorm";
import { Participant } from "./Participant"; import { Participant } from "./Participant";
/** /**
* Defines a donor. * Defines the Donor entity.
*/ */
@ChildEntity() @ChildEntity()
export class Donor extends Participant { export class Donor extends Participant {
/** /**
* Does this donor need a receipt?. * Does this donor need a receipt?
* Default: false * Will later be used to automaticly generate donation receipts.
*/ */
@Column() @Column()
@IsBoolean() @IsBoolean()

View File

@ -3,7 +3,8 @@ import { ChildEntity, Column } from "typeorm";
import { Donation } from "./Donation"; 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() @ChildEntity()
export class FixedDonation extends Donation { export class FixedDonation extends Donation {

View File

@ -13,7 +13,8 @@ import { Address } from "./Address";
import { RunnerGroup } from "./RunnerGroup"; 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() @Entity()
export class GroupContact { export class GroupContact {
@ -34,7 +35,6 @@ export class GroupContact {
/** /**
* The contact's middle name. * The contact's middle name.
* Optional
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -51,7 +51,7 @@ export class GroupContact {
/** /**
* The contact's address. * The contact's address.
* Optional * This is a address object to prevent any formatting differences.
*/ */
@IsOptional() @IsOptional()
@ManyToOne(() => Address, address => address.participants, { nullable: true }) @ManyToOne(() => Address, address => address.participants, { nullable: true })
@ -59,7 +59,7 @@ export class GroupContact {
/** /**
* The contact's phone number. * The contact's phone number.
* Optional * This will be validated against the configured country phone numer syntax (default: international).
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -68,7 +68,7 @@ export class GroupContact {
/** /**
* The contact's email address. * The contact's email address.
* Optional * Could later be used to automaticly send mails concerning the contact's associated groups.
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()

View File

@ -13,7 +13,8 @@ import { Address } from "./Address";
import { Donation } from "./Donation"; import { Donation } from "./Donation";
/** /**
* Defines the participant interface. * Defines the Participant entity.
* Participans can donate and therefor be associated with donation entities.
*/ */
@Entity() @Entity()
@TableInheritance({ column: { name: "type", type: "varchar" } }) @TableInheritance({ column: { name: "type", type: "varchar" } })
@ -35,7 +36,6 @@ export abstract class Participant {
/** /**
* The participant's middle name. * The participant's middle name.
* Optional
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -52,14 +52,14 @@ export abstract class Participant {
/** /**
* The participant's address. * The participant's address.
* Optional * This is a address object to prevent any formatting differences.
*/ */
@ManyToOne(() => Address, address => address.participants, { nullable: true }) @ManyToOne(() => Address, address => address.participants, { nullable: true })
address?: Address; address?: Address;
/** /**
* The participant's phone number. * The participant's phone number.
* Optional * This will be validated against the configured country phone numer syntax (default: international).
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -68,7 +68,7 @@ export abstract class Participant {
/** /**
* The participant's email address. * The participant's email address.
* Optional * Can be used to contact the participant.
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -77,6 +77,7 @@ export abstract class Participant {
/** /**
* Used to link the participant as the donor of a donation. * 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 }) @OneToMany(() => Donation, donation => donation.donor, { nullable: true })
donations: Donation[]; donations: Donation[];

View File

@ -8,7 +8,9 @@ import { PermissionAction } from '../enums/PermissionAction';
import { PermissionTarget } from '../enums/PermissionTargets'; import { PermissionTarget } from '../enums/PermissionTargets';
import { Principal } from './Principal'; 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() @Entity()
export class Permission { export class Permission {
@ -20,13 +22,14 @@ export class Permission {
id: number; id: number;
/** /**
* The permissions principal * The permission's principal.
*/ */
@ManyToOne(() => Principal, principal => principal.permissions) @ManyToOne(() => Principal, principal => principal.permissions)
principal: Principal; 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' }) @Column({ type: 'varchar' })
@IsNotEmpty() @IsNotEmpty()
@ -34,14 +37,16 @@ export class Permission {
target: PermissionTarget; 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' }) @Column({ type: 'varchar' })
@IsEnum(PermissionAction) @IsEnum(PermissionAction)
action: 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 { public toString(): string {
return this.target + ":" + this.action; return this.target + ":" + this.action;

View File

@ -4,23 +4,27 @@ import { ResponsePrincipal } from '../responses/ResponsePrincipal';
import { Permission } from './Permission'; 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() @Entity()
@TableInheritance({ column: { name: "type", type: "varchar" } }) @TableInheritance({ column: { name: "type", type: "varchar" } })
export abstract class Principal { export abstract class Principal {
/** /**
* autogenerated unique id (primary key). * Autogenerated unique id (primary key).
*/ */
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
@IsInt() @IsInt()
id: number; id: number;
/** /**
* permissions * The participant's permissions.
*/ */
@OneToMany(() => Permission, permission => permission.principal, { nullable: true }) @OneToMany(() => Permission, permission => permission.principal, { nullable: true })
permissions: Permission[]; permissions: Permission[];
/**
* Turns this entity into it's response class.
*/
public abstract toResponse(): ResponsePrincipal; public abstract toResponse(): ResponsePrincipal;
} }

View File

@ -7,44 +7,52 @@ import { RunnerGroup } from "./RunnerGroup";
import { Scan } from "./Scan"; 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() @ChildEntity()
export class Runner extends Participant { export class Runner extends Participant {
/** /**
* The runner's associated group. * The runner's associated group.
* Can be a runner team or organisation.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => RunnerGroup, group => group.runners, { nullable: false }) @ManyToOne(() => RunnerGroup, group => group.runners, { nullable: false })
group: RunnerGroup; 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 }) @OneToMany(() => DistanceDonation, distanceDonation => distanceDonation.runner, { nullable: true })
distanceDonations: DistanceDonation[]; 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 }) @OneToMany(() => RunnerCard, card => card.runner, { nullable: true })
cards: RunnerCard[]; 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 }) @OneToMany(() => Scan, scan => scan.runner, { nullable: true })
scans: Scan[]; scans: Scan[];
/** /**
* Returns all valid scans associated with this runner. * Returns all valid scans associated with this runner.
* This is implemented here to avoid duplicate code in other files.
*/ */
public get validScans(): Scan[] { public get validScans(): Scan[] {
return this.scans.filter(scan => { scan.valid === true }); 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() @IsInt()
public get distance(): number { public get distance(): number {

View File

@ -11,7 +11,9 @@ import { Runner } from "./Runner";
import { TrackScan } from "./TrackScan"; 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() @Entity()
export class RunnerCard { export class RunnerCard {
@ -23,7 +25,8 @@ export class RunnerCard {
id: number; 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() @IsOptional()
@ManyToOne(() => Runner, runner => runner.cards, { nullable: true }) @ManyToOne(() => Runner, runner => runner.cards, { nullable: true })
@ -32,7 +35,7 @@ export class RunnerCard {
/** /**
* The card's code. * The card's code.
* This has to be able to being converted to something barcode compatible. * This has to be able to being converted to something barcode compatible.
* could theoretically be autogenerated * Will get automaticlly generated (not implemented yet).
*/ */
@Column() @Column()
@IsEAN() @IsEAN()
@ -49,7 +52,8 @@ export class RunnerCard {
enabled: boolean = true; 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 }) @OneToMany(() => TrackScan, scan => scan.track, { nullable: true })
scans: TrackScan[]; scans: TrackScan[];

View File

@ -9,7 +9,8 @@ import { GroupContact } from "./GroupContact";
import { Runner } from "./Runner"; import { Runner } from "./Runner";
/** /**
* Defines the runnerGroup interface. * Defines the RunnerGroup entity.
* This is used to group runners together (as the name suggests).
*/ */
@Entity() @Entity()
@TableInheritance({ column: { name: "type", type: "varchar" } }) @TableInheritance({ column: { name: "type", type: "varchar" } })
@ -31,13 +32,14 @@ export abstract class RunnerGroup {
/** /**
* The group's contact. * The group's contact.
* Optional * This is mostly a feature for the group managers and public relations.
*/ */
@IsOptional() @IsOptional()
@ManyToOne(() => GroupContact, contact => contact.groups, { nullable: true }) @ManyToOne(() => GroupContact, contact => contact.groups, { nullable: true })
contact?: GroupContact; contact?: GroupContact;
/** /**
* The group's associated runners.
* Used to link runners to a runner group. * Used to link runners to a runner group.
*/ */
@OneToMany(() => Runner, runner => runner.group, { nullable: true }) @OneToMany(() => Runner, runner => runner.group, { nullable: true })

View File

@ -5,21 +5,22 @@ import { RunnerGroup } from "./RunnerGroup";
import { RunnerTeam } from "./RunnerTeam"; 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() @ChildEntity()
export class RunnerOrganisation extends RunnerGroup { export class RunnerOrganisation extends RunnerGroup {
/** /**
* The organisations's address. * The organisations's address.
* Optional
*/ */
@IsOptional() @IsOptional()
@ManyToOne(() => Address, address => address.groups, { nullable: true }) @ManyToOne(() => Address, address => address.groups, { nullable: true })
address?: Address; 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 }) @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true })
teams: RunnerTeam[]; teams: RunnerTeam[];

View File

@ -4,14 +4,15 @@ import { RunnerGroup } from "./RunnerGroup";
import { RunnerOrganisation } from "./RunnerOrganisation"; 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() @ChildEntity()
export class RunnerTeam extends RunnerGroup { export class RunnerTeam extends RunnerGroup {
/** /**
* The team's parent group. * The team's parent group.
* Optional * Every team has to be part of a runnerOrganisation - this get's checked on creation and update.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => RunnerOrganisation, org => org.teams, { nullable: true }) @ManyToOne(() => RunnerOrganisation, org => org.teams, { nullable: true })

View File

@ -9,7 +9,8 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } f
import { Runner } from "./Runner"; 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() @Entity()
@TableInheritance({ column: { name: "type", type: "varchar" } }) @TableInheritance({ column: { name: "type", type: "varchar" } })
@ -22,7 +23,8 @@ export abstract class Scan {
id: number; id: number;
/** /**
* The associated runner. * The scan's associated runner.
* This is important to link ran distances to runners.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => Runner, runner => runner.scans, { nullable: false }) @ManyToOne(() => Runner, runner => runner.scans, { nullable: false })
@ -30,6 +32,7 @@ export abstract class Scan {
/** /**
* The scan's distance in meters. * The scan's distance in meters.
* Can be set manually or derived from another object.
*/ */
@IsInt() @IsInt()
@IsPositive() @IsPositive()
@ -37,6 +40,7 @@ export abstract class Scan {
/** /**
* Is the scan valid (for fraud reasons). * Is the scan valid (for fraud reasons).
* The determination of validity will work differently for every child class.
* Default: true * Default: true
*/ */
@Column() @Column()

View File

@ -10,7 +10,8 @@ import { Track } from "./Track";
import { TrackScan } from "./TrackScan"; 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() @Entity()
export class ScanStation { export class ScanStation {
@ -23,6 +24,7 @@ export class ScanStation {
/** /**
* The station's description. * The station's description.
* Mostly for better UX when traceing back stuff.
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -31,6 +33,7 @@ export class ScanStation {
/** /**
* The track this station is associated with. * The track this station is associated with.
* All scans created by this station will also be associated with this track.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => Track, track => track.stations, { nullable: false }) @ManyToOne(() => Track, track => track.stations, { nullable: false })
@ -38,6 +41,7 @@ export class ScanStation {
/** /**
* The station's api key. * The station's api key.
* This is used to authorize a station against the api (not implemented yet).
*/ */
@Column() @Column()
@IsNotEmpty() @IsNotEmpty()
@ -45,7 +49,7 @@ export class ScanStation {
key: string; key: string;
/** /**
* Is the station enabled (for fraud reasons)? * Is the station enabled (for fraud and setup reasons)?
* Default: true * Default: true
*/ */
@Column() @Column()

View File

@ -1,7 +1,6 @@
import { import {
IsInt, IsInt,
IsNotEmpty, IsNotEmpty,
IsPositive, IsPositive,
IsString IsString
} from "class-validator"; } from "class-validator";
@ -10,7 +9,7 @@ import { ScanStation } from "./ScanStation";
import { TrackScan } from "./TrackScan"; import { TrackScan } from "./TrackScan";
/** /**
* Defines a track of given length. * Defines the Track entity.
*/ */
@Entity() @Entity()
export class Track { export class Track {
@ -23,6 +22,7 @@ export class Track {
/** /**
* The track's name. * The track's name.
* Mainly here for UX.
*/ */
@Column() @Column()
@IsString() @IsString()
@ -31,6 +31,7 @@ export class Track {
/** /**
* The track's length/distance in meters. * The track's length/distance in meters.
* Will be used to calculate runner's ran distances.
*/ */
@Column() @Column()
@IsInt() @IsInt()
@ -38,13 +39,15 @@ export class Track {
distance: number; 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 }) @OneToMany(() => ScanStation, station => station.track, { nullable: true })
stations: ScanStation[]; stations: ScanStation[];
/** /**
* Used to link track scans to a track. * 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 }) @OneToMany(() => TrackScan, scan => scan.track, { nullable: true })
scans: TrackScan[]; scans: TrackScan[];

View File

@ -12,26 +12,30 @@ import { ScanStation } from "./ScanStation";
import { Track } from "./Track"; import { Track } from "./Track";
/** /**
* Defines the scan interface. * Defines the TrackScan entity.
* A track scan usaually get's generated by a scan station.
*/ */
@ChildEntity() @ChildEntity()
export class TrackScan extends Scan { export class TrackScan extends Scan {
/** /**
* The associated track. * The scan's associated track.
* This is used to determine the scan's distance.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => Track, track => track.scans, { nullable: true }) @ManyToOne(() => Track, track => track.scans, { nullable: true })
track: Track; track: Track;
/** /**
* The associated card. * The runnerCard associated with the scan.
* This get's saved for documentation and management purposes.
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => RunnerCard, card => card.scans, { nullable: true }) @ManyToOne(() => RunnerCard, card => card.scans, { nullable: true })
card: RunnerCard; card: RunnerCard;
/** /**
* The scanning station. * The scanning station that created the scan.
* Mainly used for logging and traceing back scans (or errors)
*/ */
@IsNotEmpty() @IsNotEmpty()
@ManyToOne(() => ScanStation, station => station.scans, { nullable: true }) @ManyToOne(() => ScanStation, station => station.scans, { nullable: true })
@ -39,6 +43,7 @@ export class TrackScan extends Scan {
/** /**
* The scan's distance in meters. * The scan's distance in meters.
* This just get's loaded from it's track.
*/ */
@IsInt() @IsInt()
@IsPositive() @IsPositive()
@ -48,6 +53,7 @@ export class TrackScan extends Scan {
/** /**
* The scan's creation timestamp. * The scan's creation timestamp.
* Will be used to implement fraud detection.
*/ */
@Column() @Column()
@IsDateString() @IsDateString()

View File

@ -8,26 +8,29 @@ import { UserAction } from './UserAction';
import { UserGroup } from './UserGroup'; 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() @ChildEntity()
export class User extends Principal { 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 }) @Column({ unique: true })
@IsUUID(4) @IsUUID(4)
uuid: string; 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 }) @Column({ nullable: true, unique: true })
@IsEmail() @IsEmail()
email?: string; email?: string;
/** /**
* user phone * The user's phone number.
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsOptional() @IsOptional()
@ -35,14 +38,15 @@ export class User extends Principal {
phone?: string; 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 }) @Column({ nullable: true, unique: true })
@IsString() @IsString()
username?: string; username?: string;
/** /**
* firstname * The user's first name.
*/ */
@Column() @Column()
@IsString() @IsString()
@ -50,7 +54,7 @@ export class User extends Principal {
firstname: string; firstname: string;
/** /**
* middlename * The user's middle name.
*/ */
@Column({ nullable: true }) @Column({ nullable: true })
@IsString() @IsString()
@ -58,7 +62,7 @@ export class User extends Principal {
middlename?: string; middlename?: string;
/** /**
* lastname * The user's last name.
*/ */
@Column() @Column()
@IsString() @IsString()
@ -66,7 +70,8 @@ export class User extends Principal {
lastname: string; lastname: string;
/** /**
* password * The user's password.
* This is a argon2 hash salted with the user's uuid.
*/ */
@Column() @Column()
@IsString() @IsString()
@ -74,7 +79,8 @@ export class User extends Principal {
password: string; password: string;
/** /**
* groups * The groups this user is a part of.
* The user will inherit the groups permissions (without overwriting his own).
*/ */
@IsOptional() @IsOptional()
@ManyToMany(() => UserGroup, { nullable: true }) @ManyToMany(() => UserGroup, { nullable: true })
@ -82,21 +88,23 @@ export class User extends Principal {
groups: UserGroup[]; groups: UserGroup[];
/** /**
* is user enabled? * Is this user enabled?
*/ */
@Column() @Column()
@IsBoolean() @IsBoolean()
enabled: boolean = true; enabled: boolean = true;
/** /**
* jwt refresh count * The user's jwt refresh token count.
* Used to invalidate jwts.
*/ */
@IsInt() @IsInt()
@Column({ default: 1 }) @Column({ default: 1 })
refreshTokenCount?: number; 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 }) @Column({ nullable: true, unique: true })
@IsString() @IsString()
@ -104,14 +112,15 @@ export class User extends Principal {
profilePic?: string; profilePic?: string;
/** /**
* actions * The actions performed by this user.
* For documentation purposes only, will be implemented later.
*/ */
@IsOptional() @IsOptional()
@OneToMany(() => UserAction, action => action.user, { nullable: true }) @OneToMany(() => UserAction, action => action.user, { nullable: true })
actions: UserAction[] actions: UserAction[]
/** /**
* Turn this into a response. * Turns this entity into it's response class.
*/ */
public toResponse(): ResponsePrincipal { public toResponse(): ResponsePrincipal {
return new ResponseUser(this); return new ResponseUser(this);

View File

@ -1,14 +1,17 @@
import { import {
IsEnum,
IsInt, IsInt,
IsNotEmpty, IsNotEmpty,
IsOptional, IsOptional,
IsString IsString
} from "class-validator"; } from "class-validator";
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { PermissionAction } from '../enums/PermissionAction';
import { User } from './User'; import { User } from './User';
/** /**
* Defines the UserAction interface. * Defines the UserAction entity.
* Will later be used to document a user's actions.
*/ */
@Entity() @Entity()
export class UserAction { export class UserAction {
@ -20,7 +23,7 @@ export class UserAction {
id: number; id: number;
/** /**
* user * The user that performed the action.
*/ */
@ManyToOne(() => User, user => user.actions) @ManyToOne(() => User, user => user.actions)
user: User user: User
@ -34,15 +37,16 @@ export class UserAction {
target: string; target: string;
/** /**
* The actions's action (e.g. UPDATE) * The actions's action (e.g. UPDATE).
* Directly pulled from the PermissionAction Enum.
*/ */
@Column() @Column({ type: 'varchar' })
@IsNotEmpty() @IsEnum(PermissionAction)
@IsString() action: PermissionAction;
action: string;
/** /**
* 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 }) @Column({ nullable: true })
@IsOptional() @IsOptional()

View File

@ -9,7 +9,8 @@ import { ResponseUserGroup } from '../responses/ResponseUserGroup';
import { Principal } from './Principal'; 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() @ChildEntity()
export class UserGroup extends Principal { export class UserGroup extends Principal {
@ -30,6 +31,9 @@ export class UserGroup extends Principal {
@IsString() @IsString()
description?: string; description?: string;
/**
* Turns this entity into it's response class.
*/
public toResponse(): ResponsePrincipal { public toResponse(): ResponsePrincipal {
return new ResponseUserGroup(this); return new ResponseUserGroup(this);
} }