This commit is contained in:
2025-12-17 14:04:11 +01:00
parent 1ea9c9649f
commit daa4bb6576
238 changed files with 4263 additions and 1752 deletions

View File

@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { RaceViewModel } from './RaceViewModel';
export class AllRacesPageDTO {
@ApiProperty({ type: [RaceViewModel] })
races!: RaceViewModel[];
@ApiProperty()
totalCount!: number;
}

View File

@@ -0,0 +1,65 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsOptional, IsNumber, IsEnum } from 'class-validator';
export class ApplyPenaltyCommandDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
driverId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
stewardId!: string;
@ApiProperty({
enum: [
'time_penalty',
'grid_penalty',
'points_deduction',
'disqualification',
'warning',
'license_points',
'probation',
'fine',
'race_ban',
],
})
@IsEnum([
'time_penalty',
'grid_penalty',
'points_deduction',
'disqualification',
'warning',
'license_points',
'probation',
'fine',
'race_ban',
])
type!: string;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
value?: number;
@ApiProperty()
@IsString()
@IsNotEmpty()
reason!: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
protestId?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
notes?: string;
}

View File

@@ -0,0 +1,47 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber, IsOptional } from 'class-validator';
export class DashboardDriverSummaryDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
name!: string;
@ApiProperty()
@IsString()
country!: string;
@ApiProperty()
@IsString()
avatarUrl!: string;
@ApiProperty({ nullable: true })
@IsOptional()
@IsNumber()
rating?: number | null;
@ApiProperty({ nullable: true })
@IsOptional()
@IsNumber()
globalRank?: number | null;
@ApiProperty()
@IsNumber()
totalRaces!: number;
@ApiProperty()
@IsNumber()
wins!: number;
@ApiProperty()
@IsNumber()
podiums!: number;
@ApiProperty({ nullable: true })
@IsOptional()
@IsNumber()
consistency?: number | null;
}

View File

@@ -0,0 +1,53 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsOptional } from 'class-validator';
export type DashboardFeedItemType =
| 'friend-joined-league'
| 'friend-joined-team'
| 'friend-finished-race'
| 'friend-new-personal-best'
| 'new-race-scheduled'
| 'new-result-posted'
| 'league-highlight';
export class DashboardFeedItemSummaryDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty({
enum: [
'friend-joined-league',
'friend-joined-team',
'friend-finished-race',
'friend-new-personal-best',
'new-race-scheduled',
'new-result-posted',
'league-highlight',
],
})
type!: DashboardFeedItemType;
@ApiProperty()
@IsString()
headline!: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
body?: string;
@ApiProperty()
@IsString()
timestamp!: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
ctaLabel?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
ctaHref?: string;
}

View File

@@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';
import { DashboardFeedItemSummaryDTO } from './DashboardFeedItemSummaryDTO';
export class DashboardFeedSummaryDTO {
@ApiProperty()
@IsNumber()
notificationCount!: number;
@ApiProperty({ type: [DashboardFeedItemSummaryDTO] })
items!: DashboardFeedItemSummaryDTO[];
}

View File

@@ -0,0 +1,20 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class DashboardFriendSummaryDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
name!: string;
@ApiProperty()
@IsString()
country!: string;
@ApiProperty()
@IsString()
avatarUrl!: string;
}

View File

@@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber } from 'class-validator';
export class DashboardLeagueStandingSummaryDTO {
@ApiProperty()
@IsString()
leagueId!: string;
@ApiProperty()
@IsString()
leagueName!: string;
@ApiProperty()
@IsNumber()
position!: number;
@ApiProperty()
@IsNumber()
totalDrivers!: number;
@ApiProperty()
@IsNumber()
points!: number;
}

View File

@@ -0,0 +1,41 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsOptional } from 'class-validator';
import { DashboardDriverSummaryDTO } from './DashboardDriverSummaryDTO';
import { DashboardRaceSummaryDTO } from './DashboardRaceSummaryDTO';
import { DashboardRecentResultDTO } from './DashboardRecentResultDTO';
import { DashboardLeagueStandingSummaryDTO } from './DashboardLeagueStandingSummaryDTO';
import { DashboardFeedSummaryDTO } from './DashboardFeedSummaryDTO';
import { DashboardFriendSummaryDTO } from './DashboardFriendSummaryDTO';
export class DashboardOverviewDTO {
@ApiProperty({ nullable: true })
currentDriver!: DashboardDriverSummaryDTO | null;
@ApiProperty({ type: [DashboardRaceSummaryDTO] })
myUpcomingRaces!: DashboardRaceSummaryDTO[];
@ApiProperty({ type: [DashboardRaceSummaryDTO] })
otherUpcomingRaces!: DashboardRaceSummaryDTO[];
@ApiProperty({ type: [DashboardRaceSummaryDTO] })
upcomingRaces!: DashboardRaceSummaryDTO[];
@ApiProperty()
@IsNumber()
activeLeaguesCount!: number;
@ApiProperty({ nullable: true })
nextRace!: DashboardRaceSummaryDTO | null;
@ApiProperty({ type: [DashboardRecentResultDTO] })
recentResults!: DashboardRecentResultDTO[];
@ApiProperty({ type: [DashboardLeagueStandingSummaryDTO] })
leagueStandingsSummaries!: DashboardLeagueStandingSummaryDTO[];
@ApiProperty()
feedSummary!: DashboardFeedSummaryDTO;
@ApiProperty({ type: [DashboardFriendSummaryDTO] })
friends!: DashboardFriendSummaryDTO[];
}

View File

@@ -0,0 +1,36 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsBoolean } from 'class-validator';
export class DashboardRaceSummaryDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
leagueId!: string;
@ApiProperty()
@IsString()
leagueName!: string;
@ApiProperty()
@IsString()
track!: string;
@ApiProperty()
@IsString()
car!: string;
@ApiProperty()
@IsString()
scheduledAt!: string;
@ApiProperty({ enum: ['scheduled', 'running', 'completed', 'cancelled'] })
@IsString()
status!: 'scheduled' | 'running' | 'completed' | 'cancelled';
@ApiProperty()
@IsBoolean()
isMyLeague!: boolean;
}

View File

@@ -0,0 +1,32 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber } from 'class-validator';
export class DashboardRecentResultDTO {
@ApiProperty()
@IsString()
raceId!: string;
@ApiProperty()
@IsString()
raceName!: string;
@ApiProperty()
@IsString()
leagueId!: string;
@ApiProperty()
@IsString()
leagueName!: string;
@ApiProperty()
@IsString()
finishedAt!: string;
@ApiProperty()
@IsNumber()
position!: number;
@ApiProperty()
@IsNumber()
incidents!: number;
}

View File

@@ -0,0 +1,37 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsOptional, IsNumber, IsUrl } from 'class-validator';
export class FileProtestCommandDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
protestingDriverId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
accusedDriverId!: string;
@ApiProperty()
incident!: {
lap: number;
description: string;
timeInRace?: number;
};
@ApiProperty({ required: false })
@IsOptional()
@IsString()
comment?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
proofVideoUrl?: string;
}

View File

@@ -0,0 +1,14 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
export class GetRaceDetailParamsDTODTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
driverId!: string;
}

View File

@@ -0,0 +1,14 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
export class ImportRaceResultsDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
resultsFileContent!: string;
}

View File

@@ -0,0 +1,23 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean, IsString, IsNumber } from 'class-validator';
export class ImportRaceResultsSummaryDTOViewModel {
@ApiProperty()
@IsBoolean()
success!: boolean;
@ApiProperty()
@IsString()
raceId!: string;
@ApiProperty()
@IsNumber()
driversProcessed!: number;
@ApiProperty()
@IsNumber()
resultsRecorded!: number;
@ApiProperty({ type: [String], required: false })
errors?: string[];
}

View File

@@ -0,0 +1,32 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsOptional, IsEnum } from 'class-validator';
export class QuickPenaltyCommandDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
driverId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
adminId!: string;
@ApiProperty({ enum: ['track_limits', 'unsafe_rejoin', 'aggressive_driving', 'false_start', 'other'] })
@IsEnum(['track_limits', 'unsafe_rejoin', 'aggressive_driving', 'false_start', 'other'])
infractionType!: 'track_limits' | 'unsafe_rejoin' | 'aggressive_driving' | 'false_start' | 'other';
@ApiProperty({ enum: ['warning', 'minor', 'major', 'severe'] })
@IsEnum(['warning', 'minor', 'major', 'severe'])
severity!: 'warning' | 'minor' | 'major' | 'severe';
@ApiProperty({ required: false })
@IsOptional()
@IsString()
notes?: string;
}

View File

@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
export class RaceActionParamsDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
}

View File

@@ -0,0 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
export class RaceDTO {
@ApiProperty()
id!: string;
@ApiProperty()
name!: string;
@ApiProperty()
date!: string;
@ApiProperty({ nullable: true })
leagueName?: string;
}

View File

@@ -0,0 +1,29 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional, IsString } from 'class-validator';
import { RaceDetailRaceDTO } from './RaceDetailRaceDTO';
import { RaceDetailLeagueDTO } from './RaceDetailLeagueDTO';
import { RaceDetailEntryDTO } from './RaceDetailEntryDTO';
import { RaceDetailRegistrationDTO } from './RaceDetailRegistrationDTO';
import { RaceDetailUserResultDTO } from './RaceDetailUserResultDTO';
export class RaceDetailDTO {
@ApiProperty({ nullable: true })
race!: RaceDetailRaceDTO | null;
@ApiProperty({ nullable: true })
league!: RaceDetailLeagueDTO | null;
@ApiProperty({ type: [RaceDetailEntryDTO] })
entryList!: RaceDetailEntryDTO[];
@ApiProperty()
registration!: RaceDetailRegistrationDTO;
@ApiProperty({ nullable: true })
userResult!: RaceDetailUserResultDTO | null;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
error?: string;
}

View File

@@ -0,0 +1,27 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsBoolean, IsNumber } from 'class-validator';
export class RaceDetailEntryDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
name!: string;
@ApiProperty()
@IsString()
country!: string;
@ApiProperty()
@IsString()
avatarUrl!: string;
@ApiProperty({ nullable: true })
rating!: number | null;
@ApiProperty()
@IsBoolean()
isCurrentUser!: boolean;
}

View File

@@ -0,0 +1,22 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class RaceDetailLeagueDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
name!: string;
@ApiProperty()
@IsString()
description!: string;
@ApiProperty()
settings!: {
maxDrivers?: number;
qualifyingFormat?: string;
};
}

View File

@@ -0,0 +1,45 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsOptional, IsNumber } from 'class-validator';
export class RaceDetailRaceDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
leagueId!: string;
@ApiProperty()
@IsString()
track!: string;
@ApiProperty()
@IsString()
car!: string;
@ApiProperty()
@IsString()
scheduledAt!: string;
@ApiProperty()
@IsString()
sessionType!: string;
@ApiProperty()
@IsString()
status!: string;
@ApiProperty({ nullable: true })
strengthOfField!: number | null;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
registeredCount?: number;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
maxParticipants?: number;
}

View File

@@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean } from 'class-validator';
export class RaceDetailRegistrationDTO {
@ApiProperty()
@IsBoolean()
isUserRegistered!: boolean;
@ApiProperty()
@IsBoolean()
canRegister!: boolean;
}

View File

@@ -0,0 +1,35 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsBoolean } from 'class-validator';
export class RaceDetailUserResultDTO {
@ApiProperty()
@IsNumber()
position!: number;
@ApiProperty()
@IsNumber()
startPosition!: number;
@ApiProperty()
@IsNumber()
incidents!: number;
@ApiProperty()
@IsNumber()
fastestLap!: number;
@ApiProperty()
@IsNumber()
positionChange!: number;
@ApiProperty()
@IsBoolean()
isPodium!: boolean;
@ApiProperty()
@IsBoolean()
isClean!: boolean;
@ApiProperty({ nullable: true })
ratingChange!: number | null;
}

View File

@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { RacePenaltyDTO } from './RacePenaltyDTO';
export class RacePenaltiesDTO {
@ApiProperty({ type: [RacePenaltyDTO] })
penalties!: RacePenaltyDTO[];
@ApiProperty()
driverMap!: Record<string, string>;
}

View File

@@ -0,0 +1,35 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber } from 'class-validator';
export class RacePenaltyDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
driverId!: string;
@ApiProperty()
@IsString()
type!: string;
@ApiProperty()
@IsNumber()
value!: number;
@ApiProperty()
@IsString()
reason!: string;
@ApiProperty()
@IsString()
issuedBy!: string;
@ApiProperty()
@IsString()
issuedAt!: string;
@ApiProperty({ nullable: true })
notes?: string;
}

View File

@@ -0,0 +1,30 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class RaceProtestDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
protestingDriverId!: string;
@ApiProperty()
@IsString()
accusedDriverId!: string;
@ApiProperty()
incident!: {
lap: number;
description: string;
};
@ApiProperty()
@IsString()
status!: string;
@ApiProperty()
@IsString()
filedAt!: string;
}

View File

@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { RaceProtestDto } from './RaceProtestDto';
export class RaceProtestsDTO {
@ApiProperty({ type: [RaceProtestDto] })
protests!: RaceProtestDto[];
@ApiProperty()
driverMap!: Record<string, string>;
}

View File

@@ -0,0 +1,44 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber, IsBoolean } from 'class-validator';
export class RaceResultDTO {
@ApiProperty()
@IsString()
driverId!: string;
@ApiProperty()
@IsString()
driverName!: string;
@ApiProperty()
@IsString()
avatarUrl!: string;
@ApiProperty()
@IsNumber()
position!: number;
@ApiProperty()
@IsNumber()
startPosition!: number;
@ApiProperty()
@IsNumber()
incidents!: number;
@ApiProperty()
@IsNumber()
fastestLap!: number;
@ApiProperty()
@IsNumber()
positionChange!: number;
@ApiProperty()
@IsBoolean()
isPodium!: boolean;
@ApiProperty()
@IsBoolean()
isClean!: boolean;
}

View File

@@ -0,0 +1,16 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { RaceResultDto } from './RaceResultDto';
export class RaceResultsDetailDTO {
@ApiProperty()
@IsString()
raceId!: string;
@ApiProperty()
@IsString()
track!: string;
@ApiProperty({ type: [RaceResultDto] })
results!: RaceResultDto[];
}

View File

@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class RaceStatsDTO {
@ApiProperty()
totalRaces!: number;
}

View File

@@ -0,0 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class RaceWithSOFDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
track!: string;
@ApiProperty({ nullable: true })
strengthOfField!: number | null;
}

View File

@@ -0,0 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { RacesPageDataRaceDto } from './RacesPageDataRaceDto';
export class RacesPageDataDTO {
@ApiProperty({ type: [RacesPageDataRaceDto] })
races!: RacesPageDataRaceDto[];
}

View File

@@ -0,0 +1,47 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsBoolean } from 'class-validator';
export class RacesPageDataRaceDTO {
@ApiProperty()
@IsString()
id!: string;
@ApiProperty()
@IsString()
track!: string;
@ApiProperty()
@IsString()
car!: string;
@ApiProperty()
@IsString()
scheduledAt!: string;
@ApiProperty()
@IsString()
status!: string;
@ApiProperty()
@IsString()
leagueId!: string;
@ApiProperty()
@IsString()
leagueName!: string;
@ApiProperty({ nullable: true })
strengthOfField!: number | null;
@ApiProperty()
@IsBoolean()
isUpcoming!: boolean;
@ApiProperty()
@IsBoolean()
isLive!: boolean;
@ApiProperty()
@IsBoolean()
isPast!: boolean;
}

View File

@@ -0,0 +1,19 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
export class RegisterForRaceParamsDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
leagueId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
driverId!: string;
}

View File

@@ -0,0 +1,14 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
export class RequestProtestDefenseCommandDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
protestId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
stewardId!: string;
}

View File

@@ -0,0 +1,14 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty } from 'class-validator';
export class WithdrawFromRaceParamsDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
raceId!: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
driverId!: string;
}