presenter refactoring
This commit is contained in:
@@ -22,7 +22,8 @@ export class TeamController {
|
||||
@ApiOperation({ summary: 'Get all teams' })
|
||||
@ApiResponse({ status: 200, description: 'List of all teams', type: GetAllTeamsOutputDTO })
|
||||
async getAll(): Promise<GetAllTeamsOutputDTO> {
|
||||
return this.teamService.getAll();
|
||||
const presenter = await this.teamService.getAll();
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get(':teamId')
|
||||
@@ -31,21 +32,24 @@ export class TeamController {
|
||||
@ApiResponse({ status: 404, description: 'Team not found' })
|
||||
async getDetails(@Param('teamId') teamId: string, @Req() req: Request): Promise<GetTeamDetailsOutputDTO | null> {
|
||||
const userId = req['user']?.userId;
|
||||
return this.teamService.getDetails(teamId, userId);
|
||||
const presenter = await this.teamService.getDetails(teamId, userId);
|
||||
return presenter.getViewModel();
|
||||
}
|
||||
|
||||
@Get(':teamId/members')
|
||||
@ApiOperation({ summary: 'Get team members' })
|
||||
@ApiResponse({ status: 200, description: 'Team members', type: GetTeamMembersOutputDTO })
|
||||
async getMembers(@Param('teamId') teamId: string): Promise<GetTeamMembersOutputDTO> {
|
||||
return this.teamService.getMembers(teamId);
|
||||
const presenter = await this.teamService.getMembers(teamId);
|
||||
return presenter.getViewModel()!;
|
||||
}
|
||||
|
||||
@Get(':teamId/join-requests')
|
||||
@ApiOperation({ summary: 'Get team join requests' })
|
||||
@ApiResponse({ status: 200, description: 'Team join requests', type: GetTeamJoinRequestsOutputDTO })
|
||||
async getJoinRequests(@Param('teamId') teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
|
||||
return this.teamService.getJoinRequests(teamId);
|
||||
const presenter = await this.teamService.getJoinRequests(teamId);
|
||||
return presenter.getViewModel()!;
|
||||
}
|
||||
|
||||
@Post()
|
||||
@@ -53,7 +57,8 @@ export class TeamController {
|
||||
@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);
|
||||
const presenter = await this.teamService.create(input, userId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Patch(':teamId')
|
||||
@@ -61,7 +66,8 @@ export class TeamController {
|
||||
@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);
|
||||
const presenter = await this.teamService.update(teamId, input, userId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('driver/:driverId')
|
||||
@@ -69,14 +75,16 @@ export class TeamController {
|
||||
@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);
|
||||
const presenter = await this.teamService.getDriverTeam(driverId);
|
||||
return presenter.getViewModel();
|
||||
}
|
||||
|
||||
|
||||
@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);
|
||||
const presenter = await this.teamService.getMembership(teamId, driverId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriv
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
import { AllTeamsPresenter } from './presenters/AllTeamsPresenter';
|
||||
import { DriverTeamPresenter } from './presenters/DriverTeamPresenter';
|
||||
import { AllTeamsViewModel, DriverTeamViewModel } from './dtos/TeamDto';
|
||||
|
||||
describe('TeamService', () => {
|
||||
let service: TeamService;
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import { Injectable, Inject } 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';
|
||||
|
||||
// Core imports
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
@@ -29,6 +21,9 @@ import { TeamDetailsPresenter } from './presenters/TeamDetailsPresenter';
|
||||
import { TeamMembersPresenter } from './presenters/TeamMembersPresenter';
|
||||
import { TeamJoinRequestsPresenter } from './presenters/TeamJoinRequestsPresenter';
|
||||
import { DriverTeamPresenter } from './presenters/DriverTeamPresenter';
|
||||
import { TeamMembershipPresenter } from './presenters/TeamMembershipPresenter';
|
||||
import { CreateTeamPresenter } from './presenters/CreateTeamPresenter';
|
||||
import { UpdateTeamPresenter } from './presenters/UpdateTeamPresenter';
|
||||
|
||||
// Tokens
|
||||
import { LOGGER_TOKEN } from './TeamProviders';
|
||||
@@ -47,125 +42,150 @@ export class TeamService {
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async getAll(): Promise<GetAllTeamsOutputDTO> {
|
||||
async getAll(): Promise<AllTeamsPresenter> {
|
||||
this.logger.debug('[TeamService] Fetching all teams.');
|
||||
|
||||
const presenter = new AllTeamsPresenter();
|
||||
const result = await this.getAllTeamsUseCase.execute();
|
||||
if (result.isErr()) {
|
||||
this.logger.error('Error fetching all teams', result.error);
|
||||
return { teams: [], totalCount: 0 };
|
||||
await presenter.present({ teams: [], totalCount: 0 });
|
||||
return presenter;
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter.getViewModel()!;
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getDetails(teamId: string, userId?: string): Promise<GetTeamDetailsOutputDTO | null> {
|
||||
async getDetails(teamId: string, userId?: string): Promise<TeamDetailsPresenter> {
|
||||
this.logger.debug(`[TeamService] Fetching team details for teamId: ${teamId}, userId: ${userId}`);
|
||||
|
||||
const presenter = new TeamDetailsPresenter();
|
||||
const result = await this.getTeamDetailsUseCase.execute({ teamId, driverId: userId || '' });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team details for teamId: ${teamId}`, result.error);
|
||||
return null;
|
||||
return presenter;
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter.getViewModel();
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getMembers(teamId: string): Promise<GetTeamMembersOutputDTO> {
|
||||
async getMembers(teamId: string): Promise<TeamMembersPresenter> {
|
||||
this.logger.debug(`[TeamService] Fetching team members for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamMembersPresenter();
|
||||
const result = await this.getTeamMembersUseCase.execute({ teamId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team members for teamId: ${teamId}`, result.error);
|
||||
return {
|
||||
await presenter.present({
|
||||
members: [],
|
||||
totalCount: 0,
|
||||
ownerCount: 0,
|
||||
managerCount: 0,
|
||||
memberCount: 0,
|
||||
};
|
||||
} as unknown as any);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter.getViewModel()!;
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getJoinRequests(teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
|
||||
async getJoinRequests(teamId: string): Promise<TeamJoinRequestsPresenter> {
|
||||
this.logger.debug(`[TeamService] Fetching team join requests for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamJoinRequestsPresenter();
|
||||
const result = await this.getTeamJoinRequestsUseCase.execute({ teamId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team join requests for teamId: ${teamId}`, result.error);
|
||||
return {
|
||||
await presenter.present({
|
||||
requests: [],
|
||||
pendingCount: 0,
|
||||
totalCount: 0,
|
||||
};
|
||||
} as unknown as any);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter.getViewModel()!;
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async create(input: CreateTeamInputDTO, userId?: string): Promise<CreateTeamOutputDTO> {
|
||||
async create(input: CreateTeamInputDTO, userId?: string): Promise<CreateTeamPresenter> {
|
||||
this.logger.debug('[TeamService] Creating team', { input, userId });
|
||||
|
||||
const presenter = new CreateTeamPresenter();
|
||||
|
||||
const command = {
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description,
|
||||
description: input.description ?? '',
|
||||
ownerId: userId || '',
|
||||
leagues: [],
|
||||
};
|
||||
const result = await this.createTeamUseCase.execute(command);
|
||||
|
||||
const result = await this.createTeamUseCase.execute(command as any);
|
||||
if (result.isErr()) {
|
||||
this.logger.error('Error creating team', result.error);
|
||||
return { id: '', success: false };
|
||||
presenter.presentError();
|
||||
return presenter;
|
||||
}
|
||||
return { id: result.value.id, success: true };
|
||||
|
||||
presenter.presentSuccess(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async update(teamId: string, input: UpdateTeamInputDTO, userId?: string): Promise<UpdateTeamOutputDTO> {
|
||||
async update(teamId: string, input: UpdateTeamInputDTO, userId?: string): Promise<UpdateTeamPresenter> {
|
||||
this.logger.debug(`[TeamService] Updating team ${teamId}`, { input, userId });
|
||||
|
||||
const presenter = new UpdateTeamPresenter();
|
||||
|
||||
const command = {
|
||||
teamId,
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description,
|
||||
performerId: userId || '',
|
||||
updates: {
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description,
|
||||
},
|
||||
updatedBy: userId || '',
|
||||
};
|
||||
const result = await this.updateTeamUseCase.execute(command);
|
||||
|
||||
const result = await this.updateTeamUseCase.execute(command as any);
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error updating team ${teamId}`, result.error);
|
||||
return { success: false };
|
||||
presenter.presentError();
|
||||
return presenter;
|
||||
}
|
||||
return { success: true };
|
||||
|
||||
presenter.presentSuccess();
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getDriverTeam(driverId: string): Promise<GetDriverTeamOutputDTO | null> {
|
||||
async getDriverTeam(driverId: string): Promise<DriverTeamPresenter> {
|
||||
this.logger.debug(`[TeamService] Fetching driver team for driverId: ${driverId}`);
|
||||
|
||||
const presenter = new DriverTeamPresenter();
|
||||
const result = await this.getDriverTeamUseCase.execute({ driverId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching driver team for driverId: ${driverId}`, result.error);
|
||||
return null;
|
||||
return presenter;
|
||||
}
|
||||
|
||||
const presenter = new DriverTeamPresenter();
|
||||
await presenter.present(result.value);
|
||||
return presenter.getViewModel();
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getMembership(teamId: string, driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
|
||||
async getMembership(teamId: string, driverId: string): Promise<TeamMembershipPresenter> {
|
||||
this.logger.debug(`[TeamService] Fetching team membership for teamId: ${teamId}, driverId: ${driverId}`);
|
||||
|
||||
const presenter = new TeamMembershipPresenter();
|
||||
const result = await this.getTeamMembershipUseCase.execute({ teamId, driverId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team membership for teamId: ${teamId}, driverId: ${driverId}`, result.error);
|
||||
return null;
|
||||
return presenter;
|
||||
}
|
||||
return result.value;
|
||||
|
||||
presenter.present(result.value as any);
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
36
apps/api/src/domain/team/presenters/CreateTeamPresenter.ts
Normal file
36
apps/api/src/domain/team/presenters/CreateTeamPresenter.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { CreateTeamOutputPort } from '@core/racing/application/ports/output/CreateTeamOutputPort';
|
||||
import type { CreateTeamOutputDTO } from '../dtos/CreateTeamOutputDTO';
|
||||
|
||||
export class CreateTeamPresenter {
|
||||
private result: CreateTeamOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
presentSuccess(output: CreateTeamOutputPort): void {
|
||||
this.result = {
|
||||
id: output.team.id,
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
presentError(): void {
|
||||
this.result = {
|
||||
id: '',
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): CreateTeamOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): CreateTeamOutputDTO {
|
||||
if (!this.result) {
|
||||
throw new Error('Presenter not presented');
|
||||
}
|
||||
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { GetTeamMembershipOutputDTO } from '../dtos/GetTeamMembershipOutputDTO';
|
||||
|
||||
export class TeamMembershipPresenter {
|
||||
private result: GetTeamMembershipOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(membership: GetTeamMembershipOutputDTO | null): void {
|
||||
if (!membership) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
role: membership.role,
|
||||
joinedAt: membership.joinedAt,
|
||||
isActive: membership.isActive,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): GetTeamMembershipOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): GetTeamMembershipOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
33
apps/api/src/domain/team/presenters/UpdateTeamPresenter.ts
Normal file
33
apps/api/src/domain/team/presenters/UpdateTeamPresenter.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { UpdateTeamOutputDTO } from '../dtos/UpdateTeamOutputDTO';
|
||||
|
||||
export class UpdateTeamPresenter {
|
||||
private result: UpdateTeamOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
presentSuccess(): void {
|
||||
this.result = {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
presentError(): void {
|
||||
this.result = {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): UpdateTeamOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): UpdateTeamOutputDTO {
|
||||
if (!this.result) {
|
||||
throw new Error('Presenter not presented');
|
||||
}
|
||||
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user