refactor
This commit is contained in:
@@ -4,9 +4,14 @@
|
||||
* Represents a league in the GridPilot platform.
|
||||
* Immutable entity with factory methods and domain validation.
|
||||
*/
|
||||
|
||||
import { RacingDomainValidationError } from '../errors/RacingDomainError';
|
||||
|
||||
import type { IEntity } from '@core/shared/domain';
|
||||
import { LeagueId } from './LeagueId';
|
||||
import { LeagueName } from './LeagueName';
|
||||
import { LeagueDescription } from './LeagueDescription';
|
||||
import { LeagueOwnerId } from './LeagueOwnerId';
|
||||
import { LeagueCreatedAt } from './LeagueCreatedAt';
|
||||
import { LeagueSocialLinks } from './LeagueSocialLinks';
|
||||
|
||||
/**
|
||||
* Stewarding decision mode for protests
|
||||
@@ -21,41 +26,41 @@ export type StewardingDecisionMode =
|
||||
|
||||
export interface StewardingSettings {
|
||||
/**
|
||||
* How protest decisions are made
|
||||
*/
|
||||
* How protest decisions are made
|
||||
*/
|
||||
decisionMode: StewardingDecisionMode;
|
||||
/**
|
||||
* Number of votes required to uphold/reject a protest
|
||||
* Used with steward_vote, member_vote, steward_veto, member_veto modes
|
||||
*/
|
||||
* Number of votes required to uphold/reject a protest
|
||||
* Used with steward_vote, member_vote, steward_veto, member_veto modes
|
||||
*/
|
||||
requiredVotes?: number;
|
||||
/**
|
||||
* Whether to require a defense from the accused before deciding
|
||||
*/
|
||||
* Whether to require a defense from the accused before deciding
|
||||
*/
|
||||
requireDefense?: boolean;
|
||||
/**
|
||||
* Time limit (hours) for accused to submit defense
|
||||
*/
|
||||
* Time limit (hours) for accused to submit defense
|
||||
*/
|
||||
defenseTimeLimit?: number;
|
||||
/**
|
||||
* Time limit (hours) for voting to complete
|
||||
*/
|
||||
* Time limit (hours) for voting to complete
|
||||
*/
|
||||
voteTimeLimit?: number;
|
||||
/**
|
||||
* Time limit (hours) after race ends when protests can be filed
|
||||
*/
|
||||
* Time limit (hours) after race ends when protests can be filed
|
||||
*/
|
||||
protestDeadlineHours?: number;
|
||||
/**
|
||||
* Time limit (hours) after race ends when stewarding is closed (no more decisions)
|
||||
*/
|
||||
* Time limit (hours) after race ends when stewarding is closed (no more decisions)
|
||||
*/
|
||||
stewardingClosesHours?: number;
|
||||
/**
|
||||
* Whether to notify the accused when a protest is filed
|
||||
*/
|
||||
* Whether to notify the accused when a protest is filed
|
||||
*/
|
||||
notifyAccusedOnProtest?: boolean;
|
||||
/**
|
||||
* Whether to notify eligible voters when a vote is required
|
||||
*/
|
||||
* Whether to notify eligible voters when a vote is required
|
||||
*/
|
||||
notifyOnVoteRequired?: boolean;
|
||||
}
|
||||
|
||||
@@ -65,38 +70,32 @@ export interface LeagueSettings {
|
||||
qualifyingFormat?: 'single-lap' | 'open';
|
||||
customPoints?: Record<number, number>;
|
||||
/**
|
||||
* Maximum number of drivers allowed in the league.
|
||||
* Used for simple capacity display on the website.
|
||||
*/
|
||||
* Maximum number of drivers allowed in the league.
|
||||
* Used for simple capacity display on the website.
|
||||
*/
|
||||
maxDrivers?: number;
|
||||
/**
|
||||
* Stewarding settings for protest handling
|
||||
*/
|
||||
* Stewarding settings for protest handling
|
||||
*/
|
||||
stewarding?: StewardingSettings;
|
||||
}
|
||||
|
||||
export interface LeagueSocialLinks {
|
||||
discordUrl?: string;
|
||||
youtubeUrl?: string;
|
||||
websiteUrl?: string;
|
||||
}
|
||||
|
||||
export class League implements IEntity<string> {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly ownerId: string;
|
||||
export class League implements IEntity<LeagueId> {
|
||||
readonly id: LeagueId;
|
||||
readonly name: LeagueName;
|
||||
readonly description: LeagueDescription;
|
||||
readonly ownerId: LeagueOwnerId;
|
||||
readonly settings: LeagueSettings;
|
||||
readonly createdAt: Date;
|
||||
readonly createdAt: LeagueCreatedAt;
|
||||
readonly socialLinks: LeagueSocialLinks | undefined;
|
||||
|
||||
private constructor(props: {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
ownerId: string;
|
||||
id: LeagueId;
|
||||
name: LeagueName;
|
||||
description: LeagueDescription;
|
||||
ownerId: LeagueOwnerId;
|
||||
settings: LeagueSettings;
|
||||
createdAt: Date;
|
||||
createdAt: LeagueCreatedAt;
|
||||
socialLinks?: LeagueSocialLinks;
|
||||
}) {
|
||||
this.id = props.id;
|
||||
@@ -118,9 +117,17 @@ export class League implements IEntity<string> {
|
||||
ownerId: string;
|
||||
settings?: Partial<LeagueSettings>;
|
||||
createdAt?: Date;
|
||||
socialLinks?: LeagueSocialLinks;
|
||||
socialLinks?: {
|
||||
discordUrl?: string;
|
||||
youtubeUrl?: string;
|
||||
websiteUrl?: string;
|
||||
};
|
||||
}): League {
|
||||
this.validate(props);
|
||||
const id = LeagueId.create(props.id);
|
||||
const name = LeagueName.create(props.name);
|
||||
const description = LeagueDescription.create(props.description);
|
||||
const ownerId = LeagueOwnerId.create(props.ownerId);
|
||||
const createdAt = LeagueCreatedAt.create(props.createdAt ?? new Date());
|
||||
|
||||
const defaultStewardingSettings: StewardingSettings = {
|
||||
decisionMode: 'admin_only',
|
||||
@@ -141,48 +148,19 @@ export class League implements IEntity<string> {
|
||||
stewarding: defaultStewardingSettings,
|
||||
};
|
||||
|
||||
const socialLinks = props.socialLinks;
|
||||
const socialLinks = props.socialLinks ? LeagueSocialLinks.create(props.socialLinks) : undefined;
|
||||
|
||||
return new League({
|
||||
id: props.id,
|
||||
name: props.name,
|
||||
description: props.description,
|
||||
ownerId: props.ownerId,
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
ownerId,
|
||||
settings: { ...defaultSettings, ...props.settings },
|
||||
createdAt: props.createdAt ?? new Date(),
|
||||
createdAt,
|
||||
...(socialLinks !== undefined ? { socialLinks } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain validation logic
|
||||
*/
|
||||
private static validate(props: {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
ownerId: string;
|
||||
}): void {
|
||||
if (!props.id || props.id.trim().length === 0) {
|
||||
throw new RacingDomainValidationError('League ID is required');
|
||||
}
|
||||
|
||||
if (!props.name || props.name.trim().length === 0) {
|
||||
throw new RacingDomainValidationError('League name is required');
|
||||
}
|
||||
|
||||
if (props.name.length > 100) {
|
||||
throw new RacingDomainValidationError('League name must be 100 characters or less');
|
||||
}
|
||||
|
||||
if (!props.description || props.description.trim().length === 0) {
|
||||
throw new RacingDomainValidationError('League description is required');
|
||||
}
|
||||
|
||||
if (!props.ownerId || props.ownerId.trim().length === 0) {
|
||||
throw new RacingDomainValidationError('League owner ID is required');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy with updated properties
|
||||
@@ -192,20 +170,25 @@ export class League implements IEntity<string> {
|
||||
description: string;
|
||||
ownerId: string;
|
||||
settings: LeagueSettings;
|
||||
socialLinks?: LeagueSocialLinks;
|
||||
socialLinks?: {
|
||||
discordUrl?: string;
|
||||
youtubeUrl?: string;
|
||||
websiteUrl?: string;
|
||||
};
|
||||
}>): League {
|
||||
const name = props.name ? LeagueName.create(props.name) : this.name;
|
||||
const description = props.description ? LeagueDescription.create(props.description) : this.description;
|
||||
const ownerId = props.ownerId ? LeagueOwnerId.create(props.ownerId) : this.ownerId;
|
||||
const socialLinks = props.socialLinks ? LeagueSocialLinks.create(props.socialLinks) : this.socialLinks;
|
||||
|
||||
return new League({
|
||||
id: this.id,
|
||||
name: props.name ?? this.name,
|
||||
description: props.description ?? this.description,
|
||||
ownerId: props.ownerId ?? this.ownerId,
|
||||
name,
|
||||
description,
|
||||
ownerId,
|
||||
settings: props.settings ?? this.settings,
|
||||
createdAt: this.createdAt,
|
||||
...(props.socialLinks !== undefined
|
||||
? { socialLinks: props.socialLinks }
|
||||
: this.socialLinks !== undefined
|
||||
? { socialLinks: this.socialLinks }
|
||||
: {}),
|
||||
...(socialLinks !== undefined ? { socialLinks } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user