refactor
This commit is contained in:
@@ -1,8 +1,16 @@
|
|||||||
import { Controller, Post, Body, Res, HttpStatus } from '@nestjs/common';
|
import { Controller, Post, Body, Res, HttpStatus } from '@nestjs/common';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
import type { RecordPageViewInput, RecordPageViewOutput, RecordEngagementInput, RecordEngagementOutput } from './dto/AnalyticsDto';
|
import type { RecordPageViewInputDTO } from './dtos/RecordPageViewInputDTO';
|
||||||
|
import type { RecordPageViewOutputDTO } from './dtos/RecordPageViewOutputDTO';
|
||||||
|
import type { RecordEngagementInputDTO } from './dtos/RecordEngagementInputDTO';
|
||||||
|
import type { RecordEngagementOutputDTO } from './dtos/RecordEngagementOutputDTO';
|
||||||
import { AnalyticsService } from './AnalyticsService';
|
import { AnalyticsService } from './AnalyticsService';
|
||||||
|
|
||||||
|
type RecordPageViewInput = RecordPageViewInputDTO;
|
||||||
|
type RecordPageViewOutput = RecordPageViewOutputDTO;
|
||||||
|
type RecordEngagementInput = RecordEngagementInputDTO;
|
||||||
|
type RecordEngagementOutput = RecordEngagementOutputDTO;
|
||||||
|
|
||||||
@Controller('analytics')
|
@Controller('analytics')
|
||||||
export class AnalyticsController {
|
export class AnalyticsController {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { RecordEngagementInput, RecordEngagementOutput, RecordPageViewInput, RecordPageViewOutput } from './dto/AnalyticsDto';
|
import type { RecordPageViewInputDTO } from './dtos/RecordPageViewInputDTO';
|
||||||
|
import type { RecordPageViewOutputDTO } from './dtos/RecordPageViewOutputDTO';
|
||||||
|
import type { RecordEngagementInputDTO } from './dtos/RecordEngagementInputDTO';
|
||||||
|
import type { RecordEngagementOutputDTO } from './dtos/RecordEngagementOutputDTO';
|
||||||
import type { Logger } from '@core/shared/application';
|
import type { Logger } from '@core/shared/application';
|
||||||
import { RecordPageViewUseCase } from './use-cases/RecordPageViewUseCase';
|
import { RecordPageViewUseCase } from './use-cases/RecordPageViewUseCase';
|
||||||
import { RecordEngagementUseCase } from './use-cases/RecordEngagementUseCase';
|
import { RecordEngagementUseCase } from './use-cases/RecordEngagementUseCase';
|
||||||
|
|
||||||
|
type RecordPageViewInput = RecordPageViewInputDTO;
|
||||||
|
type RecordPageViewOutput = RecordPageViewOutputDTO;
|
||||||
|
type RecordEngagementInput = RecordEngagementInputDTO;
|
||||||
|
type RecordEngagementOutput = RecordEngagementOutputDTO;
|
||||||
|
|
||||||
const Logger_TOKEN = 'Logger_TOKEN';
|
const Logger_TOKEN = 'Logger_TOKEN';
|
||||||
const RECORD_PAGE_VIEW_USE_CASE_TOKEN = 'RecordPageViewUseCase_TOKEN';
|
const RECORD_PAGE_VIEW_USE_CASE_TOKEN = 'RecordPageViewUseCase_TOKEN';
|
||||||
const RECORD_ENGAGEMENT_USE_CASE_TOKEN = 'RecordEngagementUseCase_TOKEN';
|
const RECORD_ENGAGEMENT_USE_CASE_TOKEN = 'RecordEngagementUseCase_TOKEN';
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsString, IsOptional, IsEnum, IsBoolean, IsNumber, IsObject } from 'class-validator';
|
|
||||||
|
|
||||||
// From core/analytics/domain/types/PageView.ts
|
|
||||||
export enum EntityType {
|
|
||||||
LEAGUE = 'league',
|
|
||||||
DRIVER = 'driver',
|
|
||||||
TEAM = 'team',
|
|
||||||
RACE = 'race',
|
|
||||||
SPONSOR = 'sponsor',
|
|
||||||
}
|
|
||||||
|
|
||||||
// From core/analytics/domain/types/PageView.ts
|
|
||||||
export enum VisitorType {
|
|
||||||
ANONYMOUS = 'anonymous',
|
|
||||||
DRIVER = 'driver',
|
|
||||||
SPONSOR = 'sponsor',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RecordPageViewInput {
|
|
||||||
@ApiProperty({ enum: EntityType })
|
|
||||||
@IsEnum(EntityType)
|
|
||||||
entityType!: EntityType;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
entityId!: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
visitorId?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: VisitorType })
|
|
||||||
@IsEnum(VisitorType)
|
|
||||||
visitorType!: VisitorType;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
sessionId!: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
referrer?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
userAgent?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
country?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RecordPageViewOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
pageViewId!: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From core/analytics/domain/types/EngagementEvent.ts
|
|
||||||
export enum EngagementAction {
|
|
||||||
CLICK_SPONSOR_LOGO = 'click_sponsor_logo',
|
|
||||||
CLICK_SPONSOR_URL = 'click_sponsor_url',
|
|
||||||
DOWNLOAD_LIVERY_PACK = 'download_livery_pack',
|
|
||||||
JOIN_LEAGUE = 'join_league',
|
|
||||||
REGISTER_RACE = 'register_race',
|
|
||||||
VIEW_STANDINGS = 'view_standings',
|
|
||||||
VIEW_SCHEDULE = 'view_schedule',
|
|
||||||
SHARE_SOCIAL = 'share_social',
|
|
||||||
CONTACT_SPONSOR = 'contact_sponsor',
|
|
||||||
}
|
|
||||||
|
|
||||||
// From core/analytics/domain/types/EngagementEvent.ts
|
|
||||||
export enum EngagementEntityType {
|
|
||||||
LEAGUE = 'league',
|
|
||||||
DRIVER = 'driver',
|
|
||||||
TEAM = 'team',
|
|
||||||
RACE = 'race',
|
|
||||||
SPONSOR = 'sponsor',
|
|
||||||
SPONSORSHIP = 'sponsorship',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RecordEngagementInput {
|
|
||||||
@ApiProperty({ enum: EngagementAction })
|
|
||||||
@IsEnum(EngagementAction)
|
|
||||||
action!: EngagementAction;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: EngagementEntityType })
|
|
||||||
@IsEnum(EngagementEntityType)
|
|
||||||
entityType!: EngagementEntityType;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
entityId!: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
actorId?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['anonymous', 'driver', 'sponsor'] })
|
|
||||||
@IsEnum(['anonymous', 'driver', 'sponsor'])
|
|
||||||
actorType!: 'anonymous' | 'driver' | 'sponsor';
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
sessionId!: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, type: Object })
|
|
||||||
@IsOptional()
|
|
||||||
@IsObject()
|
|
||||||
metadata?: Record<string, string | number | boolean>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RecordEngagementOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
eventId!: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
engagementWeight!: number;
|
|
||||||
}
|
|
||||||
12
apps/api/src/domain/analytics/dtos/EngagementAction.ts
Normal file
12
apps/api/src/domain/analytics/dtos/EngagementAction.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// From core/analytics/domain/types/EngagementEvent.ts
|
||||||
|
export enum EngagementAction {
|
||||||
|
CLICK_SPONSOR_LOGO = 'click_sponsor_logo',
|
||||||
|
CLICK_SPONSOR_URL = 'click_sponsor_url',
|
||||||
|
DOWNLOAD_LIVERY_PACK = 'download_livery_pack',
|
||||||
|
JOIN_LEAGUE = 'join_league',
|
||||||
|
REGISTER_RACE = 'register_race',
|
||||||
|
VIEW_STANDINGS = 'view_standings',
|
||||||
|
VIEW_SCHEDULE = 'view_schedule',
|
||||||
|
SHARE_SOCIAL = 'share_social',
|
||||||
|
CONTACT_SPONSOR = 'contact_sponsor',
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// From core/analytics/domain/types/EngagementEvent.ts
|
||||||
|
export enum EngagementEntityType {
|
||||||
|
LEAGUE = 'league',
|
||||||
|
DRIVER = 'driver',
|
||||||
|
TEAM = 'team',
|
||||||
|
RACE = 'race',
|
||||||
|
SPONSOR = 'sponsor',
|
||||||
|
SPONSORSHIP = 'sponsorship',
|
||||||
|
}
|
||||||
8
apps/api/src/domain/analytics/dtos/EntityType.ts
Normal file
8
apps/api/src/domain/analytics/dtos/EntityType.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// From core/analytics/domain/types/PageView.ts
|
||||||
|
export enum EntityType {
|
||||||
|
LEAGUE = 'league',
|
||||||
|
DRIVER = 'driver',
|
||||||
|
TEAM = 'team',
|
||||||
|
RACE = 'race',
|
||||||
|
SPONSOR = 'sponsor',
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsOptional, IsEnum, IsObject } from 'class-validator';
|
||||||
|
import { EngagementAction } from './EngagementAction';
|
||||||
|
import { EngagementEntityType } from './EngagementEntityType';
|
||||||
|
|
||||||
|
export class RecordEngagementInputDTO {
|
||||||
|
@ApiProperty({ enum: EngagementAction })
|
||||||
|
@IsEnum(EngagementAction)
|
||||||
|
action!: EngagementAction;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: EngagementEntityType })
|
||||||
|
@IsEnum(EngagementEntityType)
|
||||||
|
entityType!: EngagementEntityType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
entityId!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
actorId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['anonymous', 'driver', 'sponsor'] })
|
||||||
|
@IsEnum(['anonymous', 'driver', 'sponsor'])
|
||||||
|
actorType!: 'anonymous' | 'driver' | 'sponsor';
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
sessionId!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false, type: Object })
|
||||||
|
@IsOptional()
|
||||||
|
@IsObject()
|
||||||
|
metadata?: Record<string, string | number | boolean>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber } from 'class-validator';
|
||||||
|
|
||||||
|
export class RecordEngagementOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
eventId!: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
engagementWeight!: number;
|
||||||
|
}
|
||||||
42
apps/api/src/domain/analytics/dtos/RecordPageViewInputDTO.ts
Normal file
42
apps/api/src/domain/analytics/dtos/RecordPageViewInputDTO.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsOptional, IsEnum } from 'class-validator';
|
||||||
|
import { EntityType } from './EntityType';
|
||||||
|
import { VisitorType } from './VisitorType';
|
||||||
|
|
||||||
|
export class RecordPageViewInputDTO {
|
||||||
|
@ApiProperty({ enum: EntityType })
|
||||||
|
@IsEnum(EntityType)
|
||||||
|
entityType!: EntityType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
entityId!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
visitorId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: VisitorType })
|
||||||
|
@IsEnum(VisitorType)
|
||||||
|
visitorType!: VisitorType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
sessionId!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
referrer?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
userAgent?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
country?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class RecordPageViewOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
pageViewId!: string;
|
||||||
|
}
|
||||||
6
apps/api/src/domain/analytics/dtos/VisitorType.ts
Normal file
6
apps/api/src/domain/analytics/dtos/VisitorType.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// From core/analytics/domain/types/PageView.ts
|
||||||
|
export enum VisitorType {
|
||||||
|
ANONYMOUS = 'anonymous',
|
||||||
|
DRIVER = 'driver',
|
||||||
|
SPONSOR = 'sponsor',
|
||||||
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { RecordEngagementInput, RecordEngagementOutput } from '../dto/AnalyticsDto';
|
import type { RecordEngagementInputDTO } from '../dtos/RecordEngagementInputDTO';
|
||||||
|
import type { RecordEngagementOutputDTO } from '../dtos/RecordEngagementOutputDTO';
|
||||||
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
|
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
|
||||||
import type { Logger } from '@core/shared/application';
|
import type { Logger } from '@core/shared/application';
|
||||||
import { EngagementEvent } from '@core/analytics/domain/entities/EngagementEvent';
|
import { EngagementEvent } from '@core/analytics/domain/entities/EngagementEvent';
|
||||||
|
|
||||||
|
type RecordEngagementInput = RecordEngagementInputDTO;
|
||||||
|
type RecordEngagementOutput = RecordEngagementOutputDTO;
|
||||||
|
|
||||||
const Logger_TOKEN = 'Logger_TOKEN';
|
const Logger_TOKEN = 'Logger_TOKEN';
|
||||||
const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN';
|
const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN';
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { RecordPageViewInput, RecordPageViewOutput } from '../dto/AnalyticsDto';
|
import type { RecordPageViewInputDTO } from '../dtos/RecordPageViewInputDTO';
|
||||||
|
import type { RecordPageViewOutputDTO } from '../dtos/RecordPageViewOutputDTO';
|
||||||
import type { IPageViewRepository } from '@core/analytics/application/repositories/IPageViewRepository';
|
import type { IPageViewRepository } from '@core/analytics/application/repositories/IPageViewRepository';
|
||||||
import type { Logger } from '@core/shared/application';
|
import type { Logger } from '@core/shared/application';
|
||||||
import { PageView } from '@core/analytics/domain/entities/PageView';
|
import { PageView } from '@core/analytics/domain/entities/PageView';
|
||||||
|
|
||||||
|
type RecordPageViewInput = RecordPageViewInputDTO;
|
||||||
|
type RecordPageViewOutput = RecordPageViewOutputDTO;
|
||||||
|
|
||||||
const Logger_TOKEN = 'Logger_TOKEN';
|
const Logger_TOKEN = 'Logger_TOKEN';
|
||||||
const IPAGE_VIEW_REPO_TOKEN = 'IPageViewRepository_TOKEN';
|
const IPAGE_VIEW_REPO_TOKEN = 'IPageViewRepository_TOKEN';
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,13 @@ import { Controller, Get, Post, Body, Req, Param } from '@nestjs/common';
|
|||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
||||||
import { DriverService } from './DriverService';
|
import { DriverService } from './DriverService';
|
||||||
import { DriversLeaderboardViewModel, DriverStatsDto, CompleteOnboardingInput, CompleteOnboardingOutput, GetDriverRegistrationStatusQuery, DriverRegistrationStatusViewModel } from './dto/DriverDto';
|
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
|
||||||
|
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
|
||||||
|
import { CompleteOnboardingInputDTO } from './dtos/CompleteOnboardingInputDTO';
|
||||||
|
import { CompleteOnboardingOutputDTO } from './dtos/CompleteOnboardingOutputDTO';
|
||||||
|
import { GetDriverRegistrationStatusQueryDTO } from './dtos/GetDriverRegistrationStatusQueryDTO';
|
||||||
|
import { DriverRegistrationStatusDTO } from './dtos/DriverRegistrationStatusDTO';
|
||||||
|
import { DriverDTO } from './dtos/DriverDTO';
|
||||||
|
|
||||||
@ApiTags('drivers')
|
@ApiTags('drivers')
|
||||||
@Controller('drivers')
|
@Controller('drivers')
|
||||||
@@ -11,15 +17,15 @@ export class DriverController {
|
|||||||
|
|
||||||
@Get('leaderboard')
|
@Get('leaderboard')
|
||||||
@ApiOperation({ summary: 'Get drivers leaderboard' })
|
@ApiOperation({ summary: 'Get drivers leaderboard' })
|
||||||
@ApiResponse({ status: 200, description: 'List of drivers for the leaderboard', type: DriversLeaderboardViewModel })
|
@ApiResponse({ status: 200, description: 'List of drivers for the leaderboard', type: DriversLeaderboardDTO })
|
||||||
async getDriversLeaderboard(): Promise<DriversLeaderboardViewModel> {
|
async getDriversLeaderboard(): Promise<DriversLeaderboardDTO> {
|
||||||
return this.driverService.getDriversLeaderboard();
|
return this.driverService.getDriversLeaderboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('total-drivers')
|
@Get('total-drivers')
|
||||||
@ApiOperation({ summary: 'Get the total number of drivers' })
|
@ApiOperation({ summary: 'Get the total number of drivers' })
|
||||||
@ApiResponse({ status: 200, description: 'Total number of drivers', type: DriverStatsDto })
|
@ApiResponse({ status: 200, description: 'Total number of drivers', type: DriverStatsDTO })
|
||||||
async getTotalDrivers(): Promise<DriverStatsDto> {
|
async getTotalDrivers(): Promise<DriverStatsDTO> {
|
||||||
return this.driverService.getTotalDrivers();
|
return this.driverService.getTotalDrivers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,11 +44,11 @@ export class DriverController {
|
|||||||
|
|
||||||
@Post('complete-onboarding')
|
@Post('complete-onboarding')
|
||||||
@ApiOperation({ summary: 'Complete driver onboarding for a user' })
|
@ApiOperation({ summary: 'Complete driver onboarding for a user' })
|
||||||
@ApiResponse({ status: 200, description: 'Onboarding complete', type: CompleteOnboardingOutput })
|
@ApiResponse({ status: 200, description: 'Onboarding complete', type: CompleteOnboardingOutputDTO })
|
||||||
async completeOnboarding(
|
async completeOnboarding(
|
||||||
@Body() input: CompleteOnboardingInput,
|
@Body() input: CompleteOnboardingInputDTO,
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
): Promise<CompleteOnboardingOutput> {
|
): Promise<CompleteOnboardingOutputDTO> {
|
||||||
// Assuming userId is available from the request (e.g., via auth middleware)
|
// Assuming userId is available from the request (e.g., via auth middleware)
|
||||||
const userId = req['user'].userId; // Placeholder for actual user extraction
|
const userId = req['user'].userId; // Placeholder for actual user extraction
|
||||||
return this.driverService.completeOnboarding(userId, input);
|
return this.driverService.completeOnboarding(userId, input);
|
||||||
@@ -50,13 +56,23 @@ export class DriverController {
|
|||||||
|
|
||||||
@Get(':driverId/races/:raceId/registration-status')
|
@Get(':driverId/races/:raceId/registration-status')
|
||||||
@ApiOperation({ summary: 'Get driver registration status for a specific race' })
|
@ApiOperation({ summary: 'Get driver registration status for a specific race' })
|
||||||
@ApiResponse({ status: 200, description: 'Driver registration status', type: DriverRegistrationStatusViewModel })
|
@ApiResponse({ status: 200, description: 'Driver registration status', type: DriverRegistrationStatusDTO })
|
||||||
async getDriverRegistrationStatus(
|
async getDriverRegistrationStatus(
|
||||||
@Param('driverId') driverId: string,
|
@Param('driverId') driverId: string,
|
||||||
@Param('raceId') raceId: string,
|
@Param('raceId') raceId: string,
|
||||||
): Promise<DriverRegistrationStatusViewModel> {
|
): Promise<DriverRegistrationStatusDTO> {
|
||||||
return this.driverService.getDriverRegistrationStatus({ driverId, raceId });
|
return this.driverService.getDriverRegistrationStatus({ driverId, raceId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Put(':driverId/profile')
|
||||||
|
@ApiOperation({ summary: 'Update driver profile' })
|
||||||
|
@ApiResponse({ status: 200, description: 'Driver profile updated', type: DriverDTO })
|
||||||
|
async updateDriverProfile(
|
||||||
|
@Param('driverId') driverId: string,
|
||||||
|
@Body() body: { bio?: string; country?: string },
|
||||||
|
): Promise<DriverDTO | null> {
|
||||||
|
return this.driverService.updateDriverProfile(driverId, body.bio, body.country);
|
||||||
|
}
|
||||||
|
|
||||||
// Add other Driver endpoints here based on other presenters
|
// Add other Driver endpoints here based on other presenters
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import type { Logger } from "@gridpilot/core/shared/application";
|
|||||||
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
|
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
|
||||||
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
|
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
|
||||||
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
|
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
|
||||||
|
import { GetProfileOverviewUseCase } from '@core/racing/application/use-cases/GetProfileOverviewUseCase';
|
||||||
|
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||||
|
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';
|
||||||
|
|
||||||
// Import concrete in-memory implementations
|
// Import concrete in-memory implementations
|
||||||
import { InMemoryDriverRepository } from '../../..//racing/persistence/inmemory/InMemoryDriverRepository';
|
import { InMemoryDriverRepository } from '../../..//racing/persistence/inmemory/InMemoryDriverRepository';
|
||||||
@@ -41,6 +44,9 @@ export const GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN = 'GetDriversLeaderboardUseC
|
|||||||
export const GET_TOTAL_DRIVERS_USE_CASE_TOKEN = 'GetTotalDriversUseCase';
|
export const GET_TOTAL_DRIVERS_USE_CASE_TOKEN = 'GetTotalDriversUseCase';
|
||||||
export const COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN = 'CompleteDriverOnboardingUseCase';
|
export const COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN = 'CompleteDriverOnboardingUseCase';
|
||||||
export const IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN = 'IsDriverRegisteredForRaceUseCase';
|
export const IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN = 'IsDriverRegisteredForRaceUseCase';
|
||||||
|
export const GET_PROFILE_OVERVIEW_USE_CASE_TOKEN = 'GetProfileOverviewUseCase';
|
||||||
|
export const GET_DRIVER_TEAM_USE_CASE_TOKEN = 'GetDriverTeamUseCase';
|
||||||
|
export const UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN = 'UpdateDriverProfileUseCase';
|
||||||
|
|
||||||
export const DriverProviders: Provider[] = [
|
export const DriverProviders: Provider[] = [
|
||||||
DriverService, // Provide the service itself
|
DriverService, // Provide the service itself
|
||||||
@@ -105,4 +111,9 @@ export const DriverProviders: Provider[] = [
|
|||||||
useFactory: (registrationRepo: IRaceRegistrationRepository) => new IsDriverRegisteredForRaceUseCase(registrationRepo),
|
useFactory: (registrationRepo: IRaceRegistrationRepository) => new IsDriverRegisteredForRaceUseCase(registrationRepo),
|
||||||
inject: [RACE_REGISTRATION_REPOSITORY_TOKEN],
|
inject: [RACE_REGISTRATION_REPOSITORY_TOKEN],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN,
|
||||||
|
useFactory: (driverRepo: IDriverRepository) => new UpdateDriverProfileUseCase(driverRepo),
|
||||||
|
inject: [DRIVER_REPOSITORY_TOKEN],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DriversLeaderboardViewModel, DriverStatsDto, CompleteOnboardingInput, CompleteOnboardingOutput, GetDriverRegistrationStatusQuery, DriverRegistrationStatusViewModel } from './dto/DriverDto';
|
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
|
||||||
|
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
|
||||||
|
import { CompleteOnboardingInputDTO } from './dtos/CompleteOnboardingInputDTO';
|
||||||
|
import { CompleteOnboardingOutputDTO } from './dtos/CompleteOnboardingOutputDTO';
|
||||||
|
import { GetDriverRegistrationStatusQueryDTO } from './dtos/GetDriverRegistrationStatusQueryDTO';
|
||||||
|
import { DriverRegistrationStatusDTO } from './dtos/DriverRegistrationStatusDTO';
|
||||||
|
|
||||||
// Use cases
|
// Use cases
|
||||||
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
|
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
|
||||||
@@ -14,8 +19,10 @@ import { CompleteOnboardingPresenter } from './presenters/CompleteOnboardingPres
|
|||||||
import { DriverRegistrationStatusPresenter } from './presenters/DriverRegistrationStatusPresenter';
|
import { DriverRegistrationStatusPresenter } from './presenters/DriverRegistrationStatusPresenter';
|
||||||
|
|
||||||
// Tokens
|
// Tokens
|
||||||
import { GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN, GET_TOTAL_DRIVERS_USE_CASE_TOKEN, COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN, IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN, LOGGER_TOKEN } from './DriverProviders';
|
import { GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN, GET_TOTAL_DRIVERS_USE_CASE_TOKEN, COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN, IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN, UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN, LOGGER_TOKEN, DRIVER_REPOSITORY_TOKEN } from './DriverProviders';
|
||||||
import type { Logger } from '@core/shared/application';
|
import type { Logger } from '@core/shared/application';
|
||||||
|
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||||
|
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DriverService {
|
export class DriverService {
|
||||||
@@ -24,10 +31,12 @@ export class DriverService {
|
|||||||
@Inject(GET_TOTAL_DRIVERS_USE_CASE_TOKEN) private readonly getTotalDriversUseCase: GetTotalDriversUseCase,
|
@Inject(GET_TOTAL_DRIVERS_USE_CASE_TOKEN) private readonly getTotalDriversUseCase: GetTotalDriversUseCase,
|
||||||
@Inject(COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN) private readonly completeDriverOnboardingUseCase: CompleteDriverOnboardingUseCase,
|
@Inject(COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN) private readonly completeDriverOnboardingUseCase: CompleteDriverOnboardingUseCase,
|
||||||
@Inject(IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN) private readonly isDriverRegisteredForRaceUseCase: IsDriverRegisteredForRaceUseCase,
|
@Inject(IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN) private readonly isDriverRegisteredForRaceUseCase: IsDriverRegisteredForRaceUseCase,
|
||||||
|
@Inject(UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN) private readonly updateDriverProfileUseCase: UpdateDriverProfileUseCase,
|
||||||
|
@Inject(DRIVER_REPOSITORY_TOKEN) private readonly driverRepository: IDriverRepository,
|
||||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getDriversLeaderboard(): Promise<DriversLeaderboardViewModel> {
|
async getDriversLeaderboard(): Promise<DriversLeaderboardDTO> {
|
||||||
this.logger.debug('[DriverService] Fetching drivers leaderboard.');
|
this.logger.debug('[DriverService] Fetching drivers leaderboard.');
|
||||||
|
|
||||||
const presenter = new DriversLeaderboardPresenter();
|
const presenter = new DriversLeaderboardPresenter();
|
||||||
@@ -35,7 +44,7 @@ export class DriverService {
|
|||||||
return presenter.viewModel;
|
return presenter.viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTotalDrivers(): Promise<DriverStatsDto> {
|
async getTotalDrivers(): Promise<DriverStatsDTO> {
|
||||||
this.logger.debug('[DriverService] Fetching total drivers count.');
|
this.logger.debug('[DriverService] Fetching total drivers count.');
|
||||||
|
|
||||||
const presenter = new DriverStatsPresenter();
|
const presenter = new DriverStatsPresenter();
|
||||||
@@ -43,7 +52,7 @@ export class DriverService {
|
|||||||
return presenter.viewModel;
|
return presenter.viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async completeOnboarding(userId: string, input: CompleteOnboardingInput): Promise<CompleteOnboardingOutput> {
|
async completeOnboarding(userId: string, input: CompleteOnboardingInputDTO): Promise<CompleteOnboardingOutputDTO> {
|
||||||
this.logger.debug('Completing onboarding for user:', userId);
|
this.logger.debug('Completing onboarding for user:', userId);
|
||||||
|
|
||||||
const presenter = new CompleteOnboardingPresenter();
|
const presenter = new CompleteOnboardingPresenter();
|
||||||
@@ -59,11 +68,37 @@ export class DriverService {
|
|||||||
return presenter.viewModel;
|
return presenter.viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDriverRegistrationStatus(query: GetDriverRegistrationStatusQuery): Promise<DriverRegistrationStatusViewModel> {
|
async getDriverRegistrationStatus(query: GetDriverRegistrationStatusQueryDTO): Promise<DriverRegistrationStatusDTO> {
|
||||||
this.logger.debug('Checking driver registration status:', query);
|
this.logger.debug('Checking driver registration status:', query);
|
||||||
|
|
||||||
const presenter = new DriverRegistrationStatusPresenter();
|
const presenter = new DriverRegistrationStatusPresenter();
|
||||||
await this.isDriverRegisteredForRaceUseCase.execute({ raceId: query.raceId, driverId: query.driverId }, presenter);
|
await this.isDriverRegisteredForRaceUseCase.execute({ raceId: query.raceId, driverId: query.driverId }, presenter);
|
||||||
return presenter.viewModel;
|
return presenter.viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCurrentDriver(userId: string): Promise<DriverDTO | null> {
|
||||||
|
this.logger.debug(`[DriverService] Fetching current driver for userId: ${userId}`);
|
||||||
|
|
||||||
|
const driver = await this.driverRepository.findById(userId);
|
||||||
|
if (!driver) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: driver.id,
|
||||||
|
name: driver.name.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDriverProfile(driverId: string, bio?: string, country?: string): Promise<DriverDTO | null> {
|
||||||
|
this.logger.debug(`[DriverService] Updating driver profile for driverId: ${driverId}`);
|
||||||
|
|
||||||
|
const result = await this.updateDriverProfileUseCase.execute({ driverId, bio, country });
|
||||||
|
if (result.isErr()) {
|
||||||
|
this.logger.error(`Failed to update driver profile: ${result.error.code}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsString, IsNotEmpty, IsOptional, IsBoolean } from 'class-validator';
|
|
||||||
|
|
||||||
export class DriverLeaderboardItemViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
rating: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
skillLevel: string; // Assuming skillLevel is a string like 'Rookie', 'Pro', etc.
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
nationality: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
racesCompleted: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
wins: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
podiums: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
isActive: boolean;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
rank: number;
|
|
||||||
|
|
||||||
@ApiProperty({ nullable: true })
|
|
||||||
avatarUrl?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DriversLeaderboardViewModel {
|
|
||||||
@ApiProperty({ type: [DriverLeaderboardItemViewModel] })
|
|
||||||
drivers: DriverLeaderboardItemViewModel[];
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
totalRaces: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
totalWins: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
activeCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DriverStatsDto {
|
|
||||||
@ApiProperty()
|
|
||||||
totalDrivers: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CompleteOnboardingInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
firstName: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
lastName: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
displayName: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
country: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
timezone?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
bio?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CompleteOnboardingOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsString()
|
|
||||||
driverId?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsString()
|
|
||||||
errorMessage?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetDriverRegistrationStatusQuery {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
raceId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
driverId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DriverRegistrationStatusViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
isRegistered: boolean;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
raceId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
driverId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DriverDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
name: string; // Display name or full name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add other DTOs for driver-related logic as needed
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
|
||||||
|
|
||||||
|
export class CompleteOnboardingInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
firstName: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
lastName: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
country: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
timezone?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
bio?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsBoolean, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class CompleteOnboardingOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsString()
|
||||||
|
driverId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsString()
|
||||||
|
errorMessage?: string;
|
||||||
|
}
|
||||||
36
apps/api/src/domain/driver/dtos/DriverLeaderboardItemDTO.ts
Normal file
36
apps/api/src/domain/driver/dtos/DriverLeaderboardItemDTO.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class DriverLeaderboardItemDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
rating: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
skillLevel: string; // Assuming skillLevel is a string like 'Rookie', 'Pro', etc.
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
nationality: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
racesCompleted: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
wins: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
podiums: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
isActive: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
rank: number;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
avatarUrl?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsBoolean, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class DriverRegistrationStatusDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
isRegistered!: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
raceId!: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
driverId!: string;
|
||||||
|
}
|
||||||
6
apps/api/src/domain/driver/dtos/DriverStatsDTO.ts
Normal file
6
apps/api/src/domain/driver/dtos/DriverStatsDTO.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class DriverStatsDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
totalDrivers: number;
|
||||||
|
}
|
||||||
16
apps/api/src/domain/driver/dtos/DriversLeaderboardDTO.ts
Normal file
16
apps/api/src/domain/driver/dtos/DriversLeaderboardDTO.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { DriverLeaderboardItemDTO } from './DriverLeaderboardItemDTO';
|
||||||
|
|
||||||
|
export class DriversLeaderboardDTO {
|
||||||
|
@ApiProperty({ type: [DriverLeaderboardItemDTO] })
|
||||||
|
drivers: DriverLeaderboardItemDTO[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
totalRaces: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
totalWins: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
activeCount: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetDriverRegistrationStatusQueryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
raceId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
driverId: string;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { CompleteOnboardingOutput } from '../dto/DriverDto';
|
import { CompleteOnboardingOutputDTO } from '../dtos/CompleteOnboardingOutputDTO';
|
||||||
import type { ICompleteDriverOnboardingPresenter, CompleteDriverOnboardingResultDTO } from '../../../../../core/racing/application/presenters/ICompleteDriverOnboardingPresenter';
|
import type { ICompleteDriverOnboardingPresenter, CompleteDriverOnboardingResultDTO } from '../../../../../core/racing/application/presenters/ICompleteDriverOnboardingPresenter';
|
||||||
|
|
||||||
export class CompleteOnboardingPresenter implements ICompleteDriverOnboardingPresenter {
|
export class CompleteOnboardingPresenter implements ICompleteDriverOnboardingPresenter {
|
||||||
private result: CompleteOnboardingOutput | null = null;
|
private result: CompleteOnboardingOutputDTO | null = null;
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.result = null;
|
this.result = null;
|
||||||
@@ -16,7 +16,7 @@ export class CompleteOnboardingPresenter implements ICompleteDriverOnboardingPre
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get viewModel(): CompleteOnboardingOutput {
|
get viewModel(): CompleteOnboardingOutputDTO {
|
||||||
if (!this.result) throw new Error('Presenter not presented');
|
if (!this.result) throw new Error('Presenter not presented');
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { DriverRegistrationStatusViewModel } from '../dto/DriverDto';
|
import { DriverRegistrationStatusDTO } from '../dtos/DriverRegistrationStatusDTO';
|
||||||
import type { IDriverRegistrationStatusPresenter } from '../../../../../core/racing/application/presenters/IDriverRegistrationStatusPresenter';
|
import type { IDriverRegistrationStatusPresenter } from '../../../../../core/racing/application/presenters/IDriverRegistrationStatusPresenter';
|
||||||
|
|
||||||
export class DriverRegistrationStatusPresenter implements IDriverRegistrationStatusPresenter {
|
export class DriverRegistrationStatusPresenter implements IDriverRegistrationStatusPresenter {
|
||||||
private result: DriverRegistrationStatusViewModel | null = null;
|
private result: DriverRegistrationStatusDTO | null = null;
|
||||||
|
|
||||||
present(isRegistered: boolean, raceId: string, driverId: string) {
|
present(isRegistered: boolean, raceId: string, driverId: string) {
|
||||||
this.result = {
|
this.result = {
|
||||||
@@ -12,7 +12,7 @@ export class DriverRegistrationStatusPresenter implements IDriverRegistrationSta
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewModel(): DriverRegistrationStatusViewModel {
|
getViewModel(): DriverRegistrationStatusDTO {
|
||||||
if (!this.result) throw new Error('Presenter not presented');
|
if (!this.result) throw new Error('Presenter not presented');
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ export class DriverRegistrationStatusPresenter implements IDriverRegistrationSta
|
|||||||
this.result = null;
|
this.result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get viewModel(): DriverRegistrationStatusViewModel {
|
get viewModel(): DriverRegistrationStatusDTO {
|
||||||
return this.getViewModel();
|
return this.getViewModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { DriverStatsDto } from '../dto/DriverDto';
|
import { DriverStatsDTO } from '../dtos/DriverStatsDTO';
|
||||||
import type { ITotalDriversPresenter, TotalDriversResultDTO } from '../../../../../core/racing/application/presenters/ITotalDriversPresenter';
|
import type { ITotalDriversPresenter, TotalDriversResultDTO } from '../../../../../core/racing/application/presenters/ITotalDriversPresenter';
|
||||||
|
|
||||||
export class DriverStatsPresenter implements ITotalDriversPresenter {
|
export class DriverStatsPresenter implements ITotalDriversPresenter {
|
||||||
private result: DriverStatsDto | null = null;
|
private result: DriverStatsDTO | null = null;
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.result = null;
|
this.result = null;
|
||||||
@@ -14,7 +14,7 @@ export class DriverStatsPresenter implements ITotalDriversPresenter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get viewModel(): DriverStatsDto {
|
get viewModel(): DriverStatsDTO {
|
||||||
if (!this.result) throw new Error('Presenter not presented');
|
if (!this.result) throw new Error('Presenter not presented');
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { DriversLeaderboardViewModel, DriverLeaderboardItemViewModel } from '../dto/DriverDto';
|
import { DriversLeaderboardDTO, DriverLeaderboardItemDTO } from '../dtos/DriversLeaderboardDTO';
|
||||||
|
import { DriverLeaderboardItemDTO } from '../dtos/DriverLeaderboardItemDTO';
|
||||||
import type { IDriversLeaderboardPresenter, DriversLeaderboardResultDTO } from '../../../../../core/racing/application/presenters/IDriversLeaderboardPresenter';
|
import type { IDriversLeaderboardPresenter, DriversLeaderboardResultDTO } from '../../../../../core/racing/application/presenters/IDriversLeaderboardPresenter';
|
||||||
|
|
||||||
export class DriversLeaderboardPresenter implements IDriversLeaderboardPresenter {
|
export class DriversLeaderboardPresenter implements IDriversLeaderboardPresenter {
|
||||||
private result: DriversLeaderboardViewModel | null = null;
|
private result: DriversLeaderboardDTO | null = null;
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.result = null;
|
this.result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
present(dto: DriversLeaderboardResultDTO) {
|
present(dto: DriversLeaderboardResultDTO) {
|
||||||
const drivers: DriverLeaderboardItemViewModel[] = dto.drivers.map(driver => {
|
const drivers: DriverLeaderboardItemDTO[] = dto.drivers.map(driver => {
|
||||||
const ranking = dto.rankings.find(r => r.driverId === driver.id);
|
const ranking = dto.rankings.find(r => r.driverId === driver.id);
|
||||||
const stats = dto.stats[driver.id];
|
const stats = dto.stats[driver.id];
|
||||||
const avatarUrl = dto.avatarUrls[driver.id];
|
const avatarUrl = dto.avatarUrls[driver.id];
|
||||||
@@ -42,7 +43,7 @@ export class DriversLeaderboardPresenter implements IDriversLeaderboardPresenter
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get viewModel(): DriversLeaderboardViewModel {
|
get viewModel(): DriversLeaderboardDTO {
|
||||||
if (!this.result) throw new Error('Presenter not presented');
|
if (!this.result) throw new Error('Presenter not presented');
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,35 @@
|
|||||||
import { Controller, Get, Post, Patch, Body, Param } from '@nestjs/common';
|
import { Controller, Get, Post, Patch, Body, Param } from '@nestjs/common';
|
||||||
import { ApiTags, ApiResponse, ApiOperation, ApiBody } from '@nestjs/swagger';
|
import { ApiTags, ApiResponse, ApiOperation, ApiBody } from '@nestjs/swagger';
|
||||||
import { LeagueService } from './LeagueService';
|
import { LeagueService } from './LeagueService';
|
||||||
import { AllLeaguesWithCapacityViewModel, LeagueStatsDto, LeagueJoinRequestViewModel, ApproveJoinRequestInput, ApproveJoinRequestOutput, RejectJoinRequestInput, RejectJoinRequestOutput, LeagueAdminPermissionsViewModel, RemoveLeagueMemberInput, RemoveLeagueMemberOutput, UpdateLeagueMemberRoleInput, UpdateLeagueMemberRoleOutput, LeagueOwnerSummaryViewModel, LeagueConfigFormModelDto, LeagueAdminProtestsViewModel, LeagueSeasonSummaryViewModel, LeagueMembershipsViewModel, LeagueStandingsViewModel, LeagueScheduleViewModel, LeagueStatsViewModel, LeagueAdminViewModel, CreateLeagueInput, CreateLeagueOutput } from './dto/LeagueDto';
|
import { AllLeaguesWithCapacityDTO } from './dtos/AllLeaguesWithCapacityDTO';
|
||||||
import { GetLeagueAdminPermissionsInput, GetLeagueJoinRequestsQuery, GetLeagueProtestsQuery, GetLeagueSeasonsQuery, GetLeagueAdminConfigQuery, GetLeagueOwnerSummaryQuery } from './dto/LeagueDto'; // Explicitly import queries
|
import { LeagueStatsDTO } from './dtos/LeagueStatsDTO';
|
||||||
|
import { LeagueJoinRequestDTO } from './dtos/LeagueJoinRequestDTO';
|
||||||
|
import { ApproveJoinRequestInputDTO } from './dtos/ApproveJoinRequestInputDTO';
|
||||||
|
import { ApproveJoinRequestOutputDTO } from './dtos/ApproveJoinRequestOutputDTO';
|
||||||
|
import { RejectJoinRequestInputDTO } from './dtos/RejectJoinRequestInputDTO';
|
||||||
|
import { RejectJoinRequestOutputDTO } from './dtos/RejectJoinRequestOutputDTO';
|
||||||
|
import { LeagueAdminPermissionsDTO } from './dtos/LeagueAdminPermissionsDTO';
|
||||||
|
import { RemoveLeagueMemberInputDTO } from './dtos/RemoveLeagueMemberInputDTO';
|
||||||
|
import { RemoveLeagueMemberOutputDTO } from './dtos/RemoveLeagueMemberOutputDTO';
|
||||||
|
import { UpdateLeagueMemberRoleInputDTO } from './dtos/UpdateLeagueMemberRoleInputDTO';
|
||||||
|
import { UpdateLeagueMemberRoleOutputDTO } from './dtos/UpdateLeagueMemberRoleOutputDTO';
|
||||||
|
import { LeagueOwnerSummaryDTO } from './dtos/LeagueOwnerSummaryDTO';
|
||||||
|
import { LeagueConfigFormModelDTO } from './dtos/LeagueConfigFormModelDTO';
|
||||||
|
import { LeagueAdminProtestsDTO } from './dtos/LeagueAdminProtestsDTO';
|
||||||
|
import { LeagueSeasonSummaryDTO } from './dtos/LeagueSeasonSummaryDTO';
|
||||||
|
import { LeagueMembershipsDTO } from './dtos/LeagueMembershipsDTO';
|
||||||
|
import { LeagueStandingsDTO } from './dtos/LeagueStandingsDTO';
|
||||||
|
import { LeagueScheduleDTO } from './dtos/LeagueScheduleDTO';
|
||||||
|
import { LeagueStatsDTO } from './dtos/LeagueStatsDTO';
|
||||||
|
import { LeagueAdminDTO } from './dtos/LeagueAdminDTO';
|
||||||
|
import { CreateLeagueInputDTO } from './dtos/CreateLeagueInputDTO';
|
||||||
|
import { CreateLeagueOutputDTO } from './dtos/CreateLeagueOutputDTO';
|
||||||
|
import { GetLeagueAdminPermissionsInputDTO } from './dtos/GetLeagueAdminPermissionsInputDTO';
|
||||||
|
import { GetLeagueJoinRequestsQueryDTO } from './dtos/GetLeagueJoinRequestsQueryDTO';
|
||||||
|
import { GetLeagueProtestsQueryDTO } from './dtos/GetLeagueProtestsQueryDTO';
|
||||||
|
import { GetLeagueSeasonsQueryDTO } from './dtos/GetLeagueSeasonsQueryDTO';
|
||||||
|
import { GetLeagueAdminConfigQueryDTO } from './dtos/GetLeagueAdminConfigQueryDTO';
|
||||||
|
import { GetLeagueOwnerSummaryQueryDTO } from './dtos/GetLeagueOwnerSummaryQueryDTO';
|
||||||
|
|
||||||
@ApiTags('leagues')
|
@ApiTags('leagues')
|
||||||
@Controller('leagues')
|
@Controller('leagues')
|
||||||
@@ -11,169 +38,197 @@ export class LeagueController {
|
|||||||
|
|
||||||
@Get('all-with-capacity')
|
@Get('all-with-capacity')
|
||||||
@ApiOperation({ summary: 'Get all leagues with their capacity information' })
|
@ApiOperation({ summary: 'Get all leagues with their capacity information' })
|
||||||
@ApiResponse({ status: 200, description: 'List of leagues with capacity', type: AllLeaguesWithCapacityViewModel })
|
@ApiResponse({ status: 200, description: 'List of leagues with capacity', type: AllLeaguesWithCapacityDTO })
|
||||||
async getAllLeaguesWithCapacity(): Promise<AllLeaguesWithCapacityViewModel> {
|
async getAllLeaguesWithCapacity(): Promise<AllLeaguesWithCapacityDTO> {
|
||||||
return this.leagueService.getAllLeaguesWithCapacity();
|
return this.leagueService.getAllLeaguesWithCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('total-leagues')
|
@Get('total-leagues')
|
||||||
@ApiOperation({ summary: 'Get the total number of leagues' })
|
@ApiOperation({ summary: 'Get the total number of leagues' })
|
||||||
@ApiResponse({ status: 200, description: 'Total number of leagues', type: LeagueStatsDto })
|
@ApiResponse({ status: 200, description: 'Total number of leagues', type: LeagueStatsDTO })
|
||||||
async getTotalLeagues(): Promise<LeagueStatsDto> {
|
async getTotalLeagues(): Promise<LeagueStatsDTO> {
|
||||||
return this.leagueService.getTotalLeagues();
|
return this.leagueService.getTotalLeagues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/join-requests')
|
@Get(':leagueId/join-requests')
|
||||||
@ApiOperation({ summary: 'Get all outstanding join requests for a league' })
|
@ApiOperation({ summary: 'Get all outstanding join requests for a league' })
|
||||||
@ApiResponse({ status: 200, description: 'List of join requests', type: [LeagueJoinRequestViewModel] })
|
@ApiResponse({ status: 200, description: 'List of join requests', type: [LeagueJoinRequestDTO] })
|
||||||
async getJoinRequests(@Param('leagueId') leagueId: string): Promise<LeagueJoinRequestViewModel[]> {
|
async getJoinRequests(@Param('leagueId') leagueId: string): Promise<LeagueJoinRequestDTO[]> {
|
||||||
// No specific query DTO needed for GET, leagueId from param
|
// No specific query DTO needed for GET, leagueId from param
|
||||||
return this.leagueService.getLeagueJoinRequests(leagueId);
|
return this.leagueService.getLeagueJoinRequests(leagueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post(':leagueId/join-requests/approve')
|
@Post(':leagueId/join-requests/approve')
|
||||||
@ApiOperation({ summary: 'Approve a league join request' })
|
@ApiOperation({ summary: 'Approve a league join request' })
|
||||||
@ApiBody({ type: ApproveJoinRequestInput }) // Explicitly define body type for Swagger
|
@ApiBody({ type: ApproveJoinRequestInputDTO }) // Explicitly define body type for Swagger
|
||||||
@ApiResponse({ status: 200, description: 'Join request approved', type: ApproveJoinRequestOutput })
|
@ApiResponse({ status: 200, description: 'Join request approved', type: ApproveJoinRequestOutputDTO })
|
||||||
@ApiResponse({ status: 404, description: 'Join request not found' })
|
@ApiResponse({ status: 404, description: 'Join request not found' })
|
||||||
async approveJoinRequest(
|
async approveJoinRequest(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
@Body() input: ApproveJoinRequestInput,
|
@Body() input: ApproveJoinRequestInputDTO,
|
||||||
): Promise<ApproveJoinRequestOutput> {
|
): Promise<ApproveJoinRequestOutputDTO> {
|
||||||
return this.leagueService.approveLeagueJoinRequest({ ...input, leagueId });
|
return this.leagueService.approveLeagueJoinRequest({ ...input, leagueId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post(':leagueId/join-requests/reject')
|
@Post(':leagueId/join-requests/reject')
|
||||||
@ApiOperation({ summary: 'Reject a league join request' })
|
@ApiOperation({ summary: 'Reject a league join request' })
|
||||||
@ApiBody({ type: RejectJoinRequestInput })
|
@ApiBody({ type: RejectJoinRequestInputDTO })
|
||||||
@ApiResponse({ status: 200, description: 'Join request rejected', type: RejectJoinRequestOutput })
|
@ApiResponse({ status: 200, description: 'Join request rejected', type: RejectJoinRequestOutputDTO })
|
||||||
@ApiResponse({ status: 404, description: 'Join request not found' })
|
@ApiResponse({ status: 404, description: 'Join request not found' })
|
||||||
async rejectJoinRequest(
|
async rejectJoinRequest(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
@Body() input: RejectJoinRequestInput,
|
@Body() input: RejectJoinRequestInputDTO,
|
||||||
): Promise<RejectJoinRequestOutput> {
|
): Promise<RejectJoinRequestOutputDTO> {
|
||||||
return this.leagueService.rejectLeagueJoinRequest({ ...input, leagueId });
|
return this.leagueService.rejectLeagueJoinRequest({ ...input, leagueId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/permissions/:performerDriverId')
|
@Get(':leagueId/permissions/:performerDriverId')
|
||||||
@ApiOperation({ summary: 'Get league admin permissions for a performer' })
|
@ApiOperation({ summary: 'Get league admin permissions for a performer' })
|
||||||
@ApiResponse({ status: 200, description: 'League admin permissions', type: LeagueAdminPermissionsViewModel })
|
@ApiResponse({ status: 200, description: 'League admin permissions', type: LeagueAdminPermissionsDTO })
|
||||||
async getLeagueAdminPermissions(
|
async getLeagueAdminPermissions(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
@Param('performerDriverId') performerDriverId: string,
|
@Param('performerDriverId') performerDriverId: string,
|
||||||
): Promise<LeagueAdminPermissionsViewModel> {
|
): Promise<LeagueAdminPermissionsDTO> {
|
||||||
// No specific input DTO needed for Get, parameters from path
|
// No specific input DTO needed for Get, parameters from path
|
||||||
return this.leagueService.getLeagueAdminPermissions({ leagueId, performerDriverId });
|
return this.leagueService.getLeagueAdminPermissions({ leagueId, performerDriverId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':leagueId/members/:targetDriverId/remove')
|
@Patch(':leagueId/members/:targetDriverId/remove')
|
||||||
@ApiOperation({ summary: 'Remove a member from the league' })
|
@ApiOperation({ summary: 'Remove a member from the league' })
|
||||||
@ApiBody({ type: RemoveLeagueMemberInput }) // Explicitly define body type for Swagger
|
@ApiBody({ type: RemoveLeagueMemberInputDTO }) // Explicitly define body type for Swagger
|
||||||
@ApiResponse({ status: 200, description: 'Member removed successfully', type: RemoveLeagueMemberOutput })
|
@ApiResponse({ status: 200, description: 'Member removed successfully', type: RemoveLeagueMemberOutputDTO })
|
||||||
@ApiResponse({ status: 400, description: 'Cannot remove member' })
|
@ApiResponse({ status: 400, description: 'Cannot remove member' })
|
||||||
@ApiResponse({ status: 404, description: 'Member not found' })
|
@ApiResponse({ status: 404, description: 'Member not found' })
|
||||||
async removeLeagueMember(
|
async removeLeagueMember(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
@Param('performerDriverId') performerDriverId: string,
|
@Param('performerDriverId') performerDriverId: string,
|
||||||
@Param('targetDriverId') targetDriverId: string,
|
@Param('targetDriverId') targetDriverId: string,
|
||||||
@Body() input: RemoveLeagueMemberInput, // Body content for a patch often includes IDs
|
@Body() input: RemoveLeagueMemberInputDTO, // Body content for a patch often includes IDs
|
||||||
): Promise<RemoveLeagueMemberOutput> {
|
): Promise<RemoveLeagueMemberOutputDTO> {
|
||||||
return this.leagueService.removeLeagueMember({ leagueId, performerDriverId, targetDriverId });
|
return this.leagueService.removeLeagueMember({ leagueId, performerDriverId, targetDriverId });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':leagueId/members/:targetDriverId/role')
|
@Patch(':leagueId/members/:targetDriverId/role')
|
||||||
@ApiOperation({ summary: "Update a member's role in the league" })
|
@ApiOperation({ summary: "Update a member's role in the league" })
|
||||||
@ApiBody({ type: UpdateLeagueMemberRoleInput }) // Explicitly define body type for Swagger
|
@ApiBody({ type: UpdateLeagueMemberRoleInputDTO }) // Explicitly define body type for Swagger
|
||||||
@ApiResponse({ status: 200, description: 'Member role updated successfully', type: UpdateLeagueMemberRoleOutput })
|
@ApiResponse({ status: 200, description: 'Member role updated successfully', type: UpdateLeagueMemberRoleOutputDTO })
|
||||||
@ApiResponse({ status: 400, description: 'Cannot update role' })
|
@ApiResponse({ status: 400, description: 'Cannot update role' })
|
||||||
@ApiResponse({ status: 404, description: 'Member not found' })
|
@ApiResponse({ status: 404, description: 'Member not found' })
|
||||||
async updateLeagueMemberRole(
|
async updateLeagueMemberRole(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
@Param('performerDriverId') performerDriverId: string,
|
@Param('performerDriverId') performerDriverId: string,
|
||||||
@Param('targetDriverId') targetDriverId: string,
|
@Param('targetDriverId') targetDriverId: string,
|
||||||
@Body() input: UpdateLeagueMemberRoleInput, // Body includes newRole, other for swagger
|
@Body() input: UpdateLeagueMemberRoleInputDTO, // Body includes newRole, other for swagger
|
||||||
): Promise<UpdateLeagueMemberRoleOutput> {
|
): Promise<UpdateLeagueMemberRoleOutputDTO> {
|
||||||
return this.leagueService.updateLeagueMemberRole({ leagueId, performerDriverId, targetDriverId, newRole: input.newRole });
|
return this.leagueService.updateLeagueMemberRole({ leagueId, performerDriverId, targetDriverId, newRole: input.newRole });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/owner-summary/:ownerId')
|
@Get(':leagueId/owner-summary/:ownerId')
|
||||||
@ApiOperation({ summary: 'Get owner summary for a league' })
|
@ApiOperation({ summary: 'Get owner summary for a league' })
|
||||||
@ApiResponse({ status: 200, description: 'League owner summary', type: LeagueOwnerSummaryViewModel })
|
@ApiResponse({ status: 200, description: 'League owner summary', type: LeagueOwnerSummaryDTO })
|
||||||
@ApiResponse({ status: 404, description: 'Owner or league not found' })
|
@ApiResponse({ status: 404, description: 'Owner or league not found' })
|
||||||
async getLeagueOwnerSummary(
|
async getLeagueOwnerSummary(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
@Param('ownerId') ownerId: string,
|
@Param('ownerId') ownerId: string,
|
||||||
): Promise<LeagueOwnerSummaryViewModel | null> {
|
): Promise<LeagueOwnerSummaryDTO | null> {
|
||||||
const query: GetLeagueOwnerSummaryQuery = { ownerId, leagueId };
|
const query: GetLeagueOwnerSummaryQuery = { ownerId, leagueId };
|
||||||
return this.leagueService.getLeagueOwnerSummary(query);
|
return this.leagueService.getLeagueOwnerSummary(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/config')
|
@Get(':leagueId/config')
|
||||||
@ApiOperation({ summary: 'Get league full configuration' })
|
@ApiOperation({ summary: 'Get league full configuration' })
|
||||||
@ApiResponse({ status: 200, description: 'League configuration form model', type: LeagueConfigFormModelDto })
|
@ApiResponse({ status: 200, description: 'League configuration form model', type: LeagueConfigFormModelDTO })
|
||||||
async getLeagueFullConfig(
|
async getLeagueFullConfig(
|
||||||
@Param('leagueId') leagueId: string,
|
@Param('leagueId') leagueId: string,
|
||||||
): Promise<LeagueConfigFormModelDto | null> {
|
): Promise<LeagueConfigFormModelDTO | null> {
|
||||||
const query: GetLeagueAdminConfigQuery = { leagueId };
|
const query: GetLeagueAdminConfigQuery = { leagueId };
|
||||||
return this.leagueService.getLeagueFullConfig(query);
|
return this.leagueService.getLeagueFullConfig(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/protests')
|
@Get(':leagueId/protests')
|
||||||
@ApiOperation({ summary: 'Get protests for a league' })
|
@ApiOperation({ summary: 'Get protests for a league' })
|
||||||
@ApiResponse({ status: 200, description: 'List of protests for the league', type: LeagueAdminProtestsViewModel })
|
@ApiResponse({ status: 200, description: 'List of protests for the league', type: LeagueAdminProtestsDTO })
|
||||||
async getLeagueProtests(@Param('leagueId') leagueId: string): Promise<LeagueAdminProtestsViewModel> {
|
async getLeagueProtests(@Param('leagueId') leagueId: string): Promise<LeagueAdminProtestsDTO> {
|
||||||
const query: GetLeagueProtestsQuery = { leagueId };
|
const query: GetLeagueProtestsQuery = { leagueId };
|
||||||
return this.leagueService.getLeagueProtests(query);
|
return this.leagueService.getLeagueProtests(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/seasons')
|
@Get(':leagueId/seasons')
|
||||||
@ApiOperation({ summary: 'Get seasons for a league' })
|
@ApiOperation({ summary: 'Get seasons for a league' })
|
||||||
@ApiResponse({ status: 200, description: 'List of seasons for the league', type: [LeagueSeasonSummaryViewModel] })
|
@ApiResponse({ status: 200, description: 'List of seasons for the league', type: [LeagueSeasonSummaryDTO] })
|
||||||
async getLeagueSeasons(@Param('leagueId') leagueId: string): Promise<LeagueSeasonSummaryViewModel[]> {
|
async getLeagueSeasons(@Param('leagueId') leagueId: string): Promise<LeagueSeasonSummaryDTO[]> {
|
||||||
const query: GetLeagueSeasonsQuery = { leagueId };
|
const query: GetLeagueSeasonsQuery = { leagueId };
|
||||||
return this.leagueService.getLeagueSeasons(query);
|
return this.leagueService.getLeagueSeasons(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/memberships')
|
@Get(':leagueId/memberships')
|
||||||
@ApiOperation({ summary: 'Get league memberships' })
|
@ApiOperation({ summary: 'Get league memberships' })
|
||||||
@ApiResponse({ status: 200, description: 'List of league members', type: LeagueMembershipsViewModel })
|
@ApiResponse({ status: 200, description: 'List of league members', type: LeagueMembershipsDTO })
|
||||||
async getLeagueMemberships(@Param('leagueId') leagueId: string): Promise<LeagueMembershipsViewModel> {
|
async getLeagueMemberships(@Param('leagueId') leagueId: string): Promise<LeagueMembershipsDTO> {
|
||||||
return this.leagueService.getLeagueMemberships(leagueId);
|
return this.leagueService.getLeagueMemberships(leagueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/standings')
|
@Get(':leagueId/standings')
|
||||||
@ApiOperation({ summary: 'Get league standings' })
|
@ApiOperation({ summary: 'Get league standings' })
|
||||||
@ApiResponse({ status: 200, description: 'League standings', type: LeagueStandingsViewModel })
|
@ApiResponse({ status: 200, description: 'League standings', type: LeagueStandingsDTO })
|
||||||
async getLeagueStandings(@Param('leagueId') leagueId: string): Promise<LeagueStandingsViewModel> {
|
async getLeagueStandings(@Param('leagueId') leagueId: string): Promise<LeagueStandingsDTO> {
|
||||||
return this.leagueService.getLeagueStandings(leagueId);
|
return this.leagueService.getLeagueStandings(leagueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/schedule')
|
@Get(':leagueId/schedule')
|
||||||
@ApiOperation({ summary: 'Get league schedule' })
|
@ApiOperation({ summary: 'Get league schedule' })
|
||||||
@ApiResponse({ status: 200, description: 'League schedule', type: LeagueScheduleViewModel })
|
@ApiResponse({ status: 200, description: 'League schedule', type: LeagueScheduleDTO })
|
||||||
async getLeagueSchedule(@Param('leagueId') leagueId: string): Promise<LeagueScheduleViewModel> {
|
async getLeagueSchedule(@Param('leagueId') leagueId: string): Promise<LeagueScheduleDTO> {
|
||||||
return this.leagueService.getLeagueSchedule(leagueId);
|
return this.leagueService.getLeagueSchedule(leagueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/stats')
|
@Get(':leagueId/stats')
|
||||||
@ApiOperation({ summary: 'Get league stats' })
|
@ApiOperation({ summary: 'Get league stats' })
|
||||||
@ApiResponse({ status: 200, description: 'League stats', type: LeagueStatsViewModel })
|
@ApiResponse({ status: 200, description: 'League stats', type: LeagueStatsDTO })
|
||||||
async getLeagueStats(@Param('leagueId') leagueId: string): Promise<LeagueStatsViewModel> {
|
async getLeagueStats(@Param('leagueId') leagueId: string): Promise<LeagueStatsDTO> {
|
||||||
return this.leagueService.getLeagueStats(leagueId);
|
return this.leagueService.getLeagueStats(leagueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':leagueId/admin')
|
@Get(':leagueId/admin')
|
||||||
@ApiOperation({ summary: 'Get league admin data' })
|
@ApiOperation({ summary: 'Get league admin data' })
|
||||||
@ApiResponse({ status: 200, description: 'League admin data', type: LeagueAdminViewModel })
|
@ApiResponse({ status: 200, description: 'League admin data', type: LeagueAdminDTO })
|
||||||
async getLeagueAdmin(@Param('leagueId') leagueId: string): Promise<LeagueAdminViewModel> {
|
async getLeagueAdmin(@Param('leagueId') leagueId: string): Promise<LeagueAdminDTO> {
|
||||||
return this.leagueService.getLeagueAdmin(leagueId);
|
return this.leagueService.getLeagueAdmin(leagueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a new league' })
|
@ApiOperation({ summary: 'Create a new league' })
|
||||||
@ApiBody({ type: CreateLeagueInput })
|
@ApiBody({ type: CreateLeagueInputDTO })
|
||||||
@ApiResponse({ status: 201, description: 'League created successfully', type: CreateLeagueOutput })
|
@ApiResponse({ status: 201, description: 'League created successfully', type: CreateLeagueOutputDTO })
|
||||||
async createLeague(@Body() input: CreateLeagueInput): Promise<CreateLeagueOutput> {
|
async createLeague(@Body() input: CreateLeagueInputDTO): Promise<CreateLeagueOutputDTO> {
|
||||||
return this.leagueService.createLeague(input);
|
return this.leagueService.createLeague(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('scoring-presets')
|
||||||
|
@ApiOperation({ summary: 'Get league scoring presets' })
|
||||||
|
@ApiResponse({ status: 200, description: 'List of scoring presets' })
|
||||||
|
async getLeagueScoringPresets() {
|
||||||
|
return this.leagueService.listLeagueScoringPresets();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':leagueId/scoring-config')
|
||||||
|
@ApiOperation({ summary: 'Get league scoring config' })
|
||||||
|
@ApiResponse({ status: 200, description: 'League scoring config' })
|
||||||
|
async getLeagueScoringConfig(@Param('leagueId') leagueId: string) {
|
||||||
|
return this.leagueService.getLeagueScoringConfig(leagueId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post(':leagueId/join')
|
||||||
|
@ApiOperation({ summary: 'Join a league' })
|
||||||
|
@ApiResponse({ status: 200, description: 'Joined league successfully' })
|
||||||
|
async joinLeague(@Param('leagueId') leagueId: string, @Body() body: { driverId: string }) {
|
||||||
|
return this.leagueService.joinLeague(leagueId, body.driverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post(':leagueId/transfer-ownership')
|
||||||
|
@ApiOperation({ summary: 'Transfer league ownership' })
|
||||||
|
@ApiResponse({ status: 200, description: 'Ownership transferred successfully' })
|
||||||
|
async transferLeagueOwnership(@Param('leagueId') leagueId: string, @Body() body: { currentOwnerId: string, newOwnerId: string }) {
|
||||||
|
return this.leagueService.transferLeagueOwnership(leagueId, body.currentOwnerId, body.newOwnerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,32 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { AllLeaguesWithCapacityViewModel, LeagueStatsDto, LeagueJoinRequestViewModel, ApproveJoinRequestInput, ApproveJoinRequestOutput, RejectJoinRequestInput, RejectJoinRequestOutput, LeagueAdminPermissionsViewModel, RemoveLeagueMemberInput, RemoveLeagueMemberOutput, UpdateLeagueMemberRoleInput, UpdateLeagueMemberRoleOutput, LeagueOwnerSummaryViewModel, LeagueConfigFormModelDto, LeagueAdminProtestsViewModel, LeagueSeasonSummaryViewModel, GetLeagueAdminPermissionsInput, GetLeagueProtestsQuery, GetLeagueSeasonsQuery, GetLeagueAdminConfigQuery, GetLeagueOwnerSummaryQuery, LeagueMembershipsViewModel, LeagueStandingsViewModel, LeagueScheduleViewModel, LeagueStatsViewModel, LeagueAdminViewModel, CreateLeagueInput, CreateLeagueOutput } from './dto/LeagueDto';
|
import { AllLeaguesWithCapacityDTO } from './dtos/AllLeaguesWithCapacityDTO';
|
||||||
|
import { LeagueStatsDTO } from './dtos/LeagueStatsDTO';
|
||||||
|
import { LeagueJoinRequestDTO } from './dtos/LeagueJoinRequestDTO';
|
||||||
|
import { ApproveJoinRequestInputDTO } from './dtos/ApproveJoinRequestInputDTO';
|
||||||
|
import { ApproveJoinRequestOutputDTO } from './dtos/ApproveJoinRequestOutputDTO';
|
||||||
|
import { RejectJoinRequestInputDTO } from './dtos/RejectJoinRequestInputDTO';
|
||||||
|
import { RejectJoinRequestOutputDTO } from './dtos/RejectJoinRequestOutputDTO';
|
||||||
|
import { LeagueAdminPermissionsDTO } from './dtos/LeagueAdminPermissionsDTO';
|
||||||
|
import { RemoveLeagueMemberInputDTO } from './dtos/RemoveLeagueMemberInputDTO';
|
||||||
|
import { RemoveLeagueMemberOutputDTO } from './dtos/RemoveLeagueMemberOutputDTO';
|
||||||
|
import { UpdateLeagueMemberRoleInputDTO } from './dtos/UpdateLeagueMemberRoleInputDTO';
|
||||||
|
import { UpdateLeagueMemberRoleOutputDTO } from './dtos/UpdateLeagueMemberRoleOutputDTO';
|
||||||
|
import { LeagueOwnerSummaryDTO } from './dtos/LeagueOwnerSummaryDTO';
|
||||||
|
import { LeagueConfigFormModelDTO } from './dtos/LeagueConfigFormModelDTO';
|
||||||
|
import { LeagueAdminProtestsDTO } from './dtos/LeagueAdminProtestsDTO';
|
||||||
|
import { LeagueSeasonSummaryDTO } from './dtos/LeagueSeasonSummaryDTO';
|
||||||
|
import { GetLeagueAdminPermissionsInputDTO } from './dtos/GetLeagueAdminPermissionsInputDTO';
|
||||||
|
import { GetLeagueProtestsQueryDTO } from './dtos/GetLeagueProtestsQueryDTO';
|
||||||
|
import { GetLeagueSeasonsQueryDTO } from './dtos/GetLeagueSeasonsQueryDTO';
|
||||||
|
import { GetLeagueAdminConfigQueryDTO } from './dtos/GetLeagueAdminConfigQueryDTO';
|
||||||
|
import { GetLeagueOwnerSummaryQueryDTO } from './dtos/GetLeagueOwnerSummaryQueryDTO';
|
||||||
|
import { LeagueMembershipsDTO } from './dtos/LeagueMembershipsDTO';
|
||||||
|
import { LeagueStandingsDTO } from './dtos/LeagueStandingsDTO';
|
||||||
|
import { LeagueScheduleDTO } from './dtos/LeagueScheduleDTO';
|
||||||
|
import { LeagueStatsDTO } from './dtos/LeagueStatsDTO';
|
||||||
|
import { LeagueAdminDTO } from './dtos/LeagueAdminDTO';
|
||||||
|
import { CreateLeagueInputDTO } from './dtos/CreateLeagueInputDTO';
|
||||||
|
import { CreateLeagueOutputDTO } from './dtos/CreateLeagueOutputDTO';
|
||||||
|
|
||||||
// Core imports
|
// Core imports
|
||||||
import type { Logger } from '@core/shared/application/Logger';
|
import type { Logger } from '@core/shared/application/Logger';
|
||||||
@@ -9,6 +36,10 @@ import { GetAllLeaguesWithCapacityUseCase } from '@core/racing/application/use-c
|
|||||||
import { GetLeagueStandingsUseCase } from '@core/racing/application/use-cases/GetLeagueStandingsUseCase';
|
import { GetLeagueStandingsUseCase } from '@core/racing/application/use-cases/GetLeagueStandingsUseCase';
|
||||||
import { GetLeagueStatsUseCase } from '@core/racing/application/use-cases/GetLeagueStatsUseCase';
|
import { GetLeagueStatsUseCase } from '@core/racing/application/use-cases/GetLeagueStatsUseCase';
|
||||||
import { GetLeagueFullConfigUseCase } from '@core/racing/application/use-cases/GetLeagueFullConfigUseCase';
|
import { GetLeagueFullConfigUseCase } from '@core/racing/application/use-cases/GetLeagueFullConfigUseCase';
|
||||||
|
import { GetLeagueScoringConfigUseCase } from '@core/racing/application/use-cases/GetLeagueScoringConfigUseCase';
|
||||||
|
import { ListLeagueScoringPresetsUseCase } from '@core/racing/application/use-cases/ListLeagueScoringPresetsUseCase';
|
||||||
|
import { JoinLeagueUseCase } from '@core/racing/application/use-cases/JoinLeagueUseCase';
|
||||||
|
import { TransferLeagueOwnershipUseCase } from '@core/racing/application/use-cases/TransferLeagueOwnershipUseCase';
|
||||||
import { CreateLeagueWithSeasonAndScoringUseCase } from '@core/racing/application/use-cases/CreateLeagueWithSeasonAndScoringUseCase';
|
import { CreateLeagueWithSeasonAndScoringUseCase } from '@core/racing/application/use-cases/CreateLeagueWithSeasonAndScoringUseCase';
|
||||||
import { GetRaceProtestsUseCase } from '@core/racing/application/use-cases/GetRaceProtestsUseCase';
|
import { GetRaceProtestsUseCase } from '@core/racing/application/use-cases/GetRaceProtestsUseCase';
|
||||||
import { GetTotalLeaguesUseCase } from '@core/racing/application/use-cases/GetTotalLeaguesUseCase';
|
import { GetTotalLeaguesUseCase } from '@core/racing/application/use-cases/GetTotalLeaguesUseCase';
|
||||||
@@ -27,6 +58,8 @@ import { GetLeagueAdminPermissionsUseCase } from '@core/racing/application/use-c
|
|||||||
// API Presenters
|
// API Presenters
|
||||||
import { LeagueStandingsPresenter } from './presenters/LeagueStandingsPresenter';
|
import { LeagueStandingsPresenter } from './presenters/LeagueStandingsPresenter';
|
||||||
import { AllLeaguesWithCapacityPresenter } from './presenters/AllLeaguesWithCapacityPresenter';
|
import { AllLeaguesWithCapacityPresenter } from './presenters/AllLeaguesWithCapacityPresenter';
|
||||||
|
import { LeagueScoringConfigPresenter } from './presenters/LeagueScoringConfigPresenter';
|
||||||
|
import { LeagueScoringPresetsPresenter } from './presenters/LeagueScoringPresetsPresenter';
|
||||||
import { LeagueJoinRequestsPresenter } from './presenters/LeagueJoinRequestsPresenter';
|
import { LeagueJoinRequestsPresenter } from './presenters/LeagueJoinRequestsPresenter';
|
||||||
import { ApproveLeagueJoinRequestPresenter } from './presenters/ApproveLeagueJoinRequestPresenter';
|
import { ApproveLeagueJoinRequestPresenter } from './presenters/ApproveLeagueJoinRequestPresenter';
|
||||||
import { RejectLeagueJoinRequestPresenter } from './presenters/RejectLeagueJoinRequestPresenter';
|
import { RejectLeagueJoinRequestPresenter } from './presenters/RejectLeagueJoinRequestPresenter';
|
||||||
@@ -52,6 +85,10 @@ export class LeagueService {
|
|||||||
private readonly getLeagueStandingsUseCase: GetLeagueStandingsUseCase,
|
private readonly getLeagueStandingsUseCase: GetLeagueStandingsUseCase,
|
||||||
private readonly getLeagueStatsUseCase: GetLeagueStatsUseCase,
|
private readonly getLeagueStatsUseCase: GetLeagueStatsUseCase,
|
||||||
private readonly getLeagueFullConfigUseCase: GetLeagueFullConfigUseCase,
|
private readonly getLeagueFullConfigUseCase: GetLeagueFullConfigUseCase,
|
||||||
|
private readonly getLeagueScoringConfigUseCase: GetLeagueScoringConfigUseCase,
|
||||||
|
private readonly listLeagueScoringPresetsUseCase: ListLeagueScoringPresetsUseCase,
|
||||||
|
private readonly joinLeagueUseCase: JoinLeagueUseCase,
|
||||||
|
private readonly transferLeagueOwnershipUseCase: TransferLeagueOwnershipUseCase,
|
||||||
private readonly createLeagueWithSeasonAndScoringUseCase: CreateLeagueWithSeasonAndScoringUseCase,
|
private readonly createLeagueWithSeasonAndScoringUseCase: CreateLeagueWithSeasonAndScoringUseCase,
|
||||||
private readonly getRaceProtestsUseCase: GetRaceProtestsUseCase,
|
private readonly getRaceProtestsUseCase: GetRaceProtestsUseCase,
|
||||||
private readonly getTotalLeaguesUseCase: GetTotalLeaguesUseCase,
|
private readonly getTotalLeaguesUseCase: GetTotalLeaguesUseCase,
|
||||||
@@ -234,4 +271,61 @@ export class LeagueService {
|
|||||||
success: true,
|
success: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLeagueScoringConfig(leagueId: string): Promise<LeagueScoringConfigViewModel | null> {
|
||||||
|
this.logger.debug('Getting league scoring config', { leagueId });
|
||||||
|
|
||||||
|
const presenter = new LeagueScoringConfigPresenter();
|
||||||
|
try {
|
||||||
|
const result = await this.getLeagueScoringConfigUseCase.execute({ leagueId });
|
||||||
|
if (result.isErr()) {
|
||||||
|
this.logger.error('Error getting league scoring config', result.error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
await presenter.present(result.value);
|
||||||
|
return presenter.getViewModel();
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Error getting league scoring config', error instanceof Error ? error : new Error(String(error)));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async listLeagueScoringPresets(): Promise<LeagueScoringPresetsViewModel> {
|
||||||
|
this.logger.debug('Listing league scoring presets');
|
||||||
|
|
||||||
|
const presenter = new LeagueScoringPresetsPresenter();
|
||||||
|
await this.listLeagueScoringPresetsUseCase.execute(undefined, presenter);
|
||||||
|
return presenter.getViewModel()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
async joinLeague(leagueId: string, driverId: string): Promise<JoinLeagueOutput> {
|
||||||
|
this.logger.debug('Joining league', { leagueId, driverId });
|
||||||
|
|
||||||
|
const result = await this.joinLeagueUseCase.execute({ leagueId, driverId });
|
||||||
|
if (result.isErr()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error.code,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
membershipId: result.value.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async transferLeagueOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<TransferLeagueOwnershipOutput> {
|
||||||
|
this.logger.debug('Transferring league ownership', { leagueId, currentOwnerId, newOwnerId });
|
||||||
|
|
||||||
|
const result = await this.transferLeagueOwnershipUseCase.execute({ leagueId, currentOwnerId, newOwnerId });
|
||||||
|
if (result.isErr()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: result.error.code,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,666 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsString, IsNumber, IsBoolean, IsDate, IsOptional, IsEnum, IsArray, ValidateNested } from 'class-validator';
|
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
import { DriverDto } from '../../driver/dto/DriverDto';
|
|
||||||
import { RaceDto } from '../../race/dto/RaceDto';
|
|
||||||
|
|
||||||
|
|
||||||
export class LeagueSettingsDto {
|
|
||||||
@ApiProperty({ nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@IsNumber()
|
|
||||||
maxDrivers?: number;
|
|
||||||
// Add other league settings properties as needed
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueWithCapacityViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
// ... other properties of LeagueWithCapacityViewModel
|
|
||||||
@ApiProperty({ nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
description?: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
ownerId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => LeagueSettingsDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueSettingsDto)
|
|
||||||
settings: LeagueSettingsDto;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
createdAt: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
usedSlots: number;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => Object, nullable: true }) // Using Object for generic social links
|
|
||||||
@IsOptional()
|
|
||||||
socialLinks?: {
|
|
||||||
discordUrl?: string;
|
|
||||||
youtubeUrl?: string;
|
|
||||||
websiteUrl?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AllLeaguesWithCapacityViewModel {
|
|
||||||
@ApiProperty({ type: [LeagueWithCapacityViewModel] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => LeagueWithCapacityViewModel)
|
|
||||||
leagues: LeagueWithCapacityViewModel[];
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
totalCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueStatsDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
totalLeagues: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ProtestDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
raceId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
protestingDriverId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
accusedDriverId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
submittedAt: Date;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['pending', 'accepted', 'rejected'] })
|
|
||||||
@IsEnum(['pending', 'accepted', 'rejected'])
|
|
||||||
status: 'pending' | 'accepted' | 'rejected';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SeasonDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
seasonId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
startDate?: Date;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
endDate?: Date;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['planned', 'active', 'completed'] })
|
|
||||||
@IsEnum(['planned', 'active', 'completed'])
|
|
||||||
status: 'planned' | 'active' | 'completed';
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
isPrimary: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
seasonGroupId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueJoinRequestViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
driverId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
requestedAt: Date;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
message?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => DriverDto, required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => DriverDto)
|
|
||||||
driver?: DriverDto;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueJoinRequestsQuery {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ApproveJoinRequestInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
requestId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ApproveJoinRequestOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsString()
|
|
||||||
message?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RejectJoinRequestInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
requestId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RejectJoinRequestOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsString()
|
|
||||||
message?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueAdminPermissionsInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
performerDriverId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueAdminPermissionsViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
canRemoveMember: boolean;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
canUpdateRoles: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RemoveLeagueMemberInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
performerDriverId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
targetDriverId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RemoveLeagueMemberOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UpdateLeagueMemberRoleInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
performerDriverId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
targetDriverId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['owner', 'manager', 'member'] })
|
|
||||||
@IsEnum(['owner', 'manager', 'member'])
|
|
||||||
newRole: 'owner' | 'manager' | 'member';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UpdateLeagueMemberRoleOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueOwnerSummaryQuery {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
ownerId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueOwnerSummaryViewModel {
|
|
||||||
@ApiProperty({ type: () => DriverDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => DriverDto)
|
|
||||||
driver: DriverDto;
|
|
||||||
|
|
||||||
@ApiProperty({ nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@IsNumber()
|
|
||||||
rating: number | null;
|
|
||||||
|
|
||||||
@ApiProperty({ nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@IsNumber()
|
|
||||||
rank: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelBasicsDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['public', 'private'] })
|
|
||||||
@IsEnum(['public', 'private'])
|
|
||||||
visibility: 'public' | 'private';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelStructureDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsEnum(['solo', 'team'])
|
|
||||||
mode: 'solo' | 'team';
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelScoringDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
type: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
points: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelDropPolicyDto {
|
|
||||||
@ApiProperty({ enum: ['none', 'worst_n'] })
|
|
||||||
@IsEnum(['none', 'worst_n'])
|
|
||||||
strategy: 'none' | 'worst_n';
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsNumber()
|
|
||||||
n?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelStewardingDto {
|
|
||||||
@ApiProperty({ enum: ['single_steward', 'committee_vote'] })
|
|
||||||
@IsEnum(['single_steward', 'committee_vote'])
|
|
||||||
decisionMode: 'single_steward' | 'committee_vote';
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsNumber()
|
|
||||||
requiredVotes?: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
requireDefense: boolean;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
defenseTimeLimit: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
voteTimeLimit: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
protestDeadlineHours: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
stewardingClosesHours: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
notifyAccusedOnProtest: boolean;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
notifyOnVoteRequired: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelTimingsDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
raceDayOfWeek: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
raceTimeHour: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
raceTimeMinute: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueConfigFormModelDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: LeagueConfigFormModelBasicsDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelBasicsDto)
|
|
||||||
basics: LeagueConfigFormModelBasicsDto;
|
|
||||||
|
|
||||||
@ApiProperty({ type: LeagueConfigFormModelStructureDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelStructureDto)
|
|
||||||
structure: LeagueConfigFormModelStructureDto;
|
|
||||||
|
|
||||||
@ApiProperty({ type: [Object] })
|
|
||||||
@IsArray()
|
|
||||||
championships: any[];
|
|
||||||
|
|
||||||
@ApiProperty({ type: LeagueConfigFormModelScoringDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelScoringDto)
|
|
||||||
scoring: LeagueConfigFormModelScoringDto;
|
|
||||||
|
|
||||||
@ApiProperty({ type: LeagueConfigFormModelDropPolicyDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelDropPolicyDto)
|
|
||||||
dropPolicy: LeagueConfigFormModelDropPolicyDto;
|
|
||||||
|
|
||||||
@ApiProperty({ type: LeagueConfigFormModelTimingsDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelTimingsDto)
|
|
||||||
timings: LeagueConfigFormModelTimingsDto;
|
|
||||||
|
|
||||||
@ApiProperty({ type: LeagueConfigFormModelStewardingDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelStewardingDto)
|
|
||||||
stewarding: LeagueConfigFormModelStewardingDto;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueAdminConfigQuery {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueAdminConfigOutput {
|
|
||||||
@ApiProperty({ type: () => LeagueConfigFormModelDto, nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelDto)
|
|
||||||
form: LeagueConfigFormModelDto | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueAdminConfigViewModel {
|
|
||||||
@ApiProperty({ type: () => LeagueConfigFormModelDto, nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueConfigFormModelDto)
|
|
||||||
form: LeagueConfigFormModelDto | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueProtestsQuery {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueAdminProtestsViewModel {
|
|
||||||
@ApiProperty({ type: [ProtestDto] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => ProtestDto)
|
|
||||||
protests: ProtestDto[];
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => RaceDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => RaceDto)
|
|
||||||
racesById: { [raceId: string]: RaceDto };
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => DriverDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => DriverDto)
|
|
||||||
driversById: { [driverId: string]: DriverDto };
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GetLeagueSeasonsQuery {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueSeasonSummaryViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
seasonId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
status: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
startDate?: Date;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
endDate?: Date;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
isPrimary: boolean;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
isParallelActive: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueAdminViewModel {
|
|
||||||
@ApiProperty({ type: [LeagueJoinRequestViewModel] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => LeagueJoinRequestViewModel)
|
|
||||||
joinRequests: LeagueJoinRequestViewModel[];
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => LeagueOwnerSummaryViewModel, nullable: true })
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueOwnerSummaryViewModel)
|
|
||||||
ownerSummary: LeagueOwnerSummaryViewModel | null;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => LeagueAdminConfigViewModel })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueAdminConfigViewModel)
|
|
||||||
config: LeagueAdminConfigViewModel;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => LeagueAdminProtestsViewModel })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => LeagueAdminProtestsViewModel)
|
|
||||||
protests: LeagueAdminProtestsViewModel;
|
|
||||||
|
|
||||||
@ApiProperty({ type: [LeagueSeasonSummaryViewModel] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => LeagueSeasonSummaryViewModel)
|
|
||||||
seasons: LeagueSeasonSummaryViewModel[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueMemberDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
driverId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => DriverDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => DriverDto)
|
|
||||||
driver: DriverDto;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['owner', 'manager', 'member'] })
|
|
||||||
@IsEnum(['owner', 'manager', 'member'])
|
|
||||||
role: 'owner' | 'manager' | 'member';
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsDate()
|
|
||||||
@Type(() => Date)
|
|
||||||
joinedAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueMembershipsViewModel {
|
|
||||||
@ApiProperty({ type: [LeagueMemberDto] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => LeagueMemberDto)
|
|
||||||
members: LeagueMemberDto[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueStandingDto {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
driverId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: () => DriverDto })
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => DriverDto)
|
|
||||||
driver: DriverDto;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
points: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
rank: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueStandingsViewModel {
|
|
||||||
@ApiProperty({ type: [LeagueStandingDto] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => LeagueStandingDto)
|
|
||||||
standings: LeagueStandingDto[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueScheduleViewModel {
|
|
||||||
@ApiProperty({ type: [RaceDto] })
|
|
||||||
@IsArray()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => RaceDto)
|
|
||||||
races: RaceDto[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LeagueStatsViewModel {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
totalMembers: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
totalRaces: number;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsNumber()
|
|
||||||
averageRating: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CreateLeagueInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: ['public', 'private'] })
|
|
||||||
@IsEnum(['public', 'private'])
|
|
||||||
visibility: 'public' | 'private';
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
ownerId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CreateLeagueOutput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
leagueId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber, IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueSummaryDTO } from './LeagueSummaryDTO';
|
||||||
|
|
||||||
|
export class AllLeaguesWithCapacityAndScoringDTO {
|
||||||
|
@ApiProperty({ type: [LeagueSummaryDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => LeagueSummaryDTO)
|
||||||
|
leagues: LeagueSummaryDTO[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
totalCount: number;
|
||||||
|
}
|
||||||
16
apps/api/src/domain/league/dtos/AllLeaguesWithCapacityDTO.ts
Normal file
16
apps/api/src/domain/league/dtos/AllLeaguesWithCapacityDTO.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber, IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueWithCapacityDTO } from './LeagueWithCapacityDTO';
|
||||||
|
|
||||||
|
export class AllLeaguesWithCapacityDTO {
|
||||||
|
@ApiProperty({ type: [LeagueWithCapacityDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => LeagueWithCapacityDTO)
|
||||||
|
leagues: LeagueWithCapacityDTO[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
totalCount: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class ApproveJoinRequestInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
requestId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsBoolean } from 'class-validator';
|
||||||
|
|
||||||
|
export class ApproveJoinRequestOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsString()
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
20
apps/api/src/domain/league/dtos/CreateLeagueInputDTO.ts
Normal file
20
apps/api/src/domain/league/dtos/CreateLeagueInputDTO.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateLeagueInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['public', 'private'] })
|
||||||
|
@IsEnum(['public', 'private'])
|
||||||
|
visibility: 'public' | 'private';
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
ownerId: string;
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/CreateLeagueOutputDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/CreateLeagueOutputDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsBoolean } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateLeagueOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsOptional, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueConfigFormModelDTO } from './LeagueConfigFormModelDTO';
|
||||||
|
|
||||||
|
export class GetLeagueAdminConfigOutputDTO {
|
||||||
|
@ApiProperty({ type: () => LeagueConfigFormModelDTO, nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelDTO)
|
||||||
|
form: LeagueConfigFormModelDTO | null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetLeagueAdminConfigQueryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetLeagueAdminPermissionsInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
performerDriverId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetLeagueJoinRequestsQueryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetLeagueOwnerSummaryQueryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
ownerId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetLeagueProtestsQueryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetLeagueSeasonsQueryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/LeagueAdminConfigDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/LeagueAdminConfigDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsOptional, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueConfigFormModelDTO } from './LeagueConfigFormModelDTO';
|
||||||
|
|
||||||
|
export class LeagueAdminConfigDTO {
|
||||||
|
@ApiProperty({ type: () => LeagueConfigFormModelDTO, nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelDTO)
|
||||||
|
form: LeagueConfigFormModelDTO | null;
|
||||||
|
}
|
||||||
38
apps/api/src/domain/league/dtos/LeagueAdminDTO.ts
Normal file
38
apps/api/src/domain/league/dtos/LeagueAdminDTO.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsOptional, IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueJoinRequestDTO } from './LeagueJoinRequestDTO';
|
||||||
|
import { LeagueOwnerSummaryDTO } from './LeagueOwnerSummaryDTO';
|
||||||
|
import { LeagueAdminConfigDTO } from './LeagueAdminConfigDTO';
|
||||||
|
import { LeagueAdminProtestsDTO } from './LeagueAdminProtestsDTO';
|
||||||
|
import { LeagueSeasonSummaryDTO } from './LeagueSeasonSummaryDTO';
|
||||||
|
|
||||||
|
export class LeagueAdminDTO {
|
||||||
|
@ApiProperty({ type: [LeagueJoinRequestDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => LeagueJoinRequestDTO)
|
||||||
|
joinRequests: LeagueJoinRequestDTO[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => LeagueOwnerSummaryDTO, nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueOwnerSummaryDTO)
|
||||||
|
ownerSummary: LeagueOwnerSummaryDTO | null;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => LeagueAdminConfigDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueAdminConfigDTO)
|
||||||
|
config: LeagueAdminConfigDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => LeagueAdminProtestsDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueAdminProtestsDTO)
|
||||||
|
protests: LeagueAdminProtestsDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: [LeagueSeasonSummaryDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => LeagueSeasonSummaryDTO)
|
||||||
|
seasons: LeagueSeasonSummaryDTO[];
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/LeagueAdminPermissionsDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/LeagueAdminPermissionsDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsBoolean } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueAdminPermissionsDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
canRemoveMember: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
canUpdateRoles: boolean;
|
||||||
|
}
|
||||||
24
apps/api/src/domain/league/dtos/LeagueAdminProtestsDTO.ts
Normal file
24
apps/api/src/domain/league/dtos/LeagueAdminProtestsDTO.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { DriverDto } from '../../driver/dto/DriverDto';
|
||||||
|
import { RaceDto } from '../../race/dto/RaceDto';
|
||||||
|
import { ProtestDTO } from './ProtestDTO';
|
||||||
|
|
||||||
|
export class LeagueAdminProtestsDTO {
|
||||||
|
@ApiProperty({ type: [ProtestDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => ProtestDTO)
|
||||||
|
protests: ProtestDTO[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => RaceDto })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => RaceDto)
|
||||||
|
racesById: { [raceId: string]: RaceDto };
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => DriverDto })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => DriverDto)
|
||||||
|
driversById: { [driverId: string]: DriverDto };
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelBasicsDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['public', 'private'] })
|
||||||
|
@IsEnum(['public', 'private'])
|
||||||
|
visibility: 'public' | 'private';
|
||||||
|
}
|
||||||
49
apps/api/src/domain/league/dtos/LeagueConfigFormModelDTO.ts
Normal file
49
apps/api/src/domain/league/dtos/LeagueConfigFormModelDTO.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueConfigFormModelBasicsDTO } from './LeagueConfigFormModelBasicsDTO';
|
||||||
|
import { LeagueConfigFormModelStructureDTO } from './LeagueConfigFormModelStructureDTO';
|
||||||
|
import { LeagueConfigFormModelScoringDTO } from './LeagueConfigFormModelScoringDTO';
|
||||||
|
import { LeagueConfigFormModelDropPolicyDTO } from './LeagueConfigFormModelDropPolicyDTO';
|
||||||
|
import { LeagueConfigFormModelStewardingDTO } from './LeagueConfigFormModelStewardingDTO';
|
||||||
|
import { LeagueConfigFormModelTimingsDTO } from './LeagueConfigFormModelTimingsDTO';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: LeagueConfigFormModelBasicsDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelBasicsDTO)
|
||||||
|
basics: LeagueConfigFormModelBasicsDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: LeagueConfigFormModelStructureDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelStructureDTO)
|
||||||
|
structure: LeagueConfigFormModelStructureDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: [Object] })
|
||||||
|
@IsArray()
|
||||||
|
championships: any[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: LeagueConfigFormModelScoringDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelScoringDTO)
|
||||||
|
scoring: LeagueConfigFormModelScoringDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: LeagueConfigFormModelDropPolicyDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelDropPolicyDTO)
|
||||||
|
dropPolicy: LeagueConfigFormModelDropPolicyDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: LeagueConfigFormModelTimingsDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelTimingsDTO)
|
||||||
|
timings: LeagueConfigFormModelTimingsDTO;
|
||||||
|
|
||||||
|
@ApiProperty({ type: LeagueConfigFormModelStewardingDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueConfigFormModelStewardingDTO)
|
||||||
|
stewarding: LeagueConfigFormModelStewardingDTO;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber, IsOptional, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelDropPolicyDTO {
|
||||||
|
@ApiProperty({ enum: ['none', 'worst_n'] })
|
||||||
|
@IsEnum(['none', 'worst_n'])
|
||||||
|
strategy: 'none' | 'worst_n';
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
n?: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelScoringDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
points: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber, IsBoolean, IsOptional, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelStewardingDTO {
|
||||||
|
@ApiProperty({ enum: ['single_steward', 'committee_vote'] })
|
||||||
|
@IsEnum(['single_steward', 'committee_vote'])
|
||||||
|
decisionMode: 'single_steward' | 'committee_vote';
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
requiredVotes?: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
requireDefense: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
defenseTimeLimit: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
voteTimeLimit: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
protestDeadlineHours: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
stewardingClosesHours: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
notifyAccusedOnProtest: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
notifyOnVoteRequired: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelStructureDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsEnum(['solo', 'team'])
|
||||||
|
mode: 'solo' | 'team';
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueConfigFormModelTimingsDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
raceDayOfWeek: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
raceTimeHour: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
raceTimeMinute: number;
|
||||||
|
}
|
||||||
34
apps/api/src/domain/league/dtos/LeagueJoinRequestDTO.ts
Normal file
34
apps/api/src/domain/league/dtos/LeagueJoinRequestDTO.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsDate, IsOptional, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { DriverDto } from '../../driver/dto/DriverDto';
|
||||||
|
|
||||||
|
export class LeagueJoinRequestDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
driverId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
requestedAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
message?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => DriverDto, required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => DriverDto)
|
||||||
|
driver?: DriverDto;
|
||||||
|
}
|
||||||
24
apps/api/src/domain/league/dtos/LeagueMemberDTO.ts
Normal file
24
apps/api/src/domain/league/dtos/LeagueMemberDTO.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsDate, IsEnum, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { DriverDto } from '../../driver/dto/DriverDto';
|
||||||
|
|
||||||
|
export class LeagueMemberDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
driverId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => DriverDto })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => DriverDto)
|
||||||
|
driver: DriverDto;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['owner', 'manager', 'member'] })
|
||||||
|
@IsEnum(['owner', 'manager', 'member'])
|
||||||
|
role: 'owner' | 'manager' | 'member';
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
joinedAt: Date;
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/LeagueMembershipsDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/LeagueMembershipsDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueMemberDTO } from './LeagueMemberDTO';
|
||||||
|
|
||||||
|
export class LeagueMembershipsDTO {
|
||||||
|
@ApiProperty({ type: [LeagueMemberDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => LeagueMemberDTO)
|
||||||
|
members: LeagueMemberDTO[];
|
||||||
|
}
|
||||||
21
apps/api/src/domain/league/dtos/LeagueOwnerSummaryDTO.ts
Normal file
21
apps/api/src/domain/league/dtos/LeagueOwnerSummaryDTO.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber, IsOptional, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { DriverDto } from '../../driver/dto/DriverDto';
|
||||||
|
|
||||||
|
export class LeagueOwnerSummaryDTO {
|
||||||
|
@ApiProperty({ type: () => DriverDto })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => DriverDto)
|
||||||
|
driver: DriverDto;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
rating: number | null;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
rank: number | null;
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/LeagueScheduleDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/LeagueScheduleDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { RaceDto } from '../../race/dto/RaceDto';
|
||||||
|
|
||||||
|
export class LeagueScheduleDTO {
|
||||||
|
@ApiProperty({ type: [RaceDto] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => RaceDto)
|
||||||
|
races: RaceDto[];
|
||||||
|
}
|
||||||
37
apps/api/src/domain/league/dtos/LeagueSeasonSummaryDTO.ts
Normal file
37
apps/api/src/domain/league/dtos/LeagueSeasonSummaryDTO.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsBoolean, IsDate, IsOptional } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class LeagueSeasonSummaryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
seasonId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
status: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
startDate?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
endDate?: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
isPrimary: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
isParallelActive: boolean;
|
||||||
|
}
|
||||||
10
apps/api/src/domain/league/dtos/LeagueSettingsDTO.ts
Normal file
10
apps/api/src/domain/league/dtos/LeagueSettingsDTO.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber, IsOptional } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueSettingsDTO {
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
maxDrivers?: number;
|
||||||
|
// Add other league settings properties as needed
|
||||||
|
}
|
||||||
23
apps/api/src/domain/league/dtos/LeagueStandingDTO.ts
Normal file
23
apps/api/src/domain/league/dtos/LeagueStandingDTO.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { DriverDto } from '../../driver/dto/DriverDto';
|
||||||
|
|
||||||
|
export class LeagueStandingDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
driverId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => DriverDto })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => DriverDto)
|
||||||
|
driver: DriverDto;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
points: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
rank: number;
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/LeagueStandingsDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/LeagueStandingsDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsArray, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueStandingDTO } from './LeagueStandingDTO';
|
||||||
|
|
||||||
|
export class LeagueStandingsDTO {
|
||||||
|
@ApiProperty({ type: [LeagueStandingDTO] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => LeagueStandingDTO)
|
||||||
|
standings: LeagueStandingDTO[];
|
||||||
|
}
|
||||||
16
apps/api/src/domain/league/dtos/LeagueStatsDTO.ts
Normal file
16
apps/api/src/domain/league/dtos/LeagueStatsDTO.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNumber } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueStatsDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
totalMembers: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
totalRaces: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
averageRating: number;
|
||||||
|
}
|
||||||
58
apps/api/src/domain/league/dtos/LeagueSummaryDTO.ts
Normal file
58
apps/api/src/domain/league/dtos/LeagueSummaryDTO.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber, IsBoolean, IsOptional } from 'class-validator';
|
||||||
|
|
||||||
|
export class LeagueSummaryDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
logoUrl?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
coverImage?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
memberCount: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
maxMembers: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
isPublic: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
ownerId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
ownerName?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
scoringType?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
45
apps/api/src/domain/league/dtos/LeagueWithCapacityDTO.ts
Normal file
45
apps/api/src/domain/league/dtos/LeagueWithCapacityDTO.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber, IsOptional, ValidateNested } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { LeagueSettingsDTO } from './LeagueSettingsDTO';
|
||||||
|
|
||||||
|
export class LeagueWithCapacityDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
// ... other properties of LeagueWithCapacityDTO
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
ownerId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => LeagueSettingsDTO })
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => LeagueSettingsDTO)
|
||||||
|
settings: LeagueSettingsDTO;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
createdAt: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
usedSlots: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => Object, nullable: true }) // Using Object for generic social links
|
||||||
|
@IsOptional()
|
||||||
|
socialLinks?: {
|
||||||
|
discordUrl?: string;
|
||||||
|
youtubeUrl?: string;
|
||||||
|
websiteUrl?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
36
apps/api/src/domain/league/dtos/ProtestDTO.ts
Normal file
36
apps/api/src/domain/league/dtos/ProtestDTO.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsDate, IsEnum } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
// TODO: protests are filed at race level but also managed on league level
|
||||||
|
|
||||||
|
export class ProtestDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
raceId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
protestingDriverId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
accusedDriverId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
submittedAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['pending', 'accepted', 'rejected'] })
|
||||||
|
@IsEnum(['pending', 'accepted', 'rejected'])
|
||||||
|
status: 'pending' | 'accepted' | 'rejected';
|
||||||
|
}
|
||||||
12
apps/api/src/domain/league/dtos/RejectJoinRequestInputDTO.ts
Normal file
12
apps/api/src/domain/league/dtos/RejectJoinRequestInputDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class RejectJoinRequestInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
requestId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsBoolean } from 'class-validator';
|
||||||
|
|
||||||
|
export class RejectJoinRequestOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsString()
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class RemoveLeagueMemberInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
performerDriverId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
targetDriverId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsBoolean } from 'class-validator';
|
||||||
|
|
||||||
|
export class RemoveLeagueMemberOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
42
apps/api/src/domain/league/dtos/SeasonDTO.ts
Normal file
42
apps/api/src/domain/league/dtos/SeasonDTO.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsBoolean, IsDate, IsOptional, IsEnum } from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class SeasonDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
seasonId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
startDate?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
endDate?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['planned', 'active', 'completed'] })
|
||||||
|
@IsEnum(['planned', 'active', 'completed'])
|
||||||
|
status: 'planned' | 'active' | 'completed';
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
isPrimary: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
seasonGroupId?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsEnum } from 'class-validator';
|
||||||
|
|
||||||
|
export class UpdateLeagueMemberRoleInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
performerDriverId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
targetDriverId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['owner', 'manager', 'member'] })
|
||||||
|
@IsEnum(['owner', 'manager', 'member'])
|
||||||
|
newRole: 'owner' | 'manager' | 'member';
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsBoolean } from 'class-validator';
|
||||||
|
|
||||||
|
export class UpdateLeagueMemberRoleOutputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IGetLeagueMembershipsPresenter, GetLeagueMembershipsResultDTO, GetLeagueMembershipsViewModel } from '@core/racing/application/presenters/IGetLeagueMembershipsPresenter';
|
import { IGetLeagueMembershipsPresenter, GetLeagueMembershipsResultDTO, GetLeagueMembershipsViewModel } from '@core/racing/application/presenters/IGetLeagueMembershipsPresenter';
|
||||||
import { LeagueMembershipsViewModel } from '../dto/LeagueDto';
|
import { LeagueMembershipsDTO } from '../dtos/LeagueMembershipsDTO';
|
||||||
|
|
||||||
export class GetLeagueMembershipsPresenter implements IGetLeagueMembershipsPresenter {
|
export class GetLeagueMembershipsPresenter implements IGetLeagueMembershipsPresenter {
|
||||||
private result: GetLeagueMembershipsViewModel | null = null;
|
private result: GetLeagueMembershipsViewModel | null = null;
|
||||||
@@ -40,7 +40,7 @@ export class GetLeagueMembershipsPresenter implements IGetLeagueMembershipsPrese
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API-specific method
|
// API-specific method
|
||||||
get apiViewModel(): LeagueMembershipsViewModel | null {
|
get apiViewModel(): LeagueMembershipsDTO | null {
|
||||||
if (!this.result?.memberships) return null;
|
if (!this.result?.memberships) return null;
|
||||||
return this.result.memberships as LeagueMembershipsViewModel;
|
return this.result.memberships as LeagueMembershipsViewModel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { LeagueAdminViewModel } from '../dto/LeagueDto';
|
import { LeagueAdminDTO } from '../dtos/LeagueAdminDTO';
|
||||||
|
|
||||||
export class LeagueAdminPresenter {
|
export class LeagueAdminPresenter {
|
||||||
private result: LeagueAdminViewModel | null = null;
|
private result: LeagueAdminDTO | null = null;
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.result = null;
|
this.result = null;
|
||||||
@@ -23,7 +23,7 @@ export class LeagueAdminPresenter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewModel(): LeagueAdminViewModel {
|
getViewModel(): LeagueAdminDTO {
|
||||||
if (!this.result) throw new Error('Presenter not presented');
|
if (!this.result) throw new Error('Presenter not presented');
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ILeagueFullConfigPresenter, LeagueFullConfigData, LeagueConfigFormViewModel } from '@core/racing/application/presenters/ILeagueFullConfigPresenter';
|
import { ILeagueFullConfigPresenter, LeagueFullConfigData, LeagueConfigFormViewModel } from '@core/racing/application/presenters/ILeagueFullConfigPresenter';
|
||||||
import { LeagueConfigFormModelDto } from '../dto/LeagueDto';
|
import { LeagueConfigFormModelDTO } from '../dtos/LeagueConfigFormModelDTO';
|
||||||
|
|
||||||
export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
|
export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
|
||||||
private result: LeagueConfigFormViewModel | null = null;
|
private result: LeagueConfigFormViewModel | null = null;
|
||||||
@@ -65,7 +65,7 @@ export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API-specific method to get the DTO
|
// API-specific method to get the DTO
|
||||||
get viewModel(): LeagueConfigFormModelDto | null {
|
get viewModel(): LeagueConfigFormModelDTO | null {
|
||||||
if (!this.result) return null;
|
if (!this.result) return null;
|
||||||
|
|
||||||
// Map from LeagueConfigFormViewModel to LeagueConfigFormModelDto
|
// Map from LeagueConfigFormViewModel to LeagueConfigFormModelDto
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import type { ChampionshipConfig } from '@core/racing/domain/types/ChampionshipConfig';
|
||||||
|
import type { BonusRule } from '@core/racing/domain/types/BonusRule';
|
||||||
|
import type {
|
||||||
|
ILeagueScoringConfigPresenter,
|
||||||
|
LeagueScoringConfigData,
|
||||||
|
LeagueScoringConfigViewModel,
|
||||||
|
LeagueScoringChampionshipViewModel,
|
||||||
|
} from '@core/racing/application/presenters/ILeagueScoringConfigPresenter';
|
||||||
|
|
||||||
|
export class LeagueScoringConfigPresenter implements ILeagueScoringConfigPresenter {
|
||||||
|
private viewModel: LeagueScoringConfigViewModel | null = null;
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.viewModel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
present(data: LeagueScoringConfigData): LeagueScoringConfigViewModel {
|
||||||
|
const championships: LeagueScoringChampionshipViewModel[] =
|
||||||
|
data.championships.map((champ) => this.mapChampionship(champ));
|
||||||
|
|
||||||
|
const dropPolicySummary =
|
||||||
|
data.preset?.dropPolicySummary ??
|
||||||
|
this.deriveDropPolicyDescriptionFromChampionships(data.championships);
|
||||||
|
|
||||||
|
this.viewModel = {
|
||||||
|
leagueId: data.leagueId,
|
||||||
|
seasonId: data.seasonId,
|
||||||
|
gameId: data.gameId,
|
||||||
|
gameName: data.gameName,
|
||||||
|
scoringPresetId: data.scoringPresetId ?? 'custom',
|
||||||
|
scoringPresetName: data.preset?.name ?? 'Custom',
|
||||||
|
dropPolicySummary,
|
||||||
|
championships,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
getViewModel(): LeagueScoringConfigViewModel | null {
|
||||||
|
return this.viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapChampionship(championship: ChampionshipConfig): LeagueScoringChampionshipViewModel {
|
||||||
|
const sessionTypes = championship.sessionTypes.map((s) => s.toString());
|
||||||
|
const pointsPreview = this.buildPointsPreview(championship.pointsTableBySessionType);
|
||||||
|
const bonusSummary = this.buildBonusSummary(
|
||||||
|
championship.bonusRulesBySessionType ?? {},
|
||||||
|
);
|
||||||
|
const dropPolicyDescription = this.deriveDropPolicyDescription(
|
||||||
|
championship.dropScorePolicy,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: championship.id,
|
||||||
|
name: championship.name,
|
||||||
|
type: championship.type,
|
||||||
|
sessionTypes,
|
||||||
|
pointsPreview,
|
||||||
|
bonusSummary,
|
||||||
|
dropPolicyDescription,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildPointsPreview(
|
||||||
|
tables: Record<string, { getPointsForPosition: (position: number) => number }>,
|
||||||
|
): Array<{ sessionType: string; position: number; points: number }> {
|
||||||
|
const preview: Array<{
|
||||||
|
sessionType: string;
|
||||||
|
position: number;
|
||||||
|
points: number;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
const maxPositions = 10;
|
||||||
|
|
||||||
|
for (const [sessionType, table] of Object.entries(tables)) {
|
||||||
|
for (let pos = 1; pos <= maxPositions; pos++) {
|
||||||
|
const points = table.getPointsForPosition(pos);
|
||||||
|
if (points && points !== 0) {
|
||||||
|
preview.push({
|
||||||
|
sessionType,
|
||||||
|
position: pos,
|
||||||
|
points,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildBonusSummary(
|
||||||
|
bonusRulesBySessionType: Record<string, BonusRule[]>,
|
||||||
|
): string[] {
|
||||||
|
const summaries: string[] = [];
|
||||||
|
|
||||||
|
for (const [sessionType, rules] of Object.entries(bonusRulesBySessionType)) {
|
||||||
|
for (const rule of rules) {
|
||||||
|
if (rule.type === 'fastestLap') {
|
||||||
|
const base = `Fastest lap in ${sessionType}`;
|
||||||
|
if (rule.requiresFinishInTopN) {
|
||||||
|
summaries.push(
|
||||||
|
`${base} +${rule.points} points if finishing P${rule.requiresFinishInTopN} or better`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
summaries.push(`${base} +${rule.points} points`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
summaries.push(
|
||||||
|
`${rule.type} bonus in ${sessionType} worth ${rule.points} points`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return summaries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private deriveDropPolicyDescriptionFromChampionships(
|
||||||
|
championships: ChampionshipConfig[],
|
||||||
|
): string {
|
||||||
|
const first = championships[0];
|
||||||
|
if (!first) {
|
||||||
|
return 'All results count';
|
||||||
|
}
|
||||||
|
return this.deriveDropPolicyDescription(first.dropScorePolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private deriveDropPolicyDescription(policy: {
|
||||||
|
strategy: string;
|
||||||
|
count?: number;
|
||||||
|
dropCount?: number;
|
||||||
|
}): string {
|
||||||
|
if (!policy || policy.strategy === 'none') {
|
||||||
|
return 'All results count';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (policy.strategy === 'bestNResults' && typeof policy.count === 'number') {
|
||||||
|
return `Best ${policy.count} results count towards the championship`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
policy.strategy === 'dropWorstN' &&
|
||||||
|
typeof policy.dropCount === 'number'
|
||||||
|
) {
|
||||||
|
return `Worst ${policy.dropCount} results are dropped from the championship total`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Custom drop score rules apply';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import type {
|
||||||
|
ILeagueScoringPresetsPresenter,
|
||||||
|
LeagueScoringPresetsResultDTO,
|
||||||
|
LeagueScoringPresetsViewModel,
|
||||||
|
} from '@core/racing/application/presenters/ILeagueScoringPresetsPresenter';
|
||||||
|
|
||||||
|
export class LeagueScoringPresetsPresenter implements ILeagueScoringPresetsPresenter {
|
||||||
|
private viewModel: LeagueScoringPresetsViewModel | null = null;
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.viewModel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
present(dto: LeagueScoringPresetsResultDTO): void {
|
||||||
|
this.viewModel = {
|
||||||
|
presets: dto.presets,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getViewModel(): LeagueScoringPresetsViewModel | null {
|
||||||
|
return this.viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IGetTotalLeaguesPresenter, GetTotalLeaguesResultDTO, GetTotalLeaguesViewModel } from '@core/racing/application/presenters/IGetTotalLeaguesPresenter';
|
import { IGetTotalLeaguesPresenter, GetTotalLeaguesResultDTO, GetTotalLeaguesViewModel } from '@core/racing/application/presenters/IGetTotalLeaguesPresenter';
|
||||||
import { LeagueStatsDto } from '../dto/LeagueDto';
|
import { LeagueStatsDTO } from '../dtos/LeagueStatsDTO';
|
||||||
|
|
||||||
export class TotalLeaguesPresenter implements IGetTotalLeaguesPresenter {
|
export class TotalLeaguesPresenter implements IGetTotalLeaguesPresenter {
|
||||||
private result: LeagueStatsDto | null = null;
|
private result: LeagueStatsDto | null = null;
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import { Controller, Post, Body, HttpStatus, Res } from '@nestjs/common';
|
|||||||
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import { MediaService } from './MediaService';
|
import { MediaService } from './MediaService';
|
||||||
import { RequestAvatarGenerationInput, RequestAvatarGenerationOutput } from './dto/MediaDto'; // Assuming these DTOs are defined
|
import type { RequestAvatarGenerationInputDTO } from './dtos/RequestAvatarGenerationInputDTO';
|
||||||
|
import type { RequestAvatarGenerationOutputDTO } from './dtos/RequestAvatarGenerationOutputDTO';
|
||||||
|
|
||||||
|
type RequestAvatarGenerationInput = RequestAvatarGenerationInputDTO;
|
||||||
|
type RequestAvatarGenerationOutput = RequestAvatarGenerationOutputDTO;
|
||||||
|
|
||||||
@ApiTags('media')
|
@ApiTags('media')
|
||||||
@Controller('media')
|
@Controller('media')
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { RequestAvatarGenerationInput, RequestAvatarGenerationOutput } from './dto/MediaDto';
|
import type { RequestAvatarGenerationInputDTO } from './dtos/RequestAvatarGenerationInputDTO';
|
||||||
|
import type { RequestAvatarGenerationOutputDTO } from './dtos/RequestAvatarGenerationOutputDTO';
|
||||||
|
|
||||||
|
type RequestAvatarGenerationInput = RequestAvatarGenerationInputDTO;
|
||||||
|
type RequestAvatarGenerationOutput = RequestAvatarGenerationOutputDTO;
|
||||||
|
|
||||||
// Use cases
|
// Use cases
|
||||||
import { RequestAvatarGenerationUseCase } from '@core/media/application/use-cases/RequestAvatarGenerationUseCase';
|
import { RequestAvatarGenerationUseCase } from '@core/media/application/use-cases/RequestAvatarGenerationUseCase';
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsString, IsNotEmpty, IsBoolean } from 'class-validator';
|
|
||||||
|
|
||||||
export class RequestAvatarGenerationInput {
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
userId: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
facePhotoData: string;
|
|
||||||
|
|
||||||
@ApiProperty()
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
suitColor: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RequestAvatarGenerationOutput {
|
|
||||||
@ApiProperty({ type: Boolean })
|
|
||||||
@IsBoolean()
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsString()
|
|
||||||
requestId?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: [String], required: false })
|
|
||||||
avatarUrls?: string[];
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsString()
|
|
||||||
errorMessage?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assuming FacePhotoData and SuitColor are simple string types for DTO purposes
|
|
||||||
export type FacePhotoData = string;
|
|
||||||
export type SuitColor = string;
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNotEmpty } from 'class-validator';
|
||||||
|
|
||||||
|
export class RequestAvatarGenerationInputDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
userId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
facePhotoData: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
suitColor: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsBoolean, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class RequestAvatarGenerationOutputDTO {
|
||||||
|
@ApiProperty({ type: Boolean })
|
||||||
|
@IsBoolean()
|
||||||
|
success: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsString()
|
||||||
|
requestId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: [String], required: false })
|
||||||
|
avatarUrls?: string[];
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsString()
|
||||||
|
errorMessage?: string;
|
||||||
|
}
|
||||||
2
apps/api/src/domain/media/types/FacePhotoData.ts
Normal file
2
apps/api/src/domain/media/types/FacePhotoData.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Assuming FacePhotoData is a simple string type for DTO purposes
|
||||||
|
export type FacePhotoData = string;
|
||||||
2
apps/api/src/domain/media/types/SuitColor.ts
Normal file
2
apps/api/src/domain/media/types/SuitColor.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Assuming SuitColor is a simple string type for DTO purposes
|
||||||
|
export type SuitColor = string;
|
||||||
31
apps/api/src/domain/payments/dtos/CreatePaymentInputDTO.ts
Normal file
31
apps/api/src/domain/payments/dtos/CreatePaymentInputDTO.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsEnum, IsNumber, IsString, IsOptional } from 'class-validator';
|
||||||
|
import { PaymentType } from './PaymentType';
|
||||||
|
import { PayerType } from './PayerType';
|
||||||
|
|
||||||
|
export class CreatePaymentInputDTO {
|
||||||
|
@ApiProperty({ enum: PaymentType })
|
||||||
|
@IsEnum(PaymentType)
|
||||||
|
type: PaymentType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
payerId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: PayerType })
|
||||||
|
@IsEnum(PayerType)
|
||||||
|
payerType: PayerType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
seasonId?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { PaymentDTO } from './PaymentDTO';
|
||||||
|
|
||||||
|
export class CreatePaymentOutputDTO {
|
||||||
|
@ApiProperty({ type: PaymentDTO })
|
||||||
|
payment: PaymentDTO;
|
||||||
|
}
|
||||||
5
apps/api/src/domain/payments/dtos/MemberPaymentStatus.ts
Normal file
5
apps/api/src/domain/payments/dtos/MemberPaymentStatus.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum MemberPaymentStatus {
|
||||||
|
PENDING = 'pending',
|
||||||
|
PAID = 'paid',
|
||||||
|
OVERDUE = 'overdue',
|
||||||
|
}
|
||||||
5
apps/api/src/domain/payments/dtos/MembershipFeeType.ts
Normal file
5
apps/api/src/domain/payments/dtos/MembershipFeeType.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum MembershipFeeType {
|
||||||
|
SEASON = 'season',
|
||||||
|
MONTHLY = 'monthly',
|
||||||
|
PER_RACE = 'per_race',
|
||||||
|
}
|
||||||
4
apps/api/src/domain/payments/dtos/PayerType.ts
Normal file
4
apps/api/src/domain/payments/dtos/PayerType.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export enum PayerType {
|
||||||
|
SPONSOR = 'sponsor',
|
||||||
|
DRIVER = 'driver',
|
||||||
|
}
|
||||||
57
apps/api/src/domain/payments/dtos/PaymentDTO.ts
Normal file
57
apps/api/src/domain/payments/dtos/PaymentDTO.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber, IsEnum, IsOptional, IsDate } from 'class-validator';
|
||||||
|
import { PaymentType } from './PaymentType';
|
||||||
|
import { PayerType } from './PayerType';
|
||||||
|
import { PaymentStatus } from './PaymentStatus';
|
||||||
|
|
||||||
|
export class PaymentDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: PaymentType })
|
||||||
|
@IsEnum(PaymentType)
|
||||||
|
type: PaymentType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
platformFee: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsNumber()
|
||||||
|
netAmount: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
payerId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: PayerType })
|
||||||
|
@IsEnum(PayerType)
|
||||||
|
payerType: PayerType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
leagueId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
seasonId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: PaymentStatus })
|
||||||
|
@IsEnum(PaymentStatus)
|
||||||
|
status: PaymentStatus;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsDate()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsDate()
|
||||||
|
completedAt?: Date;
|
||||||
|
}
|
||||||
6
apps/api/src/domain/payments/dtos/PaymentStatus.ts
Normal file
6
apps/api/src/domain/payments/dtos/PaymentStatus.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export enum PaymentStatus {
|
||||||
|
PENDING = 'pending',
|
||||||
|
COMPLETED = 'completed',
|
||||||
|
FAILED = 'failed',
|
||||||
|
REFUNDED = 'refunded',
|
||||||
|
}
|
||||||
4
apps/api/src/domain/payments/dtos/PaymentType.ts
Normal file
4
apps/api/src/domain/payments/dtos/PaymentType.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export enum PaymentType {
|
||||||
|
SPONSORSHIP = 'sponsorship',
|
||||||
|
MEMBERSHIP_FEE = 'membership_fee',
|
||||||
|
}
|
||||||
5
apps/api/src/domain/payments/dtos/PrizeType.ts
Normal file
5
apps/api/src/domain/payments/dtos/PrizeType.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum PrizeType {
|
||||||
|
CASH = 'cash',
|
||||||
|
MERCHANDISE = 'merchandise',
|
||||||
|
OTHER = 'other',
|
||||||
|
}
|
||||||
5
apps/api/src/domain/payments/dtos/ReferenceType.ts
Normal file
5
apps/api/src/domain/payments/dtos/ReferenceType.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum ReferenceType {
|
||||||
|
SPONSORSHIP = 'sponsorship',
|
||||||
|
MEMBERSHIP_FEE = 'membership_fee',
|
||||||
|
PRIZE = 'prize',
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user