website cleanup
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Controller, Get, Post, Body, Query } from '@nestjs/common';
|
||||
import { AuthService } from './AuthService';
|
||||
import { LoginParams, SignupParams, AuthSessionDTO } from './dtos/AuthDto';
|
||||
import { LoginParamsDTO, SignupParamsDTO, AuthSessionDTO } from './dtos/AuthDto';
|
||||
import type { CommandResultDTO } from './presenters/CommandResultPresenter';
|
||||
|
||||
@Controller('auth')
|
||||
@@ -8,12 +8,12 @@ export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Post('signup')
|
||||
async signup(@Body() params: SignupParams): Promise<AuthSessionDTO> {
|
||||
async signup(@Body() params: SignupParamsDTO): Promise<AuthSessionDTO> {
|
||||
return this.authService.signupWithEmail(params);
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
async login(@Body() params: LoginParams): Promise<AuthSessionDTO> {
|
||||
async login(@Body() params: LoginParamsDTO): Promise<AuthSessionDTO> {
|
||||
return this.authService.loginWithEmail(params);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
SIGNUP_USE_CASE_TOKEN,
|
||||
} from './AuthProviders';
|
||||
import type { AuthSessionDTO } from './dtos/AuthDto';
|
||||
import { LoginParams, SignupParams } from './dtos/AuthDto';
|
||||
import { LoginParamsDTO, SignupParamsDTO } from './dtos/AuthDto';
|
||||
import { AuthSessionPresenter } from './presenters/AuthSessionPresenter';
|
||||
import type { CommandResultDTO } from './presenters/CommandResultPresenter';
|
||||
import { CommandResultPresenter } from './presenters/CommandResultPresenter';
|
||||
@@ -67,7 +67,7 @@ export class AuthService {
|
||||
};
|
||||
}
|
||||
|
||||
async signupWithEmail(params: SignupParams): Promise<AuthSessionDTO> {
|
||||
async signupWithEmail(params: SignupParamsDTO): Promise<AuthSessionDTO> {
|
||||
this.logger.debug(`[AuthService] Attempting signup for email: ${params.email}`);
|
||||
|
||||
this.authSessionPresenter.reset();
|
||||
@@ -98,7 +98,7 @@ export class AuthService {
|
||||
};
|
||||
}
|
||||
|
||||
async loginWithEmail(params: LoginParams): Promise<AuthSessionDTO> {
|
||||
async loginWithEmail(params: LoginParamsDTO): Promise<AuthSessionDTO> {
|
||||
this.logger.debug(`[AuthService] Attempting login for email: ${params.email}`);
|
||||
|
||||
this.authSessionPresenter.reset();
|
||||
@@ -142,4 +142,51 @@ export class AuthService {
|
||||
|
||||
return this.commandResultPresenter.responseModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start iRacing OAuth flow.
|
||||
*
|
||||
* NOTE: This is a placeholder implementation for the current alpha build.
|
||||
* A production implementation should delegate to a dedicated iRacing OAuth port
|
||||
* and persist/validate state server-side.
|
||||
*/
|
||||
async startIracingAuth(returnTo?: string): Promise<string> {
|
||||
this.logger.debug('[AuthService] Starting iRacing auth flow', { returnTo });
|
||||
|
||||
const state = Math.random().toString(36).slice(2);
|
||||
const base = 'https://example.com/iracing/auth';
|
||||
const query = new URLSearchParams();
|
||||
query.set('state', state);
|
||||
if (returnTo) {
|
||||
query.set('returnTo', returnTo);
|
||||
}
|
||||
|
||||
return `${base}?${query.toString()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle iRacing OAuth callback.
|
||||
*
|
||||
* NOTE: Placeholder implementation that creates a demo session.
|
||||
*/
|
||||
async iracingCallback(code: string, state: string, returnTo?: string): Promise<AuthSessionDTO> {
|
||||
this.logger.debug('[AuthService] iRacing callback received', { hasCode: !!code, state, returnTo });
|
||||
|
||||
const userId = `iracing-${state || code}`.slice(0, 64);
|
||||
|
||||
const session = await this.identitySessionPort.createSession({
|
||||
id: userId,
|
||||
displayName: 'iRacing User',
|
||||
email: '',
|
||||
});
|
||||
|
||||
return {
|
||||
token: session.token,
|
||||
user: {
|
||||
userId,
|
||||
email: '',
|
||||
displayName: 'iRacing User',
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export class AuthSessionDTO {
|
||||
user!: AuthenticatedUserDTO;
|
||||
}
|
||||
|
||||
export class SignupParams {
|
||||
export class SignupParamsDTO {
|
||||
@ApiProperty()
|
||||
email!: string;
|
||||
@ApiProperty()
|
||||
@@ -31,21 +31,21 @@ export class SignupParams {
|
||||
avatarUrl?: string;
|
||||
}
|
||||
|
||||
export class LoginParams {
|
||||
export class LoginParamsDTO {
|
||||
@ApiProperty()
|
||||
email!: string;
|
||||
@ApiProperty()
|
||||
password!: string;
|
||||
}
|
||||
|
||||
export class IracingAuthRedirectResult {
|
||||
export class IracingAuthRedirectResultDTO {
|
||||
@ApiProperty()
|
||||
redirectUrl!: string;
|
||||
@ApiProperty()
|
||||
state!: string;
|
||||
}
|
||||
|
||||
export class LoginWithIracingCallbackParams {
|
||||
export class LoginWithIracingCallbackParamsDTO {
|
||||
@ApiProperty()
|
||||
code!: string;
|
||||
@ApiProperty()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsOptional, IsString, ValidateNested } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
class WizardErrorsBasicsDTO {
|
||||
export class WizardErrorsBasicsDTO {
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -19,7 +19,7 @@ class WizardErrorsBasicsDTO {
|
||||
visibility?: string;
|
||||
}
|
||||
|
||||
class WizardErrorsStructureDTO {
|
||||
export class WizardErrorsStructureDTO {
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -36,7 +36,7 @@ class WizardErrorsStructureDTO {
|
||||
driversPerTeam?: string;
|
||||
}
|
||||
|
||||
class WizardErrorsTimingsDTO {
|
||||
export class WizardErrorsTimingsDTO {
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -53,7 +53,7 @@ class WizardErrorsTimingsDTO {
|
||||
roundsPlanned?: string;
|
||||
}
|
||||
|
||||
class WizardErrorsScoringDTO {
|
||||
export class WizardErrorsScoringDTO {
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -89,4 +89,4 @@ export class WizardErrorsDTO {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
submit?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,12 @@ export class LeagueStandingsPresenter implements Presenter<GetLeagueStandingsRes
|
||||
joinedAt: standing.driver.joinedAt.toString(),
|
||||
},
|
||||
points: standing.points,
|
||||
rank: standing.rank,
|
||||
position: standing.rank,
|
||||
// TODO: GetLeagueStandings currently does not provide these metrics.
|
||||
// Keep them stable in the API contract for now.
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
races: 0,
|
||||
}));
|
||||
this.result = { standings };
|
||||
}
|
||||
@@ -30,4 +35,4 @@ export class LeagueStandingsPresenter implements Presenter<GetLeagueStandingsRes
|
||||
if (!this.result) throw new Error('Presenter not presented');
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsNotEmpty, IsOptional, IsUrl } from 'class-validator';
|
||||
import { IsNotEmpty, IsOptional, IsString, IsUrl, ValidateNested } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { ProtestIncidentDTO } from './ProtestIncidentDTO';
|
||||
|
||||
export class FileProtestCommandDTO {
|
||||
@ApiProperty()
|
||||
@@ -18,11 +20,9 @@ export class FileProtestCommandDTO {
|
||||
accusedDriverId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
incident!: {
|
||||
lap: number;
|
||||
description: string;
|
||||
timeInRace?: number;
|
||||
};
|
||||
@ValidateNested()
|
||||
@Type(() => ProtestIncidentDTO)
|
||||
incident!: ProtestIncidentDTO;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@@ -34,4 +34,4 @@ export class FileProtestCommandDTO {
|
||||
@IsString()
|
||||
@IsUrl()
|
||||
proofVideoUrl?: string;
|
||||
}
|
||||
}
|
||||
|
||||
21
apps/api/src/domain/race/dtos/ProtestIncidentDTO.ts
Normal file
21
apps/api/src/domain/race/dtos/ProtestIncidentDTO.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsInt, IsNotEmpty, IsOptional, IsString, Min } from 'class-validator';
|
||||
|
||||
export class ProtestIncidentDTO {
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
lap!: number;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
description!: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Seconds from race start' })
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
timeInRace?: number;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import { InvoiceDTO } from './dtos/InvoiceDTO';
|
||||
import { BillingStatsDTO } from './dtos/BillingStatsDTO';
|
||||
import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO';
|
||||
import { LeagueDetailDTO } from './dtos/LeagueDetailDTO';
|
||||
import { DriverDTO } from './dtos/DriverDTO';
|
||||
import { RaceDTO } from './dtos/RaceDTO';
|
||||
import { SponsorDriverDTO } from './dtos/SponsorDriverDTO';
|
||||
import { SponsorRaceDTO } from './dtos/RaceDTO';
|
||||
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
|
||||
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
|
||||
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
|
||||
@@ -194,8 +194,8 @@ export class SponsorController {
|
||||
@Param('leagueId') leagueId: string,
|
||||
): Promise<{
|
||||
league: LeagueDetailDTO;
|
||||
drivers: DriverDTO[];
|
||||
races: RaceDTO[];
|
||||
drivers: SponsorDriverDTO[];
|
||||
races: SponsorRaceDTO[];
|
||||
} | null> {
|
||||
const presenter = await this.sponsorService.getLeagueDetail(leagueId);
|
||||
return presenter.viewModel;
|
||||
|
||||
@@ -11,8 +11,8 @@ import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshi
|
||||
import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO';
|
||||
import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO';
|
||||
import { LeagueDetailDTO } from './dtos/LeagueDetailDTO';
|
||||
import { DriverDTO } from './dtos/DriverDTO';
|
||||
import { RaceDTO } from './dtos/RaceDTO';
|
||||
import { SponsorDriverDTO } from './dtos/SponsorDriverDTO';
|
||||
import { SponsorRaceDTO } from './dtos/RaceDTO';
|
||||
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
|
||||
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
|
||||
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
|
||||
@@ -399,7 +399,7 @@ export class SponsorService {
|
||||
},
|
||||
};
|
||||
|
||||
const drivers: DriverDTO[] = [
|
||||
const drivers: SponsorDriverDTO[] = [
|
||||
{
|
||||
id: 'd1',
|
||||
name: 'Max Verstappen',
|
||||
@@ -420,7 +420,7 @@ export class SponsorService {
|
||||
},
|
||||
];
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
const races: SponsorRaceDTO[] = [
|
||||
{
|
||||
id: 'r1',
|
||||
name: 'Spa-Francorchamps',
|
||||
@@ -508,4 +508,4 @@ export class SponsorService {
|
||||
presenter.present({ success: true });
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
|
||||
|
||||
export class RaceDTO {
|
||||
export class SponsorRaceDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string = '';
|
||||
@@ -21,4 +21,4 @@ export class RaceDTO {
|
||||
@ApiProperty({ enum: ['upcoming', 'completed'] })
|
||||
@IsEnum(['upcoming', 'completed'])
|
||||
status: 'upcoming' | 'completed' = 'upcoming';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsNumber } from 'class-validator';
|
||||
|
||||
export class DriverDTO {
|
||||
export class SponsorDriverDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string = '';
|
||||
@@ -29,4 +29,5 @@ export class DriverDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
team: string = '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { LeagueDetailDTO } from '../dtos/LeagueDetailDTO';
|
||||
import { DriverDTO } from '../dtos/DriverDTO';
|
||||
import { RaceDTO } from '../dtos/RaceDTO';
|
||||
import { SponsorDriverDTO } from '../dtos/SponsorDriverDTO';
|
||||
import { SponsorRaceDTO } from '../dtos/RaceDTO';
|
||||
|
||||
export interface LeagueDetailViewModel {
|
||||
league: LeagueDetailDTO;
|
||||
drivers: DriverDTO[];
|
||||
races: RaceDTO[];
|
||||
drivers: SponsorDriverDTO[];
|
||||
races: SponsorRaceDTO[];
|
||||
}
|
||||
|
||||
export class LeagueDetailPresenter {
|
||||
|
||||
@@ -1,33 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
class TeamListItemDTO {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
tag!: string;
|
||||
|
||||
@ApiProperty()
|
||||
description!: string;
|
||||
|
||||
@ApiProperty()
|
||||
memberCount!: number;
|
||||
|
||||
@ApiProperty({ type: [String] })
|
||||
leagues!: string[];
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
region?: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
languages?: string[];
|
||||
}
|
||||
import { TeamListItemDTO } from './TeamListItemDTO';
|
||||
|
||||
export class GetAllTeamsOutputDTO {
|
||||
@ApiProperty({ type: [TeamListItemDTO] })
|
||||
@@ -35,4 +8,4 @@ export class GetAllTeamsOutputDTO {
|
||||
|
||||
@ApiProperty()
|
||||
totalCount!: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,18 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
class TeamDTO {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
tag!: string;
|
||||
|
||||
@ApiProperty()
|
||||
description!: string;
|
||||
|
||||
@ApiProperty()
|
||||
ownerId!: string;
|
||||
|
||||
@ApiProperty({ type: [String] })
|
||||
leagues!: string[];
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
createdAt?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
region?: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
languages?: string[];
|
||||
}
|
||||
|
||||
class MembershipDTO {
|
||||
@ApiProperty()
|
||||
role!: 'owner' | 'manager' | 'member';
|
||||
|
||||
@ApiProperty()
|
||||
joinedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
isActive!: boolean;
|
||||
}
|
||||
import { TeamDTO } from './TeamDTO';
|
||||
import { TeamMembershipDTO } from './TeamMembershipDTO';
|
||||
|
||||
export class GetDriverTeamOutputDTO {
|
||||
@ApiProperty({ type: TeamDTO })
|
||||
team!: TeamDTO;
|
||||
|
||||
@ApiProperty({ type: MembershipDTO })
|
||||
membership!: MembershipDTO;
|
||||
@ApiProperty({ type: TeamMembershipDTO })
|
||||
membership!: TeamMembershipDTO;
|
||||
|
||||
@ApiProperty()
|
||||
isOwner!: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
canManage!: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,15 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
class TeamDTO {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
tag!: string;
|
||||
|
||||
@ApiProperty()
|
||||
description!: string;
|
||||
|
||||
@ApiProperty()
|
||||
ownerId!: string;
|
||||
|
||||
@ApiProperty({ type: [String] })
|
||||
leagues!: string[];
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
createdAt?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
region?: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
languages?: string[];
|
||||
}
|
||||
|
||||
class MembershipDTO {
|
||||
@ApiProperty()
|
||||
role!: 'owner' | 'manager' | 'member';
|
||||
|
||||
@ApiProperty()
|
||||
joinedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
isActive!: boolean;
|
||||
}
|
||||
import { TeamDTO } from './TeamDTO';
|
||||
import { TeamMembershipDTO } from './TeamMembershipDTO';
|
||||
|
||||
export class GetTeamDetailsOutputDTO {
|
||||
@ApiProperty({ type: TeamDTO })
|
||||
team!: TeamDTO;
|
||||
|
||||
@ApiProperty({ type: MembershipDTO, nullable: true })
|
||||
membership!: MembershipDTO | null;
|
||||
@ApiProperty({ type: TeamMembershipDTO, nullable: true })
|
||||
membership!: TeamMembershipDTO | null;
|
||||
|
||||
@ApiProperty()
|
||||
canManage!: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
class TeamJoinRequestDTO {
|
||||
@ApiProperty()
|
||||
requestId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
driverId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
driverName!: string;
|
||||
|
||||
@ApiProperty()
|
||||
teamId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
status!: 'pending' | 'approved' | 'rejected';
|
||||
|
||||
@ApiProperty()
|
||||
requestedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
avatarUrl!: string;
|
||||
}
|
||||
import { TeamJoinRequestDTO } from './TeamJoinRequestDTO';
|
||||
|
||||
export class GetTeamJoinRequestsOutputDTO {
|
||||
@ApiProperty({ type: [TeamJoinRequestDTO] })
|
||||
@@ -32,4 +11,4 @@ export class GetTeamJoinRequestsOutputDTO {
|
||||
|
||||
@ApiProperty()
|
||||
totalCount!: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
class TeamMemberDTO {
|
||||
@ApiProperty()
|
||||
driverId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
driverName!: string;
|
||||
|
||||
@ApiProperty()
|
||||
role!: 'owner' | 'manager' | 'member';
|
||||
|
||||
@ApiProperty()
|
||||
joinedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
isActive!: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
avatarUrl!: string;
|
||||
}
|
||||
import { TeamMemberDTO } from './TeamMemberDTO';
|
||||
|
||||
export class GetTeamMembersOutputDTO {
|
||||
@ApiProperty({ type: [TeamMemberDTO] })
|
||||
@@ -35,4 +17,4 @@ export class GetTeamMembersOutputDTO {
|
||||
|
||||
@ApiProperty()
|
||||
memberCount!: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export type SkillLevel = 'beginner' | 'intermediate' | 'advanced' | 'pro';
|
||||
|
||||
class TeamLeaderboardItemDTO {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
memberCount!: number;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
rating!: number | null;
|
||||
|
||||
@ApiProperty()
|
||||
totalWins!: number;
|
||||
|
||||
@ApiProperty()
|
||||
totalRaces!: number;
|
||||
|
||||
@ApiProperty({ enum: ['beginner', 'intermediate', 'advanced', 'pro'] })
|
||||
performanceLevel!: SkillLevel;
|
||||
|
||||
@ApiProperty()
|
||||
isRecruiting!: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
createdAt!: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
description?: string;
|
||||
|
||||
@ApiProperty({ enum: ['endurance', 'sprint', 'mixed'], required: false })
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
region?: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
languages?: string[];
|
||||
}
|
||||
import { TeamLeaderboardItemDTO, type SkillLevel } from './TeamLeaderboardItemDTO';
|
||||
|
||||
export class GetTeamsLeaderboardOutputDTO {
|
||||
@ApiProperty({ type: [TeamLeaderboardItemDTO] })
|
||||
@@ -55,4 +14,4 @@ export class GetTeamsLeaderboardOutputDTO {
|
||||
|
||||
@ApiProperty({ type: [TeamLeaderboardItemDTO] })
|
||||
topTeams!: TeamLeaderboardItemDTO[];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsNotEmpty, IsBoolean, IsOptional } from 'class-validator';
|
||||
import { IsString, IsNotEmpty, IsBoolean, IsOptional, IsArray } from 'class-validator';
|
||||
|
||||
export class TeamListItemViewModel {
|
||||
@ApiProperty()
|
||||
@@ -296,3 +296,38 @@ export class RejectTeamJoinRequestOutput {
|
||||
@IsBoolean()
|
||||
success!: boolean;
|
||||
}
|
||||
|
||||
// ---
|
||||
// DTOs used by the public API surface (consumed by the website via generated types)
|
||||
// ---
|
||||
|
||||
export class TeamDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
tag!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
description!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
ownerId!: string;
|
||||
|
||||
@ApiProperty({ type: [String] })
|
||||
@IsArray()
|
||||
leagues!: string[];
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
createdAt?: string;
|
||||
}
|
||||
|
||||
25
apps/api/src/domain/team/dtos/TeamJoinRequestDTO.ts
Normal file
25
apps/api/src/domain/team/dtos/TeamJoinRequestDTO.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TeamJoinRequestDTO {
|
||||
@ApiProperty()
|
||||
requestId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
driverId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
driverName!: string;
|
||||
|
||||
@ApiProperty()
|
||||
teamId!: string;
|
||||
|
||||
@ApiProperty({ enum: ['pending', 'approved', 'rejected'] })
|
||||
status!: 'pending' | 'approved' | 'rejected';
|
||||
|
||||
@ApiProperty()
|
||||
requestedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
avatarUrl!: string;
|
||||
}
|
||||
|
||||
45
apps/api/src/domain/team/dtos/TeamLeaderboardItemDTO.ts
Normal file
45
apps/api/src/domain/team/dtos/TeamLeaderboardItemDTO.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export type SkillLevel = 'beginner' | 'intermediate' | 'advanced' | 'pro';
|
||||
|
||||
export class TeamLeaderboardItemDTO {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
memberCount!: number;
|
||||
|
||||
@ApiProperty({ nullable: true })
|
||||
rating!: number | null;
|
||||
|
||||
@ApiProperty()
|
||||
totalWins!: number;
|
||||
|
||||
@ApiProperty()
|
||||
totalRaces!: number;
|
||||
|
||||
@ApiProperty({ enum: ['beginner', 'intermediate', 'advanced', 'pro'] })
|
||||
performanceLevel!: SkillLevel;
|
||||
|
||||
@ApiProperty()
|
||||
isRecruiting!: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
createdAt!: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
description?: string;
|
||||
|
||||
@ApiProperty({ enum: ['endurance', 'sprint', 'mixed'], required: false })
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
region?: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
languages?: string[];
|
||||
}
|
||||
|
||||
31
apps/api/src/domain/team/dtos/TeamListItemDTO.ts
Normal file
31
apps/api/src/domain/team/dtos/TeamListItemDTO.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TeamListItemDTO {
|
||||
@ApiProperty()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
name!: string;
|
||||
|
||||
@ApiProperty()
|
||||
tag!: string;
|
||||
|
||||
@ApiProperty()
|
||||
description!: string;
|
||||
|
||||
@ApiProperty()
|
||||
memberCount!: number;
|
||||
|
||||
@ApiProperty({ type: [String] })
|
||||
leagues!: string[];
|
||||
|
||||
@ApiProperty({ required: false, enum: ['endurance', 'sprint', 'mixed'] })
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
region?: string;
|
||||
|
||||
@ApiProperty({ type: [String], required: false })
|
||||
languages?: string[];
|
||||
}
|
||||
|
||||
22
apps/api/src/domain/team/dtos/TeamMemberDTO.ts
Normal file
22
apps/api/src/domain/team/dtos/TeamMemberDTO.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TeamMemberDTO {
|
||||
@ApiProperty()
|
||||
driverId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
driverName!: string;
|
||||
|
||||
@ApiProperty({ enum: ['owner', 'manager', 'member'] })
|
||||
role!: 'owner' | 'manager' | 'member';
|
||||
|
||||
@ApiProperty()
|
||||
joinedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
isActive!: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
avatarUrl!: string;
|
||||
}
|
||||
|
||||
13
apps/api/src/domain/team/dtos/TeamMembershipDTO.ts
Normal file
13
apps/api/src/domain/team/dtos/TeamMembershipDTO.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TeamMembershipDTO {
|
||||
@ApiProperty({ enum: ['owner', 'manager', 'member'] })
|
||||
role!: 'owner' | 'manager' | 'member';
|
||||
|
||||
@ApiProperty()
|
||||
joinedAt!: string;
|
||||
|
||||
@ApiProperty()
|
||||
isActive!: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user