seed data
This commit is contained in:
@@ -58,7 +58,7 @@ describe('TeamController', () => {
|
||||
it('should return team details', async () => {
|
||||
const teamId = 'team-123';
|
||||
const userId = 'user-456';
|
||||
const result = { team: { id: teamId, name: 'Team', tag: 'TAG', description: 'Desc', ownerId: 'owner', leagues: [] }, membership: null, canManage: false };
|
||||
const result = { team: { id: teamId, name: 'Team', tag: 'TAG', description: 'Desc', ownerId: 'owner', leagues: [], isRecruiting: false }, membership: null, canManage: false };
|
||||
service.getDetails.mockResolvedValue(result);
|
||||
|
||||
const mockReq = { user: { userId } } as any;
|
||||
@@ -132,7 +132,7 @@ describe('TeamController', () => {
|
||||
describe('getDriverTeam', () => {
|
||||
it('should return driver team', async () => {
|
||||
const driverId = 'driver-123';
|
||||
const result = { team: { id: 'team-456', name: 'Team', tag: 'TAG', description: 'Desc', ownerId: 'owner', leagues: [] }, membership: { role: 'member' as const, joinedAt: '2023-01-01', isActive: true }, isOwner: false, canManage: false };
|
||||
const result = { team: { id: 'team-456', name: 'Team', tag: 'TAG', description: 'Desc', ownerId: 'owner', leagues: [], isRecruiting: false }, membership: { role: 'member' as const, joinedAt: '2023-01-01', isActive: true }, isOwner: false, canManage: false };
|
||||
service.getDriverTeam.mockResolvedValue(result);
|
||||
|
||||
const response = await controller.getDriverTeam(driverId);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Provider } from '@nestjs/common';
|
||||
|
||||
import { IMAGE_SERVICE_TOKEN, LOGGER_TOKEN, TEAM_STATS_REPOSITORY_TOKEN, MEDIA_REPOSITORY_TOKEN } from './TeamTokens';
|
||||
import { IMAGE_SERVICE_TOKEN, LOGGER_TOKEN, MEDIA_REPOSITORY_TOKEN } from './TeamTokens';
|
||||
|
||||
export {
|
||||
TEAM_REPOSITORY_TOKEN,
|
||||
@@ -8,18 +8,15 @@ export {
|
||||
DRIVER_REPOSITORY_TOKEN,
|
||||
IMAGE_SERVICE_TOKEN,
|
||||
LOGGER_TOKEN,
|
||||
TEAM_STATS_REPOSITORY_TOKEN,
|
||||
MEDIA_REPOSITORY_TOKEN,
|
||||
} from './TeamTokens';
|
||||
|
||||
// Import core interfaces
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
import type { ITeamStatsRepository } from '@core/racing/domain/repositories/ITeamStatsRepository';
|
||||
|
||||
// Import concrete in-memory implementations
|
||||
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
|
||||
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
|
||||
import { InMemoryTeamStatsRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamStatsRepository';
|
||||
import { InMemoryMediaRepository } from '@adapters/racing/persistence/media/InMemoryMediaRepository';
|
||||
|
||||
// Import presenters
|
||||
@@ -35,11 +32,6 @@ export const TeamProviders: Provider[] = [
|
||||
provide: LOGGER_TOKEN,
|
||||
useClass: ConsoleLogger,
|
||||
},
|
||||
{
|
||||
provide: TEAM_STATS_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryTeamStatsRepository(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: MEDIA_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryMediaRepository(logger),
|
||||
@@ -47,7 +39,6 @@ export const TeamProviders: Provider[] = [
|
||||
},
|
||||
{
|
||||
provide: AllTeamsPresenter,
|
||||
useFactory: (teamStatsRepository: ITeamStatsRepository) => new AllTeamsPresenter(teamStatsRepository),
|
||||
inject: [TEAM_STATS_REPOSITORY_TOKEN],
|
||||
useFactory: () => new AllTeamsPresenter(),
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
@@ -113,7 +113,6 @@ describe('TeamService', () => {
|
||||
|
||||
const teamStatsRepository = {
|
||||
getTeamStats: vi.fn(),
|
||||
getTeamStatsSync: vi.fn(),
|
||||
saveTeamStats: vi.fn(),
|
||||
getAllStats: vi.fn(),
|
||||
clear: vi.fn(),
|
||||
@@ -126,6 +125,10 @@ describe('TeamService', () => {
|
||||
saveDriverAvatar: vi.fn(),
|
||||
};
|
||||
|
||||
const resultRepository = {
|
||||
findAll: vi.fn(),
|
||||
};
|
||||
|
||||
const allTeamsPresenter = {
|
||||
reset: vi.fn(),
|
||||
present: vi.fn(),
|
||||
@@ -140,6 +143,7 @@ describe('TeamService', () => {
|
||||
logger,
|
||||
teamStatsRepository as unknown as never,
|
||||
mediaRepository as unknown as never,
|
||||
resultRepository as unknown as never,
|
||||
allTeamsPresenter as unknown as never
|
||||
);
|
||||
});
|
||||
@@ -558,4 +562,4 @@ describe('TeamService', () => {
|
||||
|
||||
executeSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,9 +37,10 @@ import { CreateTeamPresenter } from './presenters/CreateTeamPresenter';
|
||||
import { UpdateTeamPresenter } from './presenters/UpdateTeamPresenter';
|
||||
|
||||
// Tokens
|
||||
import { TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN, TEAM_STATS_REPOSITORY_TOKEN, MEDIA_REPOSITORY_TOKEN } from './TeamTokens';
|
||||
import { TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN, TEAM_STATS_REPOSITORY_TOKEN, MEDIA_REPOSITORY_TOKEN, RESULT_REPOSITORY_TOKEN } from './TeamTokens';
|
||||
import type { ITeamStatsRepository } from '@core/racing/domain/repositories/ITeamStatsRepository';
|
||||
import type { IMediaRepository } from '@core/racing/domain/repositories/IMediaRepository';
|
||||
import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';
|
||||
|
||||
@Injectable()
|
||||
export class TeamService {
|
||||
@@ -50,6 +51,7 @@ export class TeamService {
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
@Inject(TEAM_STATS_REPOSITORY_TOKEN) private readonly teamStatsRepository: ITeamStatsRepository,
|
||||
@Inject(MEDIA_REPOSITORY_TOKEN) private readonly mediaRepository: IMediaRepository,
|
||||
@Inject(RESULT_REPOSITORY_TOKEN) private readonly resultRepository: IResultRepository,
|
||||
private readonly allTeamsPresenter: AllTeamsPresenter,
|
||||
) {}
|
||||
|
||||
@@ -61,6 +63,7 @@ export class TeamService {
|
||||
this.membershipRepository,
|
||||
this.teamStatsRepository,
|
||||
this.mediaRepository,
|
||||
this.resultRepository,
|
||||
this.logger,
|
||||
this.allTeamsPresenter
|
||||
);
|
||||
@@ -174,13 +177,13 @@ export class TeamService {
|
||||
}
|
||||
|
||||
async getDriverTeam(driverId: string): Promise<GetDriverTeamOutputDTO | null> {
|
||||
this.logger.debug(`[TeamService] Fetching driver team for driverId: ${driverId}`);
|
||||
this.logger.debug(`[TeamService] Fetching team for driverId: ${driverId}`);
|
||||
|
||||
const presenter = new DriverTeamPresenter();
|
||||
const useCase = new GetDriverTeamUseCase(this.teamRepository, this.membershipRepository, this.logger, presenter);
|
||||
const result = await useCase.execute({ driverId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching driver team for driverId: ${driverId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
this.logger.error(`Error fetching team for driverId: ${driverId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,4 +4,5 @@ export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
|
||||
export const IMAGE_SERVICE_TOKEN = 'IImageServicePort';
|
||||
export const LOGGER_TOKEN = 'Logger';
|
||||
export const TEAM_STATS_REPOSITORY_TOKEN = 'ITeamStatsRepository';
|
||||
export const MEDIA_REPOSITORY_TOKEN = 'IMediaRepository';
|
||||
export const MEDIA_REPOSITORY_TOKEN = 'IMediaRepository';
|
||||
export const RESULT_REPOSITORY_TOKEN = 'IResultRepository';
|
||||
@@ -326,6 +326,15 @@ export class TeamDTO {
|
||||
@IsArray()
|
||||
leagues!: string[];
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
category?: string | undefined;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
isRecruiting!: boolean;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
|
||||
@@ -37,10 +37,16 @@ export class TeamListItemDTO {
|
||||
@ApiProperty({ required: false, enum: ['beginner', 'intermediate', 'advanced', 'pro'] })
|
||||
performanceLevel?: 'beginner' | 'intermediate' | 'advanced' | 'pro';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
category?: string | undefined;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
logoUrl?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
rating?: number;
|
||||
|
||||
@ApiProperty()
|
||||
isRecruiting!: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +1,40 @@
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetAllTeamsResult } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetAllTeamsOutputDTO } from '../dtos/GetAllTeamsOutputDTO';
|
||||
import type { ITeamStatsRepository } from '@core/racing/domain/repositories/ITeamStatsRepository';
|
||||
import { TeamListItemDTO } from '../dtos/TeamListItemDTO';
|
||||
|
||||
export class AllTeamsPresenter implements UseCaseOutputPort<GetAllTeamsResult> {
|
||||
private model: GetAllTeamsOutputDTO | null = null;
|
||||
|
||||
constructor(
|
||||
private readonly teamStatsRepository: ITeamStatsRepository
|
||||
) {}
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: GetAllTeamsResult): void {
|
||||
const teams: TeamListItemDTO[] = result.teams.map(team => {
|
||||
const dto = new TeamListItemDTO();
|
||||
dto.id = team.id;
|
||||
dto.name = team.name;
|
||||
dto.tag = team.tag;
|
||||
dto.description = team.description || '';
|
||||
dto.memberCount = team.memberCount;
|
||||
dto.leagues = team.leagues || [];
|
||||
dto.totalWins = team.totalWins ?? 0;
|
||||
dto.totalRaces = team.totalRaces ?? 0;
|
||||
dto.performanceLevel = (team.performanceLevel as 'beginner' | 'intermediate' | 'advanced' | 'pro') ?? 'intermediate';
|
||||
dto.specialization = (team.specialization as 'endurance' | 'sprint' | 'mixed') ?? 'mixed';
|
||||
dto.region = team.region ?? '';
|
||||
dto.languages = team.languages ?? [];
|
||||
// Return relative URL for proxying through Next.js rewrites
|
||||
dto.logoUrl = `/api/media/teams/${team.id}/logo`;
|
||||
dto.rating = team.rating ?? 0;
|
||||
dto.category = team.category;
|
||||
dto.isRecruiting = team.isRecruiting;
|
||||
return dto;
|
||||
});
|
||||
|
||||
this.model = {
|
||||
teams: result.teams.map(team => {
|
||||
const stats = this.teamStatsRepository.getTeamStatsSync(team.id.toString());
|
||||
|
||||
return {
|
||||
id: team.id,
|
||||
name: team.name.toString(),
|
||||
tag: team.tag.toString(),
|
||||
description: team.description?.toString() || '',
|
||||
memberCount: team.memberCount,
|
||||
leagues: team.leagues?.map(l => l.toString()) || [],
|
||||
// Add stats fields
|
||||
...(stats ? {
|
||||
totalWins: stats.totalWins,
|
||||
totalRaces: stats.totalRaces,
|
||||
performanceLevel: stats.performanceLevel,
|
||||
specialization: stats.specialization,
|
||||
region: stats.region,
|
||||
languages: stats.languages,
|
||||
logoUrl: stats.logoUrl,
|
||||
rating: stats.rating,
|
||||
} : {
|
||||
totalWins: 0,
|
||||
totalRaces: 0,
|
||||
performanceLevel: 'beginner',
|
||||
specialization: 'mixed',
|
||||
region: '',
|
||||
languages: [],
|
||||
logoUrl: '',
|
||||
rating: 0,
|
||||
}),
|
||||
};
|
||||
}),
|
||||
teams,
|
||||
totalCount: result.totalCount ?? result.teams.length,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export class DriverTeamPresenter implements UseCaseOutputPort<GetDriverTeamResul
|
||||
description: result.team.description?.toString() || '',
|
||||
ownerId: result.team.ownerId.toString(),
|
||||
leagues: result.team.leagues?.map(l => l.toString()) || [],
|
||||
isRecruiting: result.team.isRecruiting,
|
||||
createdAt: result.team.createdAt.toDate().toISOString(),
|
||||
},
|
||||
membership: {
|
||||
|
||||
@@ -18,6 +18,8 @@ export class TeamDetailsPresenter implements UseCaseOutputPort<GetTeamDetailsRes
|
||||
description: result.team.description?.toString() || '',
|
||||
ownerId: result.team.ownerId.toString(),
|
||||
leagues: result.team.leagues?.map(l => l.toString()) || [],
|
||||
category: result.team.category,
|
||||
isRecruiting: result.team.isRecruiting,
|
||||
createdAt: result.team.createdAt.toDate().toISOString(),
|
||||
},
|
||||
membership: result.membership
|
||||
|
||||
Reference in New Issue
Block a user