move static data

This commit is contained in:
2025-12-26 00:20:53 +01:00
parent c977defd6a
commit b6cbb81388
63 changed files with 1482 additions and 418 deletions

View File

@@ -33,6 +33,7 @@ import { GetLeagueWalletOutputDTO } from './dtos/GetLeagueWalletOutputDTO';
import { TotalLeaguesDTO } from './dtos/TotalLeaguesDTO';
import { WithdrawFromLeagueWalletInputDTO } from './dtos/WithdrawFromLeagueWalletInputDTO';
import { WithdrawFromLeagueWalletOutputDTO } from './dtos/WithdrawFromLeagueWalletOutputDTO';
import { LeagueScoringPresetsDTO } from './dtos/LeagueScoringPresetsDTO';
@ApiTags('leagues')
@Controller('leagues')
@@ -239,8 +240,8 @@ export class LeagueController {
@Get('scoring-presets')
@ApiOperation({ summary: 'Get league scoring presets' })
@ApiResponse({ status: 200, description: 'List of scoring presets' })
async getLeagueScoringPresets() {
@ApiResponse({ status: 200, description: 'List of scoring presets', type: LeagueScoringPresetsDTO })
async getLeagueScoringPresets(): Promise<LeagueScoringPresetsDTO> {
return this.leagueService.listLeagueScoringPresets();
}

View File

@@ -1,5 +1,28 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum } from 'class-validator';
import { IsString, IsEnum, IsNumber, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
export class LeagueScoringPresetTimingDefaultsDTO {
@ApiProperty()
@IsNumber()
practiceMinutes!: number;
@ApiProperty()
@IsNumber()
qualifyingMinutes!: number;
@ApiProperty()
@IsNumber()
sprintRaceMinutes!: number;
@ApiProperty()
@IsNumber()
mainRaceMinutes!: number;
@ApiProperty()
@IsNumber()
sessionCount!: number;
}
export class LeagueScoringPresetDTO {
@ApiProperty()
@@ -29,4 +52,9 @@ export class LeagueScoringPresetDTO {
@ApiProperty()
@IsString()
dropPolicySummary!: string;
@ApiProperty({ type: LeagueScoringPresetTimingDefaultsDTO })
@ValidateNested()
@Type(() => LeagueScoringPresetTimingDefaultsDTO)
defaultTimings!: LeagueScoringPresetTimingDefaultsDTO;
}

View File

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

View File

@@ -1,10 +1,8 @@
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import type { ListLeagueScoringPresetsResult, LeagueScoringPreset } from '@core/racing/application/use-cases/ListLeagueScoringPresetsUseCase';
import type { LeagueScoringPresetsDTO } from '../dtos/LeagueScoringPresetsDTO';
export interface LeagueScoringPresetsViewModel {
presets: LeagueScoringPreset[];
totalCount: number;
}
export type LeagueScoringPresetsViewModel = LeagueScoringPresetsDTO;
export class LeagueScoringPresetsPresenter implements UseCaseOutputPort<ListLeagueScoringPresetsResult> {
private viewModel: LeagueScoringPresetsViewModel | null = null;

View File

@@ -17,6 +17,7 @@ import { FileProtestCommandDTO } from './dtos/FileProtestCommandDTO';
import { QuickPenaltyCommandDTO } from './dtos/QuickPenaltyCommandDTO';
import { ApplyPenaltyCommandDTO } from './dtos/ApplyPenaltyCommandDTO';
import { RequestProtestDefenseCommandDTO } from './dtos/RequestProtestDefenseCommandDTO';
import { PenaltyTypesReferenceDTO } from './dtos/PenaltyTypesReferenceDTO';
@ApiTags('races')
@Controller('races')
@@ -96,6 +97,13 @@ export class RaceController {
return presenter.viewModel;
}
@Get('reference/penalty-types')
@ApiOperation({ summary: 'Get allowed penalty types and semantics' })
@ApiResponse({ status: 200, description: 'Penalty types reference', type: PenaltyTypesReferenceDTO })
getPenaltyTypesReference(): PenaltyTypesReferenceDTO {
return this.raceService.getPenaltyTypesReference();
}
@Get(':raceId/penalties')
@ApiOperation({ summary: 'Get race penalties' })
@ApiParam({ name: 'raceId', description: 'Race ID' })

View File

@@ -50,6 +50,7 @@ import { FileProtestCommandDTO } from './dtos/FileProtestCommandDTO';
import { QuickPenaltyCommandDTO } from './dtos/QuickPenaltyCommandDTO';
import { RequestProtestDefenseCommandDTO } from './dtos/RequestProtestDefenseCommandDTO';
import { ReviewProtestCommandDTO } from './dtos/ReviewProtestCommandDTO';
import { PenaltyTypesReferenceDTO } from './dtos/PenaltyTypesReferenceDTO';
// Tokens
import { ApplyPenaltyUseCase } from '@core/racing/application/use-cases/ApplyPenaltyUseCase';
@@ -68,6 +69,13 @@ import {
RACES_PAGE_DATA_PRESENTER_TOKEN
} from './RaceTokens';
import {
PENALTY_TYPE_VALUES,
getPenaltyValueKind,
type PenaltyTypeValue,
} from '@core/racing/domain/entities/penalty/PenaltyType';
import { penaltyTypeRequiresValue } from '@core/racing/domain/entities/penalty/Penalty';
@Injectable()
export class RaceService {
constructor(
@@ -160,6 +168,22 @@ export class RaceService {
return this.raceProtestsPresenter;
}
getPenaltyTypesReference(): PenaltyTypesReferenceDTO {
const items = PENALTY_TYPE_VALUES.map((type: PenaltyTypeValue) => ({
type,
requiresValue: penaltyTypeRequiresValue(type),
valueKind: getPenaltyValueKind(type),
}));
return {
penaltyTypes: items,
defaultReasons: {
upheld: 'Protest upheld',
dismissed: 'Protest dismissed',
},
};
}
async getRacePenalties(raceId: string): Promise<RacePenaltiesPresenter> {
this.logger.debug('[RaceService] Fetching race penalties:', { raceId });
await this.getRacePenaltiesUseCase.execute({ raceId });

View File

@@ -1,5 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsOptional, IsNumber, IsEnum } from 'class-validator';
import { PENALTY_TYPE_VALUES } from '@core/racing/domain/entities/penalty/PenaltyType';
export class ApplyPenaltyCommandDTO {
@ApiProperty()
@@ -17,30 +18,8 @@ export class ApplyPenaltyCommandDTO {
@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',
])
@ApiProperty({ enum: PENALTY_TYPE_VALUES })
@IsEnum(PENALTY_TYPE_VALUES)
type!: string;
@ApiProperty({ required: false })

View File

@@ -0,0 +1,40 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean, IsEnum, IsString } from 'class-validator';
import {
PENALTY_TYPE_VALUES,
type PenaltyTypeValue,
} from '@core/racing/domain/entities/penalty/PenaltyType';
export type PenaltyValueKindDTO = 'seconds' | 'grid_positions' | 'points' | 'races' | 'none';
export class PenaltyTypeReferenceDTO {
@ApiProperty({ enum: PENALTY_TYPE_VALUES })
@IsEnum(PENALTY_TYPE_VALUES)
type!: PenaltyTypeValue;
@ApiProperty()
@IsBoolean()
requiresValue!: boolean;
@ApiProperty({ enum: ['seconds', 'grid_positions', 'points', 'races', 'none'] })
@IsString()
valueKind!: PenaltyValueKindDTO;
}
export class PenaltyDefaultReasonsDTO {
@ApiProperty()
@IsString()
upheld!: string;
@ApiProperty()
@IsString()
dismissed!: string;
}
export class PenaltyTypesReferenceDTO {
@ApiProperty({ type: [PenaltyTypeReferenceDTO] })
penaltyTypes!: PenaltyTypeReferenceDTO[];
@ApiProperty({ type: PenaltyDefaultReasonsDTO })
defaultReasons!: PenaltyDefaultReasonsDTO;
}