This commit is contained in:
2025-12-17 14:04:11 +01:00
parent 1ea9c9649f
commit daa4bb6576
238 changed files with 4263 additions and 1752 deletions

View File

@@ -1,7 +1,14 @@
import { Controller, Get, Post, Body, HttpCode, HttpStatus, Param } from '@nestjs/common';
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
import { SponsorService } from './SponsorService';
import { GetEntitySponsorshipPricingResultDto, GetSponsorsOutput, CreateSponsorInput, CreateSponsorOutput, GetSponsorDashboardQueryParams, SponsorDashboardDTO, GetSponsorSponsorshipsQueryParams, SponsorSponsorshipsDTO } from './dto/SponsorDto';
import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO';
import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO';
import { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
import { CreateSponsorOutputDTO } from './dtos/CreateSponsorOutputDTO';
import { GetSponsorDashboardQueryParamsDTO } from './dtos/GetSponsorDashboardQueryParamsDTO';
import { SponsorDashboardDTO } from './dtos/SponsorDashboardDTO';
import { GetSponsorSponsorshipsQueryParamsDTO } from './dtos/GetSponsorSponsorshipsQueryParamsDTO';
import { SponsorSponsorshipsDTO } from './dtos/SponsorSponsorshipsDTO';
@ApiTags('sponsors')
@Controller('sponsors')
@@ -10,23 +17,23 @@ export class SponsorController {
@Get('pricing')
@ApiOperation({ summary: 'Get sponsorship pricing for an entity' })
@ApiResponse({ status: 200, description: 'Sponsorship pricing', type: GetEntitySponsorshipPricingResultDto })
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDto> {
@ApiResponse({ status: 200, description: 'Sponsorship pricing', type: GetEntitySponsorshipPricingResultDTO })
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
return this.sponsorService.getEntitySponsorshipPricing();
}
@Get()
@ApiOperation({ summary: 'Get all sponsors' })
@ApiResponse({ status: 200, description: 'List of sponsors', type: GetSponsorsOutput })
async getSponsors(): Promise<GetSponsorsOutput> {
@ApiResponse({ status: 200, description: 'List of sponsors', type: GetSponsorsOutputDTO })
async getSponsors(): Promise<GetSponsorsOutputDTO> {
return this.sponsorService.getSponsors();
}
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: 'Create a new sponsor' })
@ApiResponse({ status: 201, description: 'Sponsor created', type: CreateSponsorOutput })
async createSponsor(@Body() input: CreateSponsorInput): Promise<CreateSponsorOutput> {
@ApiResponse({ status: 201, description: 'Sponsor created', type: CreateSponsorOutputDTO })
async createSponsor(@Body() input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
return this.sponsorService.createSponsor(input);
}
@@ -36,13 +43,13 @@ export class SponsorController {
@ApiResponse({ status: 200, description: 'Sponsor dashboard data', type: SponsorDashboardDTO })
@ApiResponse({ status: 404, description: 'Sponsor not found' })
async getSponsorDashboard(@Param('sponsorId') sponsorId: string): Promise<SponsorDashboardDTO | null> {
return this.sponsorService.getSponsorDashboard({ sponsorId });
return this.sponsorService.getSponsorDashboard({ sponsorId } as GetSponsorDashboardQueryParamsDTO);
}
@Get(':sponsorId/sponsorships')
@ApiOperation({ summary: 'Get all sponsorships for a given sponsor' })
@ApiResponse({ status: 200, description: 'List of sponsorships', type: SponsorSponsorshipsDTO })
@ApiResponse({ status: 404, description: 'Sponsor not found' })
async getSponsorSponsorships(@Param('sponsorId') sponsorId: string): Promise<SponsorSponsorshipsDTO | null> {
return this.sponsorService.getSponsorSponsorships({ sponsorId });
return this.sponsorService.getSponsorSponsorships({ sponsorId } as GetSponsorSponsorshipsQueryParamsDTO);
}
}

View File

@@ -1,5 +1,17 @@
import { Injectable, Inject } from '@nestjs/common';
import { GetEntitySponsorshipPricingResultDto, GetSponsorsOutput, CreateSponsorInput, CreateSponsorOutput, GetSponsorDashboardQueryParams, SponsorDashboardDTO, GetSponsorSponsorshipsQueryParams, SponsorSponsorshipsDTO, SponsorDto, SponsorDashboardMetricsDTO, SponsoredLeagueDTO, SponsorDashboardInvestmentDTO, SponsorshipDetailDTO } from './dto/SponsorDto';
import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO';
import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO';
import { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
import { CreateSponsorOutputDTO } from './dtos/CreateSponsorOutputDTO';
import { GetSponsorDashboardQueryParamsDTO } from './dtos/GetSponsorDashboardQueryParamsDTO';
import { SponsorDashboardDTO } from './dtos/SponsorDashboardDTO';
import { GetSponsorSponsorshipsQueryParamsDTO } from './dtos/GetSponsorSponsorshipsQueryParamsDTO';
import { SponsorSponsorshipsDTO } from './dtos/SponsorSponsorshipsDTO';
import { SponsorDTO } from './dtos/SponsorDTO';
import { SponsorDashboardMetricsDTO } from './dtos/SponsorDashboardMetricsDTO';
import { SponsoredLeagueDTO } from './dtos/SponsoredLeagueDTO';
import { SponsorDashboardInvestmentDTO } from './dtos/SponsorDashboardInvestmentDTO';
import { SponsorshipDetailDTO } from './dtos/SponsorshipDetailDTO';
// Use cases
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
@@ -30,7 +42,7 @@ export class SponsorService {
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
) {}
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDto> {
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
this.logger.debug('[SponsorService] Fetching sponsorship pricing.');
const presenter = new GetSponsorshipPricingPresenter();
@@ -38,7 +50,7 @@ export class SponsorService {
return presenter.viewModel;
}
async getSponsors(): Promise<GetSponsorsOutput> {
async getSponsors(): Promise<GetSponsorsOutputDTO> {
this.logger.debug('[SponsorService] Fetching sponsors.');
const presenter = new GetSponsorsPresenter();
@@ -46,7 +58,7 @@ export class SponsorService {
return presenter.viewModel;
}
async createSponsor(input: CreateSponsorInput): Promise<CreateSponsorOutput> {
async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
this.logger.debug('[SponsorService] Creating sponsor.', { input });
const presenter = new CreateSponsorPresenter();
@@ -54,7 +66,7 @@ export class SponsorService {
return presenter.viewModel;
}
async getSponsorDashboard(params: GetSponsorDashboardQueryParams): Promise<SponsorDashboardDTO | null> {
async getSponsorDashboard(params: GetSponsorDashboardQueryParamsDTO): Promise<SponsorDashboardDTO | null> {
this.logger.debug('[SponsorService] Fetching sponsor dashboard.', { params });
const presenter = new GetSponsorDashboardPresenter();
@@ -62,7 +74,7 @@ export class SponsorService {
return presenter.viewModel as SponsorDashboardDTO | null;
}
async getSponsorSponsorships(params: GetSponsorSponsorshipsQueryParams): Promise<SponsorSponsorshipsDTO | null> {
async getSponsorSponsorships(params: GetSponsorSponsorshipsQueryParamsDTO): Promise<SponsorSponsorshipsDTO | null> {
this.logger.debug('[SponsorService] Fetching sponsor sponsorships.', { params });
const presenter = new GetSponsorSponsorshipsPresenter();

View File

@@ -1,299 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsNumber, IsEnum, IsOptional, IsDate, IsBoolean, IsUrl, IsEmail } from 'class-validator';
export class SponsorshipPricingItemDto {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
level: string;
@ApiProperty()
@IsNumber()
price: number;
@ApiProperty()
@IsString()
currency: string;
}
export class GetEntitySponsorshipPricingResultDto {
@ApiProperty({ type: [SponsorshipPricingItemDto] })
pricing: SponsorshipPricingItemDto[];
}
export class SponsorDto {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
@IsNotEmpty()
name: string;
@ApiProperty()
@IsString()
@IsEmail()
@IsNotEmpty()
contactEmail: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
websiteUrl?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
logoUrl?: string;
@ApiProperty()
@IsDate()
createdAt: Date;
}
export class GetSponsorsOutput {
@ApiProperty({ type: [SponsorDto] })
sponsors: SponsorDto[];
}
export class CreateSponsorInput {
@ApiProperty()
@IsString()
@IsNotEmpty()
name: string;
@ApiProperty()
@IsEmail()
@IsNotEmpty()
contactEmail: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
websiteUrl?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
logoUrl?: string;
}
export class CreateSponsorOutput {
@ApiProperty({ type: SponsorDto })
sponsor: SponsorDto;
}
export class GetSponsorDashboardQueryParams {
@ApiProperty()
@IsString()
sponsorId: string;
}
export class SponsoredLeagueDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty({ enum: ['main', 'secondary'] })
@IsEnum(['main', 'secondary'])
tier: 'main' | 'secondary';
@ApiProperty()
@IsNumber()
drivers: number;
@ApiProperty()
@IsNumber()
races: number;
@ApiProperty()
@IsNumber()
impressions: number;
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
@IsEnum(['active', 'upcoming', 'completed'])
status: 'active' | 'upcoming' | 'completed';
}
export class SponsorDashboardMetricsDTO {
@ApiProperty()
@IsNumber()
impressions: number;
@ApiProperty()
@IsNumber()
impressionsChange: number;
@ApiProperty()
@IsNumber()
uniqueViewers: number;
@ApiProperty()
@IsNumber()
viewersChange: number;
@ApiProperty()
@IsNumber()
races: number;
@ApiProperty()
@IsNumber()
drivers: number;
@ApiProperty()
@IsNumber()
exposure: number;
@ApiProperty()
@IsNumber()
exposureChange: number;
}
export class SponsorDashboardInvestmentDTO {
@ApiProperty()
@IsNumber()
activeSponsorships: number;
@ApiProperty()
@IsNumber()
totalInvestment: number;
@ApiProperty()
@IsNumber()
costPerThousandViews: number;
}
export class SponsorDashboardDTO {
@ApiProperty()
@IsString()
sponsorId: string;
@ApiProperty()
@IsString()
sponsorName: string;
@ApiProperty({ type: SponsorDashboardMetricsDTO })
metrics: SponsorDashboardMetricsDTO;
@ApiProperty({ type: [SponsoredLeagueDTO] })
sponsoredLeagues: SponsoredLeagueDTO[];
@ApiProperty({ type: SponsorDashboardInvestmentDTO })
investment: SponsorDashboardInvestmentDTO;
}
export class GetSponsorSponsorshipsQueryParams {
@ApiProperty()
@IsString()
sponsorId: string;
}
export class SponsorshipDetailDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
leagueId: string;
@ApiProperty()
@IsString()
leagueName: string;
@ApiProperty()
@IsString()
seasonId: string;
@ApiProperty()
@IsString()
seasonName: string;
@ApiProperty({ required: false })
@IsOptional()
@IsDate()
seasonStartDate?: Date;
@ApiProperty({ required: false })
@IsOptional()
@IsDate()
seasonEndDate?: Date;
@ApiProperty({ enum: ['main', 'secondary'] })
@IsEnum(['main', 'secondary'])
tier: 'main' | 'secondary';
@ApiProperty({ enum: ['pending', 'active', 'expired', 'cancelled'] })
@IsEnum(['pending', 'active', 'expired', 'cancelled'])
status: 'pending' | 'active' | 'expired' | 'cancelled';
@ApiProperty()
pricing: {
amount: number;
currency: string;
};
@ApiProperty()
platformFee: {
amount: number;
currency: string;
};
@ApiProperty()
netAmount: {
amount: number;
currency: string;
};
@ApiProperty()
metrics: {
drivers: number;
races: number;
completedRaces: number;
impressions: number;
};
@ApiProperty()
createdAt: Date;
@ApiProperty({ required: false })
@IsOptional()
@IsDate()
activatedAt?: Date;
}
export class SponsorSponsorshipsDTO {
@ApiProperty()
@IsString()
sponsorId: string;
@ApiProperty()
@IsString()
sponsorName: string;
@ApiProperty({ type: [SponsorshipDetailDTO] })
sponsorships: SponsorshipDetailDTO[];
@ApiProperty()
summary: {
totalSponsorships: number;
activeSponsorships: number;
totalInvestment: number;
totalPlatformFees: number;
currency: string;
};
}
// Add other DTOs for sponsor-related logic as needed

View File

@@ -0,0 +1,26 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEmail, IsNotEmpty, IsOptional, IsUrl } from 'class-validator';
export class CreateSponsorInputDTO {
@ApiProperty()
@IsString()
@IsNotEmpty()
name: string;
@ApiProperty()
@IsEmail()
@IsNotEmpty()
contactEmail: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
websiteUrl?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
@IsUrl()
logoUrl?: string;
}

View File

@@ -0,0 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { SponsorDTO } from './SponsorDTO';
export class CreateSponsorOutputDTO {
@ApiProperty({ type: SponsorDTO })
sponsor: SponsorDTO;
}

View File

@@ -0,0 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { SponsorshipPricingItemDTO } from './SponsorshipPricingItemDTO';
export class GetEntitySponsorshipPricingResultDTO {
@ApiProperty({ type: [SponsorshipPricingItemDTO] })
pricing: SponsorshipPricingItemDTO[];
}

View File

@@ -0,0 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class GetSponsorDashboardQueryParamsDTO {
@ApiProperty()
@IsString()
sponsorId: string;
}

View File

@@ -0,0 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export class GetSponsorSponsorshipsQueryParamsDTO {
@ApiProperty()
@IsString()
sponsorId: string;
}

View File

@@ -0,0 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { SponsorDTO } from './SponsorDTO';
export class GetSponsorsOutputDTO {
@ApiProperty({ type: [SponsorDTO] })
sponsors: SponsorDTO[];
}

View File

@@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { SponsorDashboardMetricsDTO } from './SponsorDashboardMetricsDTO';
import { SponsoredLeagueDTO } from './SponsoredLeagueDTO';
import { SponsorDashboardInvestmentDTO } from './SponsorDashboardInvestmentDTO';
export class SponsorDashboardDTO {
@ApiProperty()
@IsString()
sponsorId: string;
@ApiProperty()
@IsString()
sponsorName: string;
@ApiProperty({ type: SponsorDashboardMetricsDTO })
metrics: SponsorDashboardMetricsDTO;
@ApiProperty({ type: [SponsoredLeagueDTO] })
sponsoredLeagues: SponsoredLeagueDTO[];
@ApiProperty({ type: SponsorDashboardInvestmentDTO })
investment: SponsorDashboardInvestmentDTO;
}

View File

@@ -0,0 +1,16 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';
export class SponsorDashboardInvestmentDTO {
@ApiProperty()
@IsNumber()
activeSponsorships: number;
@ApiProperty()
@IsNumber()
totalInvestment: number;
@ApiProperty()
@IsNumber()
costPerThousandViews: number;
}

View File

@@ -0,0 +1,36 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';
export class SponsorDashboardMetricsDTO {
@ApiProperty()
@IsNumber()
impressions: number;
@ApiProperty()
@IsNumber()
impressionsChange: number;
@ApiProperty()
@IsNumber()
uniqueViewers: number;
@ApiProperty()
@IsNumber()
viewersChange: number;
@ApiProperty()
@IsNumber()
races: number;
@ApiProperty()
@IsNumber()
drivers: number;
@ApiProperty()
@IsNumber()
exposure: number;
@ApiProperty()
@IsNumber()
exposureChange: number;
}

View File

@@ -0,0 +1,25 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { SponsorshipDetailDTO } from './SponsorshipDetailDTO';
export class SponsorSponsorshipsDTO {
@ApiProperty()
@IsString()
sponsorId: string;
@ApiProperty()
@IsString()
sponsorName: string;
@ApiProperty({ type: [SponsorshipDetailDTO] })
sponsorships: SponsorshipDetailDTO[];
@ApiProperty()
summary: {
totalSponsorships: number;
activeSponsorships: number;
totalInvestment: number;
totalPlatformFees: number;
currency: string;
};
}

View File

@@ -0,0 +1,32 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber } from 'class-validator';
export class SponsoredLeagueDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty({ enum: ['main', 'secondary'] })
@IsEnum(['main', 'secondary'])
tier: 'main' | 'secondary';
@ApiProperty()
@IsNumber()
drivers: number;
@ApiProperty()
@IsNumber()
races: number;
@ApiProperty()
@IsNumber()
impressions: number;
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
@IsEnum(['active', 'upcoming', 'completed'])
status: 'active' | 'upcoming' | 'completed';
}

View File

@@ -0,0 +1,76 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsOptional, IsDate } from 'class-validator';
export class SponsorshipDetailDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
leagueId: string;
@ApiProperty()
@IsString()
leagueName: string;
@ApiProperty()
@IsString()
seasonId: string;
@ApiProperty()
@IsString()
seasonName: string;
@ApiProperty({ required: false })
@IsOptional()
@IsDate()
seasonStartDate?: Date;
@ApiProperty({ required: false })
@IsOptional()
@IsDate()
seasonEndDate?: Date;
@ApiProperty({ enum: ['main', 'secondary'] })
@IsEnum(['main', 'secondary'])
tier: 'main' | 'secondary';
@ApiProperty({ enum: ['pending', 'active', 'expired', 'cancelled'] })
@IsEnum(['pending', 'active', 'expired', 'cancelled'])
status: 'pending' | 'active' | 'expired' | 'cancelled';
@ApiProperty()
pricing: {
amount: number;
currency: string;
};
@ApiProperty()
platformFee: {
amount: number;
currency: string;
};
@ApiProperty()
netAmount: {
amount: number;
currency: string;
};
@ApiProperty()
metrics: {
drivers: number;
races: number;
completedRaces: number;
impressions: number;
};
@ApiProperty()
createdAt: Date;
@ApiProperty({ required: false })
@IsOptional()
@IsDate()
activatedAt?: Date;
}

View File

@@ -0,0 +1,20 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber } from 'class-validator';
export class SponsorshipPricingItemDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
level: string;
@ApiProperty()
@IsNumber()
price: number;
@ApiProperty()
@IsString()
currency: string;
}