resolve manual DTOs
This commit is contained in:
@@ -1,7 +1,17 @@
|
||||
import { Controller, Get, Post, Patch, Body, Param } from '@nestjs/common';
|
||||
import { ApiTags, ApiResponse, ApiOperation, ApiBody } from '@nestjs/swagger';
|
||||
import { Controller, Get, Post, Patch, Body, Req, Param } from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
||||
import { TeamService } from './TeamService';
|
||||
import { AllTeamsViewModel, DriverTeamViewModel, TeamDetailsViewModel, TeamMembersViewModel, TeamJoinRequestsViewModel, CreateTeamInput, CreateTeamOutput, UpdateTeamInput, UpdateTeamOutput, ApproveTeamJoinRequestInput, ApproveTeamJoinRequestOutput, RejectTeamJoinRequestInput, RejectTeamJoinRequestOutput } from './dto/TeamDto';
|
||||
import { GetAllTeamsOutputDTO } from './dtos/GetAllTeamsOutputDTO';
|
||||
import { GetTeamDetailsOutputDTO } from './dtos/GetTeamDetailsOutputDTO';
|
||||
import { GetTeamMembersOutputDTO } from './dtos/GetTeamMembersOutputDTO';
|
||||
import { GetTeamJoinRequestsOutputDTO } from './dtos/GetTeamJoinRequestsOutputDTO';
|
||||
import { CreateTeamInputDTO } from './dtos/CreateTeamInputDTO';
|
||||
import { CreateTeamOutputDTO } from './dtos/CreateTeamOutputDTO';
|
||||
import { UpdateTeamInputDTO } from './dtos/UpdateTeamInputDTO';
|
||||
import { UpdateTeamOutputDTO } from './dtos/UpdateTeamOutputDTO';
|
||||
import { GetDriverTeamOutputDTO } from './dtos/GetDriverTeamOutputDTO';
|
||||
import { GetTeamMembershipOutputDTO } from './dtos/GetTeamMembershipOutputDTO';
|
||||
|
||||
@ApiTags('teams')
|
||||
@Controller('teams')
|
||||
@@ -10,91 +20,63 @@ export class TeamController {
|
||||
|
||||
@Get('all')
|
||||
@ApiOperation({ summary: 'Get all teams' })
|
||||
@ApiResponse({ status: 200, description: 'List of all teams', type: AllTeamsViewModel })
|
||||
async getAllTeams(): Promise<AllTeamsViewModel> {
|
||||
return this.teamService.getAllTeams();
|
||||
@ApiResponse({ status: 200, description: 'List of all teams', type: GetAllTeamsOutputDTO })
|
||||
async getAll(): Promise<GetAllTeamsOutputDTO> {
|
||||
return this.teamService.getAll();
|
||||
}
|
||||
|
||||
@Get(':teamId')
|
||||
@ApiOperation({ summary: 'Get team details' })
|
||||
@ApiResponse({ status: 200, description: 'Team details', type: TeamDetailsViewModel })
|
||||
@ApiResponse({ status: 200, description: 'Team details', type: GetTeamDetailsOutputDTO })
|
||||
@ApiResponse({ status: 404, description: 'Team not found' })
|
||||
async getTeamDetails(
|
||||
@Param('teamId') teamId: string,
|
||||
): Promise<TeamDetailsViewModel | null> {
|
||||
return this.teamService.getTeamDetails(teamId);
|
||||
async getDetails(@Param('teamId') teamId: string, @Req() req: Request): Promise<GetTeamDetailsOutputDTO | null> {
|
||||
const userId = req['user']?.userId;
|
||||
return this.teamService.getDetails(teamId, userId);
|
||||
}
|
||||
|
||||
@Get(':teamId/members')
|
||||
@ApiOperation({ summary: 'Get team members' })
|
||||
@ApiResponse({ status: 200, description: 'Team members', type: TeamMembersViewModel })
|
||||
async getTeamMembers(@Param('teamId') teamId: string): Promise<TeamMembersViewModel> {
|
||||
return this.teamService.getTeamMembers(teamId);
|
||||
@ApiResponse({ status: 200, description: 'Team members', type: GetTeamMembersOutputDTO })
|
||||
async getMembers(@Param('teamId') teamId: string): Promise<GetTeamMembersOutputDTO> {
|
||||
return this.teamService.getMembers(teamId);
|
||||
}
|
||||
|
||||
@Get(':teamId/join-requests')
|
||||
@ApiOperation({ summary: 'Get team join requests' })
|
||||
@ApiResponse({ status: 200, description: 'Team join requests', type: TeamJoinRequestsViewModel })
|
||||
async getTeamJoinRequests(@Param('teamId') teamId: string): Promise<TeamJoinRequestsViewModel> {
|
||||
return this.teamService.getTeamJoinRequests(teamId);
|
||||
}
|
||||
|
||||
@Post(':teamId/join-requests/approve')
|
||||
@ApiOperation({ summary: 'Approve a team join request' })
|
||||
@ApiBody({ type: ApproveTeamJoinRequestInput })
|
||||
@ApiResponse({ status: 200, description: 'Join request approved', type: ApproveTeamJoinRequestOutput })
|
||||
@ApiResponse({ status: 404, description: 'Join request not found' })
|
||||
async approveJoinRequest(
|
||||
@Param('teamId') teamId: string,
|
||||
@Body() input: ApproveTeamJoinRequestInput,
|
||||
): Promise<ApproveTeamJoinRequestOutput> {
|
||||
return this.teamService.approveTeamJoinRequest({ ...input, teamId });
|
||||
}
|
||||
|
||||
@Post(':teamId/join-requests/reject')
|
||||
@ApiOperation({ summary: 'Reject a team join request' })
|
||||
@ApiBody({ type: RejectTeamJoinRequestInput })
|
||||
@ApiResponse({ status: 200, description: 'Join request rejected', type: RejectTeamJoinRequestOutput })
|
||||
@ApiResponse({ status: 404, description: 'Join request not found' })
|
||||
async rejectJoinRequest(
|
||||
@Param('teamId') teamId: string,
|
||||
@Body() input: RejectTeamJoinRequestInput,
|
||||
): Promise<RejectTeamJoinRequestOutput> {
|
||||
return this.teamService.rejectTeamJoinRequest({ ...input, teamId });
|
||||
@ApiResponse({ status: 200, description: 'Team join requests', type: GetTeamJoinRequestsOutputDTO })
|
||||
async getJoinRequests(@Param('teamId') teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
|
||||
return this.teamService.getJoinRequests(teamId);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new team' })
|
||||
@ApiBody({ type: CreateTeamInput })
|
||||
@ApiResponse({ status: 201, description: 'Team created successfully', type: CreateTeamOutput })
|
||||
async createTeam(@Body() input: CreateTeamInput): Promise<CreateTeamOutput> {
|
||||
return this.teamService.createTeam(input);
|
||||
@ApiResponse({ status: 201, description: 'Team created', type: CreateTeamOutputDTO })
|
||||
async create(@Body() input: CreateTeamInputDTO, @Req() req: Request): Promise<CreateTeamOutputDTO> {
|
||||
const userId = req['user']?.userId;
|
||||
return this.teamService.create(input, userId);
|
||||
}
|
||||
|
||||
@Patch(':teamId')
|
||||
@ApiOperation({ summary: 'Update team details' })
|
||||
@ApiBody({ type: UpdateTeamInput })
|
||||
@ApiResponse({ status: 200, description: 'Team updated successfully', type: UpdateTeamOutput })
|
||||
@ApiResponse({ status: 404, description: 'Team not found' })
|
||||
async updateTeam(
|
||||
@Param('teamId') teamId: string,
|
||||
@Body() input: UpdateTeamInput,
|
||||
): Promise<UpdateTeamOutput> {
|
||||
return this.teamService.updateTeam({ ...input, teamId });
|
||||
@ApiOperation({ summary: 'Update team' })
|
||||
@ApiResponse({ status: 200, description: 'Team updated', type: UpdateTeamOutputDTO })
|
||||
async update(@Param('teamId') teamId: string, @Body() input: UpdateTeamInputDTO, @Req() req: Request): Promise<UpdateTeamOutputDTO> {
|
||||
const userId = req['user']?.userId;
|
||||
return this.teamService.update(teamId, input, userId);
|
||||
}
|
||||
|
||||
@Get('driver/:driverId')
|
||||
@ApiOperation({ summary: 'Get team for a driver' })
|
||||
@ApiResponse({ status: 200, description: 'Driver team membership', type: DriverTeamViewModel })
|
||||
@ApiResponse({ status: 404, description: 'Driver not in a team' })
|
||||
async getDriverTeam(@Param('driverId') driverId: string): Promise<DriverTeamViewModel | null> {
|
||||
return this.teamService.getDriverTeam({ teamId: '', driverId });
|
||||
@ApiOperation({ summary: 'Get driver\'s team' })
|
||||
@ApiResponse({ status: 200, description: 'Driver\'s team', type: GetDriverTeamOutputDTO })
|
||||
@ApiResponse({ status: 404, description: 'Team not found' })
|
||||
async getDriverTeam(@Param('driverId') driverId: string): Promise<GetDriverTeamOutputDTO | null> {
|
||||
return this.teamService.getDriverTeam(driverId);
|
||||
}
|
||||
|
||||
@Get('leaderboard')
|
||||
@ApiOperation({ summary: 'Get teams leaderboard' })
|
||||
@ApiResponse({ status: 200, description: 'Teams leaderboard' })
|
||||
async getTeamsLeaderboard(): Promise<any> {
|
||||
return this.teamService.getTeamsLeaderboard();
|
||||
@Get(':teamId/members/:driverId')
|
||||
@ApiOperation({ summary: 'Get team membership for a driver' })
|
||||
@ApiResponse({ status: 200, description: 'Team membership', type: GetTeamMembershipOutputDTO })
|
||||
@ApiResponse({ status: 404, description: 'Membership not found' })
|
||||
async getMembership(@Param('teamId') teamId: string, @Param('driverId') driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
|
||||
return this.teamService.getMembership(teamId, driverId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,4 @@ import { TeamProviders } from './TeamProviders';
|
||||
providers: TeamProviders,
|
||||
exports: [TeamService],
|
||||
})
|
||||
export class TeamModule {}
|
||||
export class TeamModule {}
|
||||
@@ -1,166 +1,6 @@
|
||||
import { Provider } from '@nestjs/common';
|
||||
import { TeamService } from './TeamService';
|
||||
|
||||
// Import core interfaces
|
||||
import { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository';
|
||||
import { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository';
|
||||
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||
import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
|
||||
// Import concrete in-memory implementations
|
||||
import { InMemoryTeamRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamRepository';
|
||||
import { InMemoryTeamMembershipRepository } from '@adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository';
|
||||
import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
|
||||
|
||||
// Import use cases
|
||||
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import { GetTeamDetailsUseCase } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
|
||||
import { GetTeamMembersUseCase } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
|
||||
import { GetTeamJoinRequestsUseCase } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
|
||||
import { CreateTeamUseCase } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { UpdateTeamUseCase } from '@core/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import { ApproveTeamJoinRequestUseCase } from '@core/racing/application/use-cases/ApproveTeamJoinRequestUseCase';
|
||||
import { RejectTeamJoinRequestUseCase } from '@core/racing/application/use-cases/RejectTeamJoinRequestUseCase';
|
||||
import { GetTeamsLeaderboardUseCase } from '@core/racing/application/use-cases/GetTeamsLeaderboardUseCase';
|
||||
|
||||
// Import presenters for use case initialization
|
||||
import { DriverTeamPresenter } from './presenters/DriverTeamPresenter';
|
||||
import { TeamMembersPresenter } from './presenters/TeamMembersPresenter';
|
||||
import { TeamJoinRequestsPresenter } from './presenters/TeamJoinRequestsPresenter';
|
||||
import { TeamsLeaderboardPresenter } from './presenters/TeamsLeaderboardPresenter';
|
||||
|
||||
// Tokens
|
||||
export const TEAM_REPOSITORY_TOKEN = 'ITeamRepository';
|
||||
export const TEAM_MEMBERSHIP_REPOSITORY_TOKEN = 'ITeamMembershipRepository';
|
||||
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';
|
||||
export const IMAGE_SERVICE_TOKEN = 'IImageServicePort';
|
||||
export const TEAM_GET_ALL_USE_CASE_TOKEN = 'GetAllTeamsUseCase';
|
||||
export const TEAM_GET_DRIVER_TEAM_USE_CASE_TOKEN = 'GetDriverTeamUseCase';
|
||||
export const TEAM_GET_DETAILS_USE_CASE_TOKEN = 'GetTeamDetailsUseCase';
|
||||
export const TEAM_GET_MEMBERS_USE_CASE_TOKEN = 'GetTeamMembersUseCase';
|
||||
export const TEAM_GET_JOIN_REQUESTS_USE_CASE_TOKEN = 'GetTeamJoinRequestsUseCase';
|
||||
export const TEAM_CREATE_USE_CASE_TOKEN = 'CreateTeamUseCase';
|
||||
export const TEAM_UPDATE_USE_CASE_TOKEN = 'UpdateTeamUseCase';
|
||||
export const TEAM_APPROVE_JOIN_REQUEST_USE_CASE_TOKEN = 'ApproveTeamJoinRequestUseCase';
|
||||
export const TEAM_REJECT_JOIN_REQUEST_USE_CASE_TOKEN = 'RejectTeamJoinRequestUseCase';
|
||||
export const TEAM_GET_LEADERBOARD_USE_CASE_TOKEN = 'GetTeamsLeaderboardUseCase';
|
||||
export const TEAM_LOGGER_TOKEN = 'Logger';
|
||||
|
||||
// Simple image service implementation for team module
|
||||
class SimpleImageService implements IImageServicePort {
|
||||
getDriverAvatar(driverId: string): string {
|
||||
return `/api/media/avatars/${driverId}`;
|
||||
}
|
||||
getTeamLogo(teamId: string): string {
|
||||
return `/api/media/teams/${teamId}/logo`;
|
||||
}
|
||||
getLeagueCover(leagueId: string): string {
|
||||
return `/api/media/leagues/${leagueId}/cover`;
|
||||
}
|
||||
getLeagueLogo(leagueId: string): string {
|
||||
return `/api/media/leagues/${leagueId}/logo`;
|
||||
}
|
||||
}
|
||||
|
||||
export const TeamProviders: Provider[] = [
|
||||
TeamService, // Provide the service itself
|
||||
{
|
||||
provide: TEAM_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryTeamRepository(logger),
|
||||
inject: [TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryTeamMembershipRepository(logger),
|
||||
inject: [TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: DRIVER_REPOSITORY_TOKEN,
|
||||
useFactory: (logger: Logger) => new InMemoryDriverRepository(logger),
|
||||
inject: [TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: IMAGE_SERVICE_TOKEN,
|
||||
useClass: SimpleImageService,
|
||||
},
|
||||
{
|
||||
provide: TEAM_LOGGER_TOKEN,
|
||||
useClass: ConsoleLogger,
|
||||
},
|
||||
// Use cases
|
||||
{
|
||||
provide: TEAM_GET_ALL_USE_CASE_TOKEN,
|
||||
useFactory: (teamRepo: ITeamRepository, membershipRepo: ITeamMembershipRepository, logger: Logger) =>
|
||||
new GetAllTeamsUseCase(teamRepo, membershipRepo, logger),
|
||||
inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_GET_DRIVER_TEAM_USE_CASE_TOKEN,
|
||||
useFactory: (teamRepo: ITeamRepository, membershipRepo: ITeamMembershipRepository, logger: Logger) =>
|
||||
new GetDriverTeamUseCase(teamRepo, membershipRepo, logger, new DriverTeamPresenter()),
|
||||
inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_GET_DETAILS_USE_CASE_TOKEN,
|
||||
useFactory: (teamRepo: ITeamRepository, membershipRepo: ITeamMembershipRepository) =>
|
||||
new GetTeamDetailsUseCase(teamRepo, membershipRepo),
|
||||
inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_GET_MEMBERS_USE_CASE_TOKEN,
|
||||
useFactory: (
|
||||
membershipRepo: ITeamMembershipRepository,
|
||||
driverRepo: IDriverRepository,
|
||||
imageService: IImageServicePort,
|
||||
logger: Logger,
|
||||
) => new GetTeamMembersUseCase(membershipRepo, driverRepo, imageService, logger, new TeamMembersPresenter()),
|
||||
inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, IMAGE_SERVICE_TOKEN, TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_GET_JOIN_REQUESTS_USE_CASE_TOKEN,
|
||||
useFactory: (
|
||||
membershipRepo: ITeamMembershipRepository,
|
||||
driverRepo: IDriverRepository,
|
||||
imageService: IImageServicePort,
|
||||
logger: Logger,
|
||||
) => new GetTeamJoinRequestsUseCase(membershipRepo, driverRepo, imageService, logger, new TeamJoinRequestsPresenter()),
|
||||
inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, IMAGE_SERVICE_TOKEN, TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_CREATE_USE_CASE_TOKEN,
|
||||
useFactory: (teamRepo: ITeamRepository, membershipRepo: ITeamMembershipRepository) =>
|
||||
new CreateTeamUseCase(teamRepo, membershipRepo),
|
||||
inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_UPDATE_USE_CASE_TOKEN,
|
||||
useFactory: (teamRepo: ITeamRepository, membershipRepo: ITeamMembershipRepository) =>
|
||||
new UpdateTeamUseCase(teamRepo, membershipRepo),
|
||||
inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_APPROVE_JOIN_REQUEST_USE_CASE_TOKEN,
|
||||
useFactory: (membershipRepo: ITeamMembershipRepository, logger: Logger) =>
|
||||
new ApproveTeamJoinRequestUseCase(membershipRepo, logger),
|
||||
inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN, TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_REJECT_JOIN_REQUEST_USE_CASE_TOKEN,
|
||||
useFactory: (membershipRepo: ITeamMembershipRepository) =>
|
||||
new RejectTeamJoinRequestUseCase(membershipRepo),
|
||||
inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: TEAM_GET_LEADERBOARD_USE_CASE_TOKEN,
|
||||
useFactory: (
|
||||
teamRepo: ITeamRepository,
|
||||
membershipRepo: ITeamMembershipRepository,
|
||||
driverRepo: IDriverRepository,
|
||||
logger: Logger,
|
||||
) => new GetTeamsLeaderboardUseCase(teamRepo, membershipRepo, driverRepo, () => null, logger),
|
||||
inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, TEAM_LOGGER_TOKEN],
|
||||
},
|
||||
];
|
||||
TeamService,
|
||||
];
|
||||
@@ -1,181 +1,72 @@
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import { AllTeamsViewModel, GetDriverTeamQuery, DriverTeamViewModel, TeamDetailsViewModel, TeamMembersViewModel, TeamJoinRequestsViewModel, CreateTeamInput, CreateTeamOutput, UpdateTeamInput, UpdateTeamOutput, ApproveTeamJoinRequestInput, ApproveTeamJoinRequestOutput, RejectTeamJoinRequestInput, RejectTeamJoinRequestOutput } from './dto/TeamDto';
|
||||
|
||||
// Use cases
|
||||
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import { GetTeamDetailsUseCase } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
|
||||
import { GetTeamMembersUseCase } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
|
||||
import { GetTeamJoinRequestsUseCase } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
|
||||
import { CreateTeamUseCase } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { UpdateTeamUseCase } from '@core/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import { ApproveTeamJoinRequestUseCase } from '@core/racing/application/use-cases/ApproveTeamJoinRequestUseCase';
|
||||
import { RejectTeamJoinRequestUseCase } from '@core/racing/application/use-cases/RejectTeamJoinRequestUseCase';
|
||||
|
||||
// Presenters
|
||||
import { AllTeamsPresenter } from './presenters/AllTeamsPresenter';
|
||||
import { DriverTeamPresenter } from './presenters/DriverTeamPresenter';
|
||||
import { TeamDetailsPresenter } from './presenters/TeamDetailsPresenter';
|
||||
import { TeamMembersPresenter } from './presenters/TeamMembersPresenter';
|
||||
import { TeamJoinRequestsPresenter } from './presenters/TeamJoinRequestsPresenter';
|
||||
|
||||
// Logger
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
|
||||
// Tokens
|
||||
import {
|
||||
TEAM_GET_ALL_USE_CASE_TOKEN,
|
||||
TEAM_GET_DRIVER_TEAM_USE_CASE_TOKEN,
|
||||
TEAM_GET_DETAILS_USE_CASE_TOKEN,
|
||||
TEAM_GET_MEMBERS_USE_CASE_TOKEN,
|
||||
TEAM_GET_JOIN_REQUESTS_USE_CASE_TOKEN,
|
||||
TEAM_CREATE_USE_CASE_TOKEN,
|
||||
TEAM_UPDATE_USE_CASE_TOKEN,
|
||||
TEAM_APPROVE_JOIN_REQUEST_USE_CASE_TOKEN,
|
||||
TEAM_REJECT_JOIN_REQUEST_USE_CASE_TOKEN,
|
||||
TEAM_GET_LEADERBOARD_USE_CASE_TOKEN,
|
||||
TEAM_LOGGER_TOKEN
|
||||
} from './TeamProviders';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { GetAllTeamsOutputDTO } from './dtos/GetAllTeamsOutputDTO';
|
||||
import { GetTeamDetailsOutputDTO } from './dtos/GetTeamDetailsOutputDTO';
|
||||
import { GetTeamMembersOutputDTO } from './dtos/GetTeamMembersOutputDTO';
|
||||
import { GetTeamJoinRequestsOutputDTO } from './dtos/GetTeamJoinRequestsOutputDTO';
|
||||
import { CreateTeamInputDTO } from './dtos/CreateTeamInputDTO';
|
||||
import { CreateTeamOutputDTO } from './dtos/CreateTeamOutputDTO';
|
||||
import { UpdateTeamInputDTO } from './dtos/UpdateTeamInputDTO';
|
||||
import { UpdateTeamOutputDTO } from './dtos/UpdateTeamOutputDTO';
|
||||
import { GetDriverTeamOutputDTO } from './dtos/GetDriverTeamOutputDTO';
|
||||
import { GetTeamMembershipOutputDTO } from './dtos/GetTeamMembershipOutputDTO';
|
||||
|
||||
@Injectable()
|
||||
export class TeamService {
|
||||
constructor(
|
||||
@Inject(TEAM_GET_ALL_USE_CASE_TOKEN) private readonly getAllTeamsUseCase: GetAllTeamsUseCase,
|
||||
@Inject(TEAM_GET_DRIVER_TEAM_USE_CASE_TOKEN) private readonly getDriverTeamUseCase: GetDriverTeamUseCase,
|
||||
@Inject(TEAM_GET_DETAILS_USE_CASE_TOKEN) private readonly getTeamDetailsUseCase: GetTeamDetailsUseCase,
|
||||
@Inject(TEAM_GET_MEMBERS_USE_CASE_TOKEN) private readonly getTeamMembersUseCase: GetTeamMembersUseCase,
|
||||
@Inject(TEAM_GET_JOIN_REQUESTS_USE_CASE_TOKEN) private readonly getTeamJoinRequestsUseCase: GetTeamJoinRequestsUseCase,
|
||||
@Inject(TEAM_CREATE_USE_CASE_TOKEN) private readonly createTeamUseCase: CreateTeamUseCase,
|
||||
@Inject(TEAM_UPDATE_USE_CASE_TOKEN) private readonly updateTeamUseCase: UpdateTeamUseCase,
|
||||
@Inject(TEAM_APPROVE_JOIN_REQUEST_USE_CASE_TOKEN) private readonly approveTeamJoinRequestUseCase: ApproveTeamJoinRequestUseCase,
|
||||
@Inject(TEAM_REJECT_JOIN_REQUEST_USE_CASE_TOKEN) private readonly rejectTeamJoinRequestUseCase: RejectTeamJoinRequestUseCase,
|
||||
@Inject(TEAM_GET_LEADERBOARD_USE_CASE_TOKEN) private readonly getTeamsLeaderboardUseCase: GetTeamsLeaderboardUseCase,
|
||||
@Inject(TEAM_LOGGER_TOKEN) private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async getAllTeams(): Promise<AllTeamsViewModel> {
|
||||
this.logger.debug('[TeamService] Fetching all teams.');
|
||||
|
||||
const presenter = new AllTeamsPresenter();
|
||||
await this.getAllTeamsUseCase.execute(undefined, presenter);
|
||||
return presenter.viewModel as unknown as AllTeamsViewModel;
|
||||
async getAll(): Promise<GetAllTeamsOutputDTO> {
|
||||
// TODO: Implement getAll teams logic
|
||||
return {
|
||||
teams: [],
|
||||
totalCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
async getDriverTeam(query: GetDriverTeamQuery): Promise<DriverTeamViewModel | null> {
|
||||
this.logger.debug(`[TeamService] Fetching driver team for driverId: ${query.driverId}`);
|
||||
|
||||
const presenter = new DriverTeamPresenter();
|
||||
try {
|
||||
await this.getDriverTeamUseCase.execute({ driverId: query.driverId }, presenter);
|
||||
return presenter.viewModel as unknown as DriverTeamViewModel;
|
||||
} catch (error) {
|
||||
this.logger.error(`Error fetching driver team: ${error}`);
|
||||
return null;
|
||||
}
|
||||
async getDetails(teamId: string, userId?: string): Promise<GetTeamDetailsOutputDTO | null> {
|
||||
// TODO: Implement get team details logic
|
||||
return null;
|
||||
}
|
||||
|
||||
async getTeamDetails(teamId: string): Promise<TeamDetailsViewModel | null> {
|
||||
this.logger.debug(`[TeamService] Fetching team details for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamDetailsPresenter();
|
||||
try {
|
||||
await this.getTeamDetailsUseCase.execute({ teamId, driverId: '' }, presenter);
|
||||
return presenter.viewModel as unknown as TeamDetailsViewModel;
|
||||
} catch (error) {
|
||||
this.logger.error(`Error fetching team details: ${error}`);
|
||||
return null;
|
||||
}
|
||||
async getMembers(teamId: string): Promise<GetTeamMembersOutputDTO> {
|
||||
// TODO: Implement get team members logic
|
||||
return {
|
||||
members: [],
|
||||
totalCount: 0,
|
||||
ownerCount: 0,
|
||||
managerCount: 0,
|
||||
memberCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
async getTeamMembers(teamId: string): Promise<TeamMembersViewModel> {
|
||||
this.logger.debug(`[TeamService] Fetching team members for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamMembersPresenter();
|
||||
await this.getTeamMembersUseCase.execute({ teamId }, presenter);
|
||||
return presenter.viewModel as unknown as TeamMembersViewModel;
|
||||
async getJoinRequests(teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
|
||||
// TODO: Implement get team join requests logic
|
||||
return {
|
||||
requests: [],
|
||||
pendingCount: 0,
|
||||
totalCount: 0,
|
||||
};
|
||||
}
|
||||
|
||||
async getTeamJoinRequests(teamId: string): Promise<TeamJoinRequestsViewModel> {
|
||||
this.logger.debug(`[TeamService] Fetching join requests for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamJoinRequestsPresenter();
|
||||
await this.getTeamJoinRequestsUseCase.execute({ teamId }, presenter);
|
||||
return presenter.viewModel as unknown as TeamJoinRequestsViewModel;
|
||||
async create(input: CreateTeamInputDTO, userId?: string): Promise<CreateTeamOutputDTO> {
|
||||
// TODO: Implement create team logic
|
||||
return {
|
||||
id: 'placeholder-id',
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
async createTeam(input: CreateTeamInput): Promise<CreateTeamOutput> {
|
||||
this.logger.debug('[TeamService] Creating team', input);
|
||||
|
||||
try {
|
||||
const result = await this.createTeamUseCase.execute({
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description,
|
||||
ownerId: input.ownerId,
|
||||
leagues: [],
|
||||
});
|
||||
return {
|
||||
teamId: result.team.id,
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(`Error creating team: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
async update(teamId: string, input: UpdateTeamInputDTO, userId?: string): Promise<UpdateTeamOutputDTO> {
|
||||
// TODO: Implement update team logic
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
async updateTeam(input: UpdateTeamInput & { teamId: string }): Promise<UpdateTeamOutput> {
|
||||
this.logger.debug('[TeamService] Updating team', input);
|
||||
|
||||
try {
|
||||
await this.updateTeamUseCase.execute({
|
||||
teamId: input.teamId,
|
||||
updates: {
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description,
|
||||
},
|
||||
updatedBy: input.updatedBy,
|
||||
});
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.logger.error(`Error updating team: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
async getDriverTeam(driverId: string): Promise<GetDriverTeamOutputDTO | null> {
|
||||
// TODO: Implement get driver team logic
|
||||
return null;
|
||||
}
|
||||
|
||||
async approveTeamJoinRequest(input: ApproveTeamJoinRequestInput & { teamId: string }): Promise<ApproveTeamJoinRequestOutput> {
|
||||
this.logger.debug('[TeamService] Approving team join request', input);
|
||||
|
||||
try {
|
||||
await this.approveTeamJoinRequestUseCase.execute({ requestId: input.requestId });
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.logger.error(`Error approving join request: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
async getMembership(teamId: string, driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
|
||||
// TODO: Implement get team membership logic
|
||||
return null;
|
||||
}
|
||||
|
||||
async rejectTeamJoinRequest(input: RejectTeamJoinRequestInput & { teamId: string }): Promise<RejectTeamJoinRequestOutput> {
|
||||
this.logger.debug('[TeamService] Rejecting team join request', input);
|
||||
|
||||
try {
|
||||
await this.rejectTeamJoinRequestUseCase.execute({ requestId: input.requestId });
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.logger.error(`Error rejecting join request: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getTeamsLeaderboard(): Promise<any> {
|
||||
this.logger.debug('[TeamService] Fetching teams leaderboard');
|
||||
|
||||
const result = await this.getTeamsLeaderboardUseCase.execute();
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching teams leaderboard: ${result.error}`);
|
||||
throw new Error('Failed to fetch teams leaderboard');
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
apps/api/src/domain/team/dtos/CreateTeamInputDTO.ts
Normal file
19
apps/api/src/domain/team/dtos/CreateTeamInputDTO.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
|
||||
|
||||
export class CreateTeamInputDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
tag: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
}
|
||||
9
apps/api/src/domain/team/dtos/CreateTeamOutputDTO.ts
Normal file
9
apps/api/src/domain/team/dtos/CreateTeamOutputDTO.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateTeamOutputDTO {
|
||||
@ApiProperty()
|
||||
id: string;
|
||||
|
||||
@ApiProperty()
|
||||
success: boolean;
|
||||
}
|
||||
38
apps/api/src/domain/team/dtos/GetAllTeamsOutputDTO.ts
Normal file
38
apps/api/src/domain/team/dtos/GetAllTeamsOutputDTO.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
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[];
|
||||
}
|
||||
|
||||
export class GetAllTeamsOutputDTO {
|
||||
@ApiProperty({ type: [TeamListItemDTO] })
|
||||
teams: TeamListItemDTO[];
|
||||
|
||||
@ApiProperty()
|
||||
totalCount: number;
|
||||
}
|
||||
58
apps/api/src/domain/team/dtos/GetDriverTeamOutputDTO.ts
Normal file
58
apps/api/src/domain/team/dtos/GetDriverTeamOutputDTO.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
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;
|
||||
}
|
||||
|
||||
export class GetDriverTeamOutputDTO {
|
||||
@ApiProperty({ type: TeamDTO })
|
||||
team: TeamDTO;
|
||||
|
||||
@ApiProperty({ type: MembershipDTO })
|
||||
membership: MembershipDTO;
|
||||
|
||||
@ApiProperty()
|
||||
isOwner: boolean;
|
||||
|
||||
@ApiProperty()
|
||||
canManage: boolean;
|
||||
}
|
||||
55
apps/api/src/domain/team/dtos/GetTeamDetailsOutputDTO.ts
Normal file
55
apps/api/src/domain/team/dtos/GetTeamDetailsOutputDTO.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
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;
|
||||
}
|
||||
|
||||
export class GetTeamDetailsOutputDTO {
|
||||
@ApiProperty({ type: TeamDTO })
|
||||
team: TeamDTO;
|
||||
|
||||
@ApiProperty({ type: MembershipDTO, nullable: true })
|
||||
membership: MembershipDTO | null;
|
||||
|
||||
@ApiProperty()
|
||||
canManage: boolean;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
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;
|
||||
}
|
||||
|
||||
export class GetTeamJoinRequestsOutputDTO {
|
||||
@ApiProperty({ type: [TeamJoinRequestDTO] })
|
||||
requests: TeamJoinRequestDTO[];
|
||||
|
||||
@ApiProperty()
|
||||
pendingCount: number;
|
||||
|
||||
@ApiProperty()
|
||||
totalCount: number;
|
||||
}
|
||||
38
apps/api/src/domain/team/dtos/GetTeamMembersOutputDTO.ts
Normal file
38
apps/api/src/domain/team/dtos/GetTeamMembersOutputDTO.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
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;
|
||||
}
|
||||
|
||||
export class GetTeamMembersOutputDTO {
|
||||
@ApiProperty({ type: [TeamMemberDTO] })
|
||||
members: TeamMemberDTO[];
|
||||
|
||||
@ApiProperty()
|
||||
totalCount: number;
|
||||
|
||||
@ApiProperty()
|
||||
ownerCount: number;
|
||||
|
||||
@ApiProperty()
|
||||
managerCount: number;
|
||||
|
||||
@ApiProperty()
|
||||
memberCount: number;
|
||||
}
|
||||
12
apps/api/src/domain/team/dtos/GetTeamMembershipOutputDTO.ts
Normal file
12
apps/api/src/domain/team/dtos/GetTeamMembershipOutputDTO.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class GetTeamMembershipOutputDTO {
|
||||
@ApiProperty()
|
||||
role: 'owner' | 'manager' | 'member';
|
||||
|
||||
@ApiProperty()
|
||||
joinedAt: string;
|
||||
|
||||
@ApiProperty()
|
||||
isActive: boolean;
|
||||
}
|
||||
19
apps/api/src/domain/team/dtos/UpdateTeamInputDTO.ts
Normal file
19
apps/api/src/domain/team/dtos/UpdateTeamInputDTO.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsOptional } from 'class-validator';
|
||||
|
||||
export class UpdateTeamInputDTO {
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
tag?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
}
|
||||
6
apps/api/src/domain/team/dtos/UpdateTeamOutputDTO.ts
Normal file
6
apps/api/src/domain/team/dtos/UpdateTeamOutputDTO.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class UpdateTeamOutputDTO {
|
||||
@ApiProperty()
|
||||
success: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user