wip
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { ParticipantRef } from '@gridpilot/racing/domain/value-objects/ParticipantRef';
|
||||
import type { ParticipantRef } from '@gridpilot/racing/domain/types/ParticipantRef';
|
||||
|
||||
export interface ChampionshipStandingsRowDTO {
|
||||
participant: ParticipantRef;
|
||||
|
||||
@@ -53,9 +53,9 @@ export interface LeagueTimingsFormDTO {
|
||||
timezoneId?: string; // IANA ID, e.g. "Europe/Berlin", or "track" for track local time
|
||||
recurrenceStrategy?: 'weekly' | 'everyNWeeks' | 'monthlyNthWeekday';
|
||||
intervalWeeks?: number;
|
||||
weekdays?: import('../../domain/value-objects/Weekday').Weekday[];
|
||||
weekdays?: import('../../domain/types/Weekday').Weekday[];
|
||||
monthlyOrdinal?: 1 | 2 | 3 | 4;
|
||||
monthlyWeekday?: import('../../domain/value-objects/Weekday').Weekday;
|
||||
monthlyWeekday?: import('../../domain/types/Weekday').Weekday;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { LeagueTimingsFormDTO } from './LeagueConfigFormDTO';
|
||||
import type { Weekday } from '../../domain/value-objects/Weekday';
|
||||
import type { Weekday } from '../../domain/types/Weekday';
|
||||
import { RaceTimeOfDay } from '../../domain/value-objects/RaceTimeOfDay';
|
||||
import { LeagueTimezone } from '../../domain/value-objects/LeagueTimezone';
|
||||
import { WeekdaySet } from '../../domain/value-objects/WeekdaySet';
|
||||
import { MonthlyRecurrencePattern } from '../../domain/value-objects/MonthlyRecurrencePattern';
|
||||
import type { RecurrenceStrategy } from '../../domain/value-objects/RecurrenceStrategy';
|
||||
import { RecurrenceStrategyFactory } from '../../domain/value-objects/RecurrenceStrategy';
|
||||
import type { RecurrenceStrategy } from '../../domain/types/RecurrenceStrategy';
|
||||
import { RecurrenceStrategyFactory } from '../../domain/types/RecurrenceStrategy';
|
||||
import { SeasonSchedule } from '../../domain/value-objects/SeasonSchedule';
|
||||
import { BusinessRuleViolationError } from '../errors/RacingApplicationError';
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { Team, TeamJoinRequest, TeamMembership } from '../../domain/entities/Team';
|
||||
import type { Team } from '../../domain/entities/Team';
|
||||
import type {
|
||||
TeamJoinRequest,
|
||||
TeamMembership,
|
||||
} from '../../domain/types/TeamMembership';
|
||||
|
||||
export interface JoinTeamCommandDTO {
|
||||
teamId: string;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
export abstract class RacingApplicationError extends Error {
|
||||
import type { IApplicationError, CommonApplicationErrorKind } from '@gridpilot/shared/errors';
|
||||
|
||||
export abstract class RacingApplicationError
|
||||
extends Error
|
||||
implements IApplicationError<CommonApplicationErrorKind | string, unknown>
|
||||
{
|
||||
readonly type = 'application' as const;
|
||||
readonly context = 'racing-application';
|
||||
abstract readonly kind: CommonApplicationErrorKind | string;
|
||||
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
@@ -22,11 +29,16 @@ export interface EntityNotFoundDetails {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class EntityNotFoundError extends RacingApplicationError {
|
||||
export class EntityNotFoundError
|
||||
extends RacingApplicationError
|
||||
implements IApplicationError<'not_found', EntityNotFoundDetails>
|
||||
{
|
||||
readonly kind = 'not_found' as const;
|
||||
readonly details: EntityNotFoundDetails;
|
||||
|
||||
constructor(public readonly details: EntityNotFoundDetails) {
|
||||
constructor(details: EntityNotFoundDetails) {
|
||||
super(`${details.entity} not found for id: ${details.id}`);
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,15 +51,25 @@ export type PermissionDeniedReason =
|
||||
| 'TEAM_OWNER_CANNOT_LEAVE'
|
||||
| 'UNAUTHORIZED';
|
||||
|
||||
export class PermissionDeniedError extends RacingApplicationError {
|
||||
export class PermissionDeniedError
|
||||
extends RacingApplicationError
|
||||
implements IApplicationError<'forbidden', PermissionDeniedReason>
|
||||
{
|
||||
readonly kind = 'forbidden' as const;
|
||||
|
||||
constructor(public readonly reason: PermissionDeniedReason, message?: string) {
|
||||
super(message ?? `Permission denied: ${reason}`);
|
||||
}
|
||||
|
||||
get details(): PermissionDeniedReason {
|
||||
return this.reason;
|
||||
}
|
||||
}
|
||||
|
||||
export class BusinessRuleViolationError extends RacingApplicationError {
|
||||
export class BusinessRuleViolationError
|
||||
extends RacingApplicationError
|
||||
implements IApplicationError<'conflict', undefined>
|
||||
{
|
||||
readonly kind = 'conflict' as const;
|
||||
|
||||
constructor(message: string) {
|
||||
|
||||
@@ -54,13 +54,13 @@ export * from './ports/DriverRatingProvider';
|
||||
|
||||
export type { RaceRegistration } from '../domain/entities/RaceRegistration';
|
||||
|
||||
export type { Team } from '../domain/entities/Team';
|
||||
export type {
|
||||
Team,
|
||||
TeamMembership,
|
||||
TeamJoinRequest,
|
||||
TeamRole,
|
||||
TeamMembershipStatus,
|
||||
} from '../domain/entities/Team';
|
||||
} from '../domain/types/TeamMembership';
|
||||
|
||||
export type { DriverDTO } from './dto/DriverDTO';
|
||||
export type { LeagueDTO } from './dto/LeagueDTO';
|
||||
|
||||
12
packages/racing/application/ports/IImageServicePort.ts
Normal file
12
packages/racing/application/ports/IImageServicePort.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Application Port: IImageServicePort
|
||||
*
|
||||
* Abstraction used by racing application use cases to obtain image URLs
|
||||
* for drivers, teams and leagues without depending on UI/media layers.
|
||||
*/
|
||||
export interface IImageServicePort {
|
||||
getDriverAvatar(driverId: string): string;
|
||||
getTeamLogo(teamId: string): string;
|
||||
getLeagueCover(leagueId: string): string;
|
||||
getLeagueLogo(leagueId: string): string;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Team, TeamMembership } from '../../domain/entities/Team';
|
||||
import type { Team } from '../../domain/entities/Team';
|
||||
import type { TeamMembership } from '../../domain/types/TeamMembership';
|
||||
|
||||
export interface DriverTeamViewModel {
|
||||
team: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Team, TeamMembership } from '../../domain/entities/Team';
|
||||
import type { Team } from '../../domain/entities/Team';
|
||||
import type { TeamMembership } from '../../domain/types/TeamMembership';
|
||||
|
||||
export interface TeamDetailsViewModel {
|
||||
team: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TeamJoinRequest } from '../../domain/entities/Team';
|
||||
import type { TeamJoinRequest } from '../../domain/types/TeamMembership';
|
||||
|
||||
export interface TeamJoinRequestViewModel {
|
||||
requestId: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TeamMembership } from '../../domain/entities/Team';
|
||||
import type { TeamMembership } from '../../domain/types/TeamMembership';
|
||||
|
||||
export interface TeamMemberViewModel {
|
||||
driverId: string;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';
|
||||
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
|
||||
import { SeasonSponsorship } from '../../domain/entities/SeasonSponsorship';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export interface AcceptSponsorshipRequestDTO {
|
||||
requestId: string;
|
||||
@@ -23,7 +24,8 @@ export interface AcceptSponsorshipRequestResultDTO {
|
||||
netAmount: number;
|
||||
}
|
||||
|
||||
export class AcceptSponsorshipRequestUseCase {
|
||||
export class AcceptSponsorshipRequestUseCase
|
||||
implements AsyncUseCase<AcceptSponsorshipRequestDTO, AcceptSponsorshipRequestResultDTO> {
|
||||
constructor(
|
||||
private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
private readonly seasonSponsorshipRepo: ISeasonSponsorshipRepository,
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { ISponsorshipRequestRepository } from '../../domain/repositories/IS
|
||||
import type { ISponsorshipPricingRepository } from '../../domain/repositories/ISponsorshipPricingRepository';
|
||||
import type { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
|
||||
import { Money, type Currency } from '../../domain/value-objects/Money';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import {
|
||||
EntityNotFoundError,
|
||||
BusinessRuleViolationError,
|
||||
@@ -31,8 +32,10 @@ export interface ApplyForSponsorshipResultDTO {
|
||||
status: 'pending';
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export class ApplyForSponsorshipUseCase {
|
||||
|
||||
export class ApplyForSponsorshipUseCase
|
||||
implements AsyncUseCase<ApplyForSponsorshipDTO, ApplyForSponsorshipResultDTO>
|
||||
{
|
||||
constructor(
|
||||
private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
private readonly sponsorshipPricingRepo: ISponsorshipPricingRepository,
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { IProtestRepository } from '../../domain/repositories/IProtestRepos
|
||||
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import { randomUUID } from 'crypto';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export interface ApplyPenaltyCommand {
|
||||
raceId: string;
|
||||
@@ -23,7 +24,8 @@ export interface ApplyPenaltyCommand {
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export class ApplyPenaltyUseCase {
|
||||
export class ApplyPenaltyUseCase
|
||||
implements AsyncUseCase<ApplyPenaltyCommand, { penaltyId: string }> {
|
||||
constructor(
|
||||
private readonly penaltyRepository: IPenaltyRepository,
|
||||
private readonly protestRepository: IProtestRepository,
|
||||
|
||||
@@ -4,10 +4,12 @@ import type {
|
||||
TeamMembershipStatus,
|
||||
TeamRole,
|
||||
TeamJoinRequest,
|
||||
} from '../../domain/entities/Team';
|
||||
} from '../../domain/types/TeamMembership';
|
||||
import type { ApproveTeamJoinRequestCommandDTO } from '../dto/TeamCommandAndQueryDTO';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export class ApproveTeamJoinRequestUseCase {
|
||||
export class ApproveTeamJoinRequestUseCase
|
||||
implements AsyncUseCase<ApproveTeamJoinRequestCommandDTO, void> {
|
||||
constructor(
|
||||
private readonly membershipRepository: ITeamMembershipRepository,
|
||||
) {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case: CancelRaceUseCase
|
||||
@@ -13,7 +14,8 @@ export interface CancelRaceCommandDTO {
|
||||
raceId: string;
|
||||
}
|
||||
|
||||
export class CancelRaceUseCase {
|
||||
export class CancelRaceUseCase
|
||||
implements AsyncUseCase<CancelRaceCommandDTO, void> {
|
||||
constructor(
|
||||
private readonly raceRepository: IRaceRepository,
|
||||
) {}
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { ILeagueRepository } from '../../domain/repositories/ILeagueReposit
|
||||
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
|
||||
import type { ILeagueScoringConfigRepository } from '../../domain/repositories/ILeagueScoringConfigRepository';
|
||||
import type { LeagueScoringConfig } from '../../domain/entities/LeagueScoringConfig';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import type {
|
||||
LeagueScoringPresetProvider,
|
||||
LeagueScoringPresetDTO,
|
||||
@@ -47,7 +48,8 @@ export interface CreateLeagueWithSeasonAndScoringResultDTO {
|
||||
scoringPresetName?: string;
|
||||
}
|
||||
|
||||
export class CreateLeagueWithSeasonAndScoringUseCase {
|
||||
export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
implements AsyncUseCase<CreateLeagueWithSeasonAndScoringCommand, CreateLeagueWithSeasonAndScoringResultDTO> {
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly seasonRepository: ISeasonRepository,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import { Team } from '../../domain/entities/Team';
|
||||
import type {
|
||||
Team,
|
||||
TeamMembership,
|
||||
TeamMembershipStatus,
|
||||
TeamRole,
|
||||
} from '../../domain/entities/Team';
|
||||
} from '../../domain/types/TeamMembership';
|
||||
import type {
|
||||
CreateTeamCommandDTO,
|
||||
CreateTeamResultDTO,
|
||||
|
||||
@@ -5,12 +5,15 @@ import type { ILeagueScoringConfigRepository } from '../../domain/repositories/I
|
||||
import type { IGameRepository } from '../../domain/repositories/IGameRepository';
|
||||
import type { LeagueScoringPresetProvider } from '../ports/LeagueScoringPresetProvider';
|
||||
import type { IAllLeaguesWithCapacityAndScoringPresenter, LeagueEnrichedData } from '../presenters/IAllLeaguesWithCapacityAndScoringPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving all leagues with capacity and scoring information.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetAllLeaguesWithCapacityAndScoringUseCase {
|
||||
export class GetAllLeaguesWithCapacityAndScoringUseCase
|
||||
implements AsyncUseCase<void, void>
|
||||
{
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly leagueMembershipRepository: ILeagueMembershipRepository,
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import type { IAllLeaguesWithCapacityPresenter } from '../presenters/IAllLeaguesWithCapacityPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving all leagues with capacity information.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetAllLeaguesWithCapacityUseCase {
|
||||
export class GetAllLeaguesWithCapacityUseCase
|
||||
implements AsyncUseCase<void, void>
|
||||
{
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly leagueMembershipRepository: ILeagueMembershipRepository,
|
||||
|
||||
@@ -6,8 +6,10 @@ import type {
|
||||
AllRacesListItemViewModel,
|
||||
AllRacesFilterOptionsViewModel,
|
||||
} from '../presenters/IAllRacesPagePresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export class GetAllRacesPageDataUseCase {
|
||||
export class GetAllRacesPageDataUseCase
|
||||
implements AsyncUseCase<void, void> {
|
||||
constructor(
|
||||
private readonly raceRepository: IRaceRepository,
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { IAllTeamsPresenter } from '../presenters/IAllTeamsPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving all teams.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetAllTeamsUseCase {
|
||||
export class GetAllTeamsUseCase
|
||||
implements AsyncUseCase<void, void> {
|
||||
constructor(
|
||||
private readonly teamRepository: ITeamRepository,
|
||||
private readonly teamMembershipRepository: ITeamMembershipRepository,
|
||||
|
||||
@@ -5,9 +5,10 @@ import type { ILeagueRepository } from '../../domain/repositories/ILeagueReposit
|
||||
import type { IStandingRepository } from '../../domain/repositories/IStandingRepository';
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import type { IRaceRegistrationRepository } from '../../domain/repositories/IRaceRegistrationRepository';
|
||||
import type { IImageService } from '../../domain/services/IImageService';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
import type { IFeedRepository } from '@gridpilot/social/domain/repositories/IFeedRepository';
|
||||
import type { ISocialGraphRepository } from '@gridpilot/social/domain/repositories/ISocialGraphRepository';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import type {
|
||||
IDashboardOverviewPresenter,
|
||||
DashboardOverviewViewModel,
|
||||
@@ -33,7 +34,8 @@ export interface GetDashboardOverviewParams {
|
||||
driverId: string;
|
||||
}
|
||||
|
||||
export class GetDashboardOverviewUseCase {
|
||||
export class GetDashboardOverviewUseCase
|
||||
implements AsyncUseCase<GetDashboardOverviewParams, void> {
|
||||
constructor(
|
||||
private readonly driverRepository: IDriverRepository,
|
||||
private readonly raceRepository: IRaceRepository,
|
||||
@@ -44,7 +46,7 @@ export class GetDashboardOverviewUseCase {
|
||||
private readonly raceRegistrationRepository: IRaceRegistrationRepository,
|
||||
private readonly feedRepository: IFeedRepository,
|
||||
private readonly socialRepository: ISocialGraphRepository,
|
||||
private readonly imageService: IImageService,
|
||||
private readonly imageService: IImageServicePort,
|
||||
private readonly getDriverStats: (driverId: string) => DashboardDriverStatsAdapter | null,
|
||||
public readonly presenter: IDashboardOverviewPresenter,
|
||||
) {}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { IDriverTeamPresenter } from '../presenters/IDriverTeamPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving a driver's team.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetDriverTeamUseCase {
|
||||
export class GetDriverTeamUseCase
|
||||
implements AsyncUseCase<string, boolean> {
|
||||
constructor(
|
||||
private readonly teamRepository: ITeamRepository,
|
||||
private readonly membershipRepository: ITeamMembershipRepository,
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
|
||||
import type { IRankingService } from '../../domain/services/IRankingService';
|
||||
import type { IDriverStatsService } from '../../domain/services/IDriverStatsService';
|
||||
import type { IImageService } from '../../domain/services/IImageService';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
import type { IDriversLeaderboardPresenter } from '../presenters/IDriversLeaderboardPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving driver leaderboard data.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetDriversLeaderboardUseCase {
|
||||
export class GetDriversLeaderboardUseCase
|
||||
implements AsyncUseCase<void, void> {
|
||||
constructor(
|
||||
private readonly driverRepository: IDriverRepository,
|
||||
private readonly rankingService: IRankingService,
|
||||
private readonly driverStatsService: IDriverStatsService,
|
||||
private readonly imageService: IImageService,
|
||||
private readonly imageService: IImageServicePort,
|
||||
public readonly presenter: IDriversLeaderboardPresenter,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISe
|
||||
import type { SponsorableEntityType } from '../../domain/entities/SponsorshipRequest';
|
||||
import type { SponsorshipTier } from '../../domain/entities/SeasonSponsorship';
|
||||
import type { IEntitySponsorshipPricingPresenter } from '../presenters/IEntitySponsorshipPricingPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export interface GetEntitySponsorshipPricingDTO {
|
||||
entityType: SponsorableEntityType;
|
||||
@@ -38,7 +39,8 @@ export interface GetEntitySponsorshipPricingResultDTO {
|
||||
secondarySlot?: SponsorshipSlotDTO;
|
||||
}
|
||||
|
||||
export class GetEntitySponsorshipPricingUseCase {
|
||||
export class GetEntitySponsorshipPricingUseCase
|
||||
implements AsyncUseCase<GetEntitySponsorshipPricingDTO, void> {
|
||||
constructor(
|
||||
private readonly sponsorshipPricingRepo: ISponsorshipPricingRepository,
|
||||
private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { IResultRepository } from '../../domain/repositories/IResultReposit
|
||||
import type { IPenaltyRepository } from '../../domain/repositories/IPenaltyRepository';
|
||||
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
||||
import type { ILeagueDriverSeasonStatsPresenter } from '../presenters/ILeagueDriverSeasonStatsPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export interface DriverRatingPort {
|
||||
getRating(driverId: string): { rating: number | null; ratingChange: number | null };
|
||||
@@ -16,7 +17,8 @@ export interface GetLeagueDriverSeasonStatsUseCaseParams {
|
||||
* Use Case for retrieving league driver season statistics.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetLeagueDriverSeasonStatsUseCase {
|
||||
export class GetLeagueDriverSeasonStatsUseCase
|
||||
implements AsyncUseCase<GetLeagueDriverSeasonStatsUseCaseParams, void> {
|
||||
constructor(
|
||||
private readonly standingRepository: IStandingRepository,
|
||||
private readonly resultRepository: IResultRepository,
|
||||
|
||||
@@ -3,13 +3,16 @@ import type { ISeasonRepository } from '../../domain/repositories/ISeasonReposit
|
||||
import type { ILeagueScoringConfigRepository } from '../../domain/repositories/ILeagueScoringConfigRepository';
|
||||
import type { IGameRepository } from '../../domain/repositories/IGameRepository';
|
||||
import type { ILeagueFullConfigPresenter, LeagueFullConfigData } from '../presenters/ILeagueFullConfigPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import { EntityNotFoundError } from '../errors/RacingApplicationError';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving a league's full configuration.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetLeagueFullConfigUseCase {
|
||||
export class GetLeagueFullConfigUseCase
|
||||
implements AsyncUseCase<{ leagueId: string }, void>
|
||||
{
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly seasonRepository: ISeasonRepository,
|
||||
|
||||
@@ -4,12 +4,14 @@ import type { ILeagueScoringConfigRepository } from '../../domain/repositories/I
|
||||
import type { IGameRepository } from '../../domain/repositories/IGameRepository';
|
||||
import type { LeagueScoringPresetProvider } from '../ports/LeagueScoringPresetProvider';
|
||||
import type { ILeagueScoringConfigPresenter, LeagueScoringConfigData } from '../presenters/ILeagueScoringConfigPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving a league's scoring configuration for its active season.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetLeagueScoringConfigUseCase {
|
||||
export class GetLeagueScoringConfigUseCase
|
||||
implements AsyncUseCase<{ leagueId: string }, void> {
|
||||
constructor(
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
private readonly seasonRepository: ISeasonRepository,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { IStandingRepository } from '../../domain/repositories/IStandingRepository';
|
||||
import type { ILeagueStandingsPresenter } from '../presenters/ILeagueStandingsPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
|
||||
export interface GetLeagueStandingsUseCaseParams {
|
||||
leagueId: string;
|
||||
@@ -9,7 +10,8 @@ export interface GetLeagueStandingsUseCaseParams {
|
||||
* Use Case for retrieving league standings.
|
||||
* Orchestrates domain logic and delegates presentation to the presenter.
|
||||
*/
|
||||
export class GetLeagueStandingsUseCase {
|
||||
export class GetLeagueStandingsUseCase
|
||||
implements AsyncUseCase<GetLeagueStandingsUseCaseParams, void> {
|
||||
constructor(
|
||||
private readonly standingRepository: IStandingRepository,
|
||||
public readonly presenter: ILeagueStandingsPresenter,
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { IRaceRepository } from '../../domain/repositories/IRaceRepository'
|
||||
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
|
||||
import type { DriverRatingProvider } from '../ports/DriverRatingProvider';
|
||||
import type { ILeagueStatsPresenter } from '../presenters/ILeagueStatsPresenter';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import {
|
||||
AverageStrengthOfFieldCalculator,
|
||||
type StrengthOfFieldCalculator,
|
||||
@@ -20,7 +21,8 @@ export interface GetLeagueStatsUseCaseParams {
|
||||
/**
|
||||
* Use Case for retrieving league statistics including average SOF across completed races.
|
||||
*/
|
||||
export class GetLeagueStatsUseCase {
|
||||
export class GetLeagueStatsUseCase
|
||||
implements AsyncUseCase<GetLeagueStatsUseCaseParams, void> {
|
||||
private readonly sofCalculator: StrengthOfFieldCalculator;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
|
||||
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { IImageService } from '../../domain/services/IImageService';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
import type { ISocialGraphRepository } from '@gridpilot/social/domain/repositories/ISocialGraphRepository';
|
||||
import type {
|
||||
IProfileOverviewPresenter,
|
||||
@@ -44,7 +44,7 @@ export class GetProfileOverviewUseCase {
|
||||
private readonly teamRepository: ITeamRepository,
|
||||
private readonly teamMembershipRepository: ITeamMembershipRepository,
|
||||
private readonly socialRepository: ISocialGraphRepository,
|
||||
private readonly imageService: IImageService,
|
||||
private readonly imageService: IImageServicePort,
|
||||
private readonly getDriverStats: (driverId: string) => ProfileDriverStatsAdapter | null,
|
||||
private readonly getAllDriverRankings: () => DriverRankingEntry[],
|
||||
public readonly presenter: IProfileOverviewPresenter,
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { IRaceRegistrationRepository } from '../../domain/repositories/IRac
|
||||
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import type { DriverRatingProvider } from '../ports/DriverRatingProvider';
|
||||
import type { IImageService } from '../../domain/services/IImageService';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
import type {
|
||||
IRaceDetailPresenter,
|
||||
RaceDetailViewModel,
|
||||
@@ -39,7 +39,7 @@ export class GetRaceDetailUseCase {
|
||||
private readonly resultRepository: IResultRepository,
|
||||
private readonly leagueMembershipRepository: ILeagueMembershipRepository,
|
||||
private readonly driverRatingProvider: DriverRatingProvider,
|
||||
private readonly imageService: IImageService,
|
||||
private readonly imageService: IImageServicePort,
|
||||
public readonly presenter: IRaceDetailPresenter,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
|
||||
import type { IImageService } from '../../domain/services/IImageService';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
import type { ITeamJoinRequestsPresenter } from '../presenters/ITeamJoinRequestsPresenter';
|
||||
|
||||
/**
|
||||
@@ -11,7 +11,7 @@ export class GetTeamJoinRequestsUseCase {
|
||||
constructor(
|
||||
private readonly membershipRepository: ITeamMembershipRepository,
|
||||
private readonly driverRepository: IDriverRepository,
|
||||
private readonly imageService: IImageService,
|
||||
private readonly imageService: IImageServicePort,
|
||||
public readonly presenter: ITeamJoinRequestsPresenter,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
|
||||
import type { IImageService } from '../../domain/services/IImageService';
|
||||
import type { IImageServicePort } from '../ports/IImageServicePort';
|
||||
import type { ITeamMembersPresenter } from '../presenters/ITeamMembersPresenter';
|
||||
|
||||
/**
|
||||
@@ -11,7 +11,7 @@ export class GetTeamMembersUseCase {
|
||||
constructor(
|
||||
private readonly membershipRepository: ITeamMembershipRepository,
|
||||
private readonly driverRepository: IDriverRepository,
|
||||
private readonly imageService: IImageService,
|
||||
private readonly imageService: IImageServicePort,
|
||||
public readonly presenter: ITeamMembersPresenter,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { ILeagueRepository } from '../../domain/repositories/ILeagueReposit
|
||||
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
|
||||
import type { IStandingRepository } from '../../domain/repositories/IStandingRepository';
|
||||
import { Result } from '../../domain/entities/Result';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import {
|
||||
BusinessRuleViolationError,
|
||||
EntityNotFoundError,
|
||||
@@ -26,8 +27,10 @@ export interface ImportRaceResultsParams {
|
||||
raceId: string;
|
||||
results: ImportRaceResultDTO[];
|
||||
}
|
||||
|
||||
export class ImportRaceResultsUseCase {
|
||||
|
||||
export class ImportRaceResultsUseCase
|
||||
implements AsyncUseCase<ImportRaceResultsParams, void>
|
||||
{
|
||||
constructor(
|
||||
private readonly raceRepository: IRaceRepository,
|
||||
private readonly leagueRepository: ILeagueRepository,
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import type {
|
||||
ILeagueMembershipRepository,
|
||||
} from '@gridpilot/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import type {
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import {
|
||||
LeagueMembership,
|
||||
MembershipRole,
|
||||
MembershipStatus,
|
||||
type MembershipRole,
|
||||
type MembershipStatus,
|
||||
} from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
import type { JoinLeagueCommandDTO } from '../dto/JoinLeagueCommandDTO';
|
||||
import { BusinessRuleViolationError } from '../errors/RacingApplicationError';
|
||||
|
||||
export class JoinLeagueUseCase {
|
||||
|
||||
export class JoinLeagueUseCase implements AsyncUseCase<JoinLeagueCommandDTO, LeagueMembership> {
|
||||
constructor(private readonly membershipRepository: ILeagueMembershipRepository) {}
|
||||
|
||||
/**
|
||||
@@ -27,13 +28,12 @@ export class JoinLeagueUseCase {
|
||||
throw new BusinessRuleViolationError('Already a member or have a pending request');
|
||||
}
|
||||
|
||||
const membership: LeagueMembership = {
|
||||
const membership = LeagueMembership.create({
|
||||
leagueId,
|
||||
driverId,
|
||||
role: 'member' as MembershipRole,
|
||||
status: 'active' as MembershipStatus,
|
||||
joinedAt: new Date(),
|
||||
};
|
||||
});
|
||||
|
||||
return this.membershipRepository.saveMembership(membership);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@ import type {
|
||||
TeamMembership,
|
||||
TeamMembershipStatus,
|
||||
TeamRole,
|
||||
} from '../../domain/entities/Team';
|
||||
} from '../../domain/types/TeamMembership';
|
||||
import type { JoinTeamCommandDTO } from '../dto/TeamCommandAndQueryDTO';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import {
|
||||
BusinessRuleViolationError,
|
||||
EntityNotFoundError,
|
||||
} from '../errors/RacingApplicationError';
|
||||
|
||||
export class JoinTeamUseCase {
|
||||
|
||||
export class JoinTeamUseCase implements AsyncUseCase<JoinTeamCommandDTO, void> {
|
||||
constructor(
|
||||
private readonly teamRepository: ITeamRepository,
|
||||
private readonly membershipRepository: ITeamMembershipRepository,
|
||||
|
||||
@@ -5,8 +5,8 @@ import type { IResultRepository } from '@gridpilot/racing/domain/repositories/IR
|
||||
import type { IPenaltyRepository } from '@gridpilot/racing/domain/repositories/IPenaltyRepository';
|
||||
import type { IChampionshipStandingRepository } from '@gridpilot/racing/domain/repositories/IChampionshipStandingRepository';
|
||||
|
||||
import type { ChampionshipConfig } from '@gridpilot/racing/domain/value-objects/ChampionshipConfig';
|
||||
import type { SessionType } from '@gridpilot/racing/domain/value-objects/SessionType';
|
||||
import type { ChampionshipConfig } from '@gridpilot/racing/domain/types/ChampionshipConfig';
|
||||
import type { SessionType } from '@gridpilot/racing/domain/types/SessionType';
|
||||
import type { ChampionshipStanding } from '@gridpilot/racing/domain/entities/ChampionshipStanding';
|
||||
import { EventScoringService } from '@gridpilot/racing/domain/services/EventScoringService';
|
||||
import { ChampionshipAggregator } from '@gridpilot/racing/domain/services/ChampionshipAggregator';
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import type { IRaceRegistrationRepository } from '@gridpilot/racing/domain/repositories/IRaceRegistrationRepository';
|
||||
import type { ILeagueMembershipRepository } from '@gridpilot/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import type { RaceRegistration } from '@gridpilot/racing/domain/entities/RaceRegistration';
|
||||
import { RaceRegistration } from '@gridpilot/racing/domain/entities/RaceRegistration';
|
||||
import type { RegisterForRaceCommandDTO } from '../dto/RegisterForRaceCommandDTO';
|
||||
import type { AsyncUseCase } from '@gridpilot/shared/application';
|
||||
import {
|
||||
BusinessRuleViolationError,
|
||||
PermissionDeniedError,
|
||||
} from '../errors/RacingApplicationError';
|
||||
|
||||
export class RegisterForRaceUseCase {
|
||||
|
||||
export class RegisterForRaceUseCase
|
||||
implements AsyncUseCase<RegisterForRaceCommandDTO, void>
|
||||
{
|
||||
constructor(
|
||||
private readonly registrationRepository: IRaceRegistrationRepository,
|
||||
private readonly membershipRepository: ILeagueMembershipRepository,
|
||||
@@ -32,11 +35,10 @@ export class RegisterForRaceUseCase {
|
||||
throw new PermissionDeniedError('NOT_ACTIVE_MEMBER', 'Must be an active league member to register for races');
|
||||
}
|
||||
|
||||
const registration: RaceRegistration = {
|
||||
const registration = RaceRegistration.create({
|
||||
raceId,
|
||||
driverId,
|
||||
registeredAt: new Date(),
|
||||
};
|
||||
});
|
||||
|
||||
await this.registrationRepository.register(registration);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import type { IProtestRepository } from '../../domain/repositories/IProtestRepository';
|
||||
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import { isLeagueStewardOrHigherRole } from '../../domain/value-objects/LeagueRoles';
|
||||
import { isLeagueStewardOrHigherRole } from '../../domain/types/LeagueRoles';
|
||||
|
||||
export interface RequestProtestDefenseCommand {
|
||||
protestId: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { Team } from '../../domain/entities/Team';
|
||||
import { Team } from '../../domain/entities/Team';
|
||||
import type { UpdateTeamCommandDTO } from '../dto/TeamCommandAndQueryDTO';
|
||||
|
||||
export class UpdateTeamUseCase {
|
||||
|
||||
Reference in New Issue
Block a user