This commit is contained in:
2025-12-12 15:20:17 +01:00
parent 2cd3bfbb47
commit ddbd99b747
4 changed files with 16 additions and 7 deletions

View File

@@ -9,10 +9,11 @@ import { RacingDomainValidationError } from '../errors/RacingDomainError';
import type { IEntity } from '@gridpilot/shared/domain'; import type { IEntity } from '@gridpilot/shared/domain';
/** /**
* Stewarding decision mode for protests * Stewarding decision mode for protests
*/ */
export type StewardingDecisionMode = export type StewardingDecisionMode =
| 'admin_only' // Only admins can decide | 'admin_only' // Only admins can decide
| 'steward_decides' // Single steward makes decision
| 'steward_vote' // X stewards must vote to uphold | 'steward_vote' // X stewards must vote to uphold
| 'member_vote' // X members must vote to uphold | 'member_vote' // X members must vote to uphold
| 'steward_veto' // Upheld unless X stewards vote against | 'steward_veto' // Upheld unless X stewards vote against

View File

@@ -72,7 +72,7 @@ export class Season implements IEntity<string> {
order?: number; order?: number;
status?: SeasonStatus; status?: SeasonStatus;
startDate?: Date; startDate?: Date;
endDate?: Date; endDate?: Date | undefined;
schedule?: SeasonSchedule; schedule?: SeasonSchedule;
scoringConfig?: SeasonScoringConfig; scoringConfig?: SeasonScoringConfig;
dropPolicy?: SeasonDropPolicy; dropPolicy?: SeasonDropPolicy;

View File

@@ -4,7 +4,7 @@ import type { StewardingDecisionMode } from '../entities/League';
export interface SeasonStewardingConfigProps { export interface SeasonStewardingConfigProps {
decisionMode: StewardingDecisionMode; decisionMode: StewardingDecisionMode;
requiredVotes?: number; requiredVotes?: number | undefined;
requireDefense: boolean; requireDefense: boolean;
defenseTimeLimit: number; defenseTimeLimit: number;
voteTimeLimit: number; voteTimeLimit: number;
@@ -54,6 +54,17 @@ export class SeasonStewardingConfig
); );
} }
// For non-voting modes, requiredVotes should not be provided
if (props.decisionMode !== 'steward_vote' &&
props.decisionMode !== 'member_vote' &&
props.decisionMode !== 'steward_veto' &&
props.decisionMode !== 'member_veto' &&
props.requiredVotes !== undefined) {
throw new RacingDomainValidationError(
'SeasonStewardingConfig.requiredVotes should only be provided for voting/veto modes',
);
}
if (!Number.isInteger(props.defenseTimeLimit) || props.defenseTimeLimit < 0) { if (!Number.isInteger(props.defenseTimeLimit) || props.defenseTimeLimit < 0) {
throw new RacingDomainValidationError( throw new RacingDomainValidationError(
'SeasonStewardingConfig.defenseTimeLimit must be a non-negative integer (hours)', 'SeasonStewardingConfig.defenseTimeLimit must be a non-negative integer (hours)',

View File

@@ -253,7 +253,6 @@ describe('SeasonScoringConfig', () => {
expect( expect(
() => () =>
new SeasonScoringConfig({ new SeasonScoringConfig({
// @ts-expect-error intentional invalid input
scoringPresetId: ' ', scoringPresetId: ' ',
}), }),
).toThrow(RacingDomainValidationError); ).toThrow(RacingDomainValidationError);
@@ -395,8 +394,6 @@ describe('SeasonStewardingConfig', () => {
() => () =>
new SeasonStewardingConfig({ new SeasonStewardingConfig({
decisionMode: mode, decisionMode: mode,
// @ts-expect-error intentional invalid
requiredVotes: undefined,
requireDefense: true, requireDefense: true,
defenseTimeLimit: 24, defenseTimeLimit: 24,
voteTimeLimit: 24, voteTimeLimit: 24,