module cleanup
This commit is contained in:
15
core/racing/application/presenters/ICreateLeaguePresenter.ts
Normal file
15
core/racing/application/presenters/ICreateLeaguePresenter.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Presenter } from './Presenter';
|
||||
|
||||
export interface CreateLeagueResultDTO {
|
||||
leagueId: string;
|
||||
seasonId: string;
|
||||
scoringPresetId?: string;
|
||||
scoringPresetName?: string;
|
||||
}
|
||||
|
||||
export interface CreateLeagueViewModel {
|
||||
leagueId: string;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface ICreateLeaguePresenter extends Presenter<CreateLeagueResultDTO, CreateLeagueViewModel> {}
|
||||
13
core/racing/application/presenters/IJoinLeaguePresenter.ts
Normal file
13
core/racing/application/presenters/IJoinLeaguePresenter.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Presenter } from './Presenter';
|
||||
|
||||
export interface JoinLeagueResultDTO {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface JoinLeagueViewModel {
|
||||
success: boolean;
|
||||
membershipId?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface IJoinLeaguePresenter extends Presenter<JoinLeagueResultDTO, JoinLeagueViewModel> {}
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Presenter } from '@core/shared/presentation/Presenter';
|
||||
|
||||
export interface RemoveLeagueMemberViewModel {
|
||||
success: boolean;
|
||||
}
|
||||
import { Presenter } from './Presenter';
|
||||
|
||||
export interface RemoveLeagueMemberResultDTO {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface RemoveLeagueMemberViewModel {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface IRemoveLeagueMemberPresenter extends Presenter<RemoveLeagueMemberResultDTO, RemoveLeagueMemberViewModel> {}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Presenter } from './Presenter';
|
||||
|
||||
export interface TransferLeagueOwnershipResultDTO {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface TransferLeagueOwnershipViewModel {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ITransferLeagueOwnershipPresenter extends Presenter<TransferLeagueOwnershipResultDTO, TransferLeagueOwnershipViewModel> {}
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Presenter } from '@core/shared/presentation/Presenter';
|
||||
|
||||
export interface UpdateLeagueMemberRoleViewModel {
|
||||
success: boolean;
|
||||
}
|
||||
import { Presenter } from './Presenter';
|
||||
|
||||
export interface UpdateLeagueMemberRoleResultDTO {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateLeagueMemberRoleViewModel {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface IUpdateLeagueMemberRolePresenter extends Presenter<UpdateLeagueMemberRoleResultDTO, UpdateLeagueMemberRoleViewModel> {}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { GetTeamMembershipUseCase } from './GetTeamMembershipUseCase';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
|
||||
describe('GetTeamMembershipUseCase', () => {
|
||||
const mockGetMembership = vi.fn();
|
||||
const mockMembershipRepo: ITeamMembershipRepository = {
|
||||
getMembership: mockGetMembership,
|
||||
getActiveMembershipForDriver: vi.fn(),
|
||||
getTeamMembers: vi.fn(),
|
||||
saveMembership: vi.fn(),
|
||||
removeMembership: vi.fn(),
|
||||
getJoinRequests: vi.fn(),
|
||||
countByTeamId: vi.fn(),
|
||||
saveJoinRequest: vi.fn(),
|
||||
removeJoinRequest: vi.fn(),
|
||||
};
|
||||
|
||||
const mockLogger: Logger = {
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return membership data when membership exists', async () => {
|
||||
const useCase = new GetTeamMembershipUseCase(
|
||||
mockMembershipRepo,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const teamId = 'team1';
|
||||
const driverId = 'driver1';
|
||||
const membership = {
|
||||
teamId,
|
||||
driverId,
|
||||
role: 'manager' as const,
|
||||
status: 'active' as const,
|
||||
joinedAt: new Date('2023-01-01'),
|
||||
};
|
||||
|
||||
mockGetMembership.mockResolvedValue(membership);
|
||||
|
||||
const result = await useCase.execute({ teamId, driverId });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.value).toEqual({
|
||||
role: 'manager',
|
||||
joinedAt: '2023-01-01T00:00:00.000Z',
|
||||
isActive: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null when no membership exists', async () => {
|
||||
const useCase = new GetTeamMembershipUseCase(
|
||||
mockMembershipRepo,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const teamId = 'team1';
|
||||
const driverId = 'driver1';
|
||||
|
||||
mockGetMembership.mockResolvedValue(null);
|
||||
|
||||
const result = await useCase.execute({ teamId, driverId });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.value).toBe(null);
|
||||
});
|
||||
|
||||
it('should map driver role to member', async () => {
|
||||
const useCase = new GetTeamMembershipUseCase(
|
||||
mockMembershipRepo,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const teamId = 'team1';
|
||||
const driverId = 'driver1';
|
||||
const membership = {
|
||||
teamId,
|
||||
driverId,
|
||||
role: 'driver' as const,
|
||||
status: 'active' as const,
|
||||
joinedAt: new Date('2023-01-01'),
|
||||
};
|
||||
|
||||
mockGetMembership.mockResolvedValue(membership);
|
||||
|
||||
const result = await useCase.execute({ teamId, driverId });
|
||||
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.value?.role).toBe('member');
|
||||
});
|
||||
|
||||
it('should return error when repository throws', async () => {
|
||||
const useCase = new GetTeamMembershipUseCase(
|
||||
mockMembershipRepo,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
const teamId = 'team1';
|
||||
const driverId = 'driver1';
|
||||
const error = new Error('Repository error');
|
||||
|
||||
mockGetMembership.mockRejectedValue(error);
|
||||
|
||||
const result = await useCase.execute({ teamId, driverId });
|
||||
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR');
|
||||
expect(result.unwrapErr().details.message).toBe('Failed to retrieve team membership');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type { AsyncUseCase, Logger } from '@core/shared/application';
|
||||
|
||||
/**
|
||||
* Use Case for retrieving a driver's membership in a team.
|
||||
*/
|
||||
export class GetTeamMembershipUseCase
|
||||
implements AsyncUseCase<{ teamId: string; driverId: string }, { role: 'owner' | 'manager' | 'member'; joinedAt: string; isActive: boolean } | null, 'REPOSITORY_ERROR'>
|
||||
{
|
||||
constructor(
|
||||
private readonly membershipRepository: ITeamMembershipRepository,
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(input: { teamId: string; driverId: string }): Promise<Result<{ role: 'owner' | 'manager' | 'member'; joinedAt: string; isActive: boolean } | null, ApplicationErrorCode<'REPOSITORY_ERROR'>>> {
|
||||
this.logger.debug(`Executing GetTeamMembershipUseCase for teamId: ${input.teamId}, driverId: ${input.driverId}`);
|
||||
|
||||
try {
|
||||
const membership = await this.membershipRepository.getMembership(input.teamId, input.driverId);
|
||||
if (!membership) {
|
||||
this.logger.debug(`No membership found for teamId: ${input.teamId}, driverId: ${input.driverId}`);
|
||||
return Result.ok(null);
|
||||
}
|
||||
|
||||
const result = {
|
||||
role: membership.role === 'driver' ? 'member' : membership.role as 'owner' | 'manager' | 'member',
|
||||
joinedAt: membership.joinedAt.toISOString(),
|
||||
isActive: membership.status === 'active',
|
||||
};
|
||||
|
||||
this.logger.info(`Successfully retrieved membership for teamId: ${input.teamId}, driverId: ${input.driverId}`);
|
||||
return Result.ok(result);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error in GetTeamMembershipUseCase for teamId: ${input.teamId}, driverId: ${input.driverId}`, error as Error);
|
||||
return Result.err({ code: 'REPOSITORY_ERROR', details: { message: 'Failed to retrieve team membership' } });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import type { IRejectLeagueJoinRequestPresenter, RejectLeagueJoinRequestResultDTO, RejectLeagueJoinRequestViewModel } from '../presenters/IRejectLeagueJoinRequestPresenter';
|
||||
import type { UseCase } from '@core/shared/application/UseCase';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type { AsyncUseCase } from '@core/shared/application';
|
||||
|
||||
export interface RejectLeagueJoinRequestUseCaseParams {
|
||||
requestId: string;
|
||||
@@ -11,13 +12,12 @@ export interface RejectLeagueJoinRequestResultDTO {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export class RejectLeagueJoinRequestUseCase implements UseCase<RejectLeagueJoinRequestUseCaseParams, RejectLeagueJoinRequestResultDTO, RejectLeagueJoinRequestViewModel, IRejectLeagueJoinRequestPresenter> {
|
||||
export class RejectLeagueJoinRequestUseCase implements AsyncUseCase<RejectLeagueJoinRequestUseCaseParams, RejectLeagueJoinRequestResultDTO, 'NO_ERROR'> {
|
||||
constructor(private readonly leagueMembershipRepository: ILeagueMembershipRepository) {}
|
||||
|
||||
async execute(params: RejectLeagueJoinRequestUseCaseParams, presenter: IRejectLeagueJoinRequestPresenter): Promise<void> {
|
||||
async execute(params: RejectLeagueJoinRequestUseCaseParams): Promise<Result<RejectLeagueJoinRequestResultDTO, ApplicationErrorCode<'NO_ERROR'>>> {
|
||||
await this.leagueMembershipRepository.removeJoinRequest(params.requestId);
|
||||
const dto: RejectLeagueJoinRequestResultDTO = { success: true, message: 'Join request rejected.' };
|
||||
presenter.reset();
|
||||
presenter.present(dto);
|
||||
return Result.ok(dto);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeague
|
||||
import type {
|
||||
MembershipRole,
|
||||
} from '@core/racing/domain/entities/LeagueMembership';
|
||||
import type { TransferLeagueOwnershipResultDTO } from '../presenters/ITransferLeagueOwnershipPresenter';
|
||||
|
||||
export interface TransferLeagueOwnershipCommandDTO {
|
||||
leagueId: string;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
||||
import type { UpdateLeagueMemberRoleResultDTO } from '../presenters/IUpdateLeagueMemberRolePresenter';
|
||||
|
||||
export interface UpdateLeagueMemberRoleUseCaseParams {
|
||||
leagueId: string;
|
||||
@@ -11,7 +12,7 @@ export interface UpdateLeagueMemberRoleUseCaseParams {
|
||||
export class UpdateLeagueMemberRoleUseCase {
|
||||
constructor(private readonly leagueMembershipRepository: ILeagueMembershipRepository) {}
|
||||
|
||||
async execute(params: UpdateLeagueMemberRoleUseCaseParams): Promise<Result<void, ApplicationErrorCode<'MEMBERSHIP_NOT_FOUND'>>> {
|
||||
async execute(params: UpdateLeagueMemberRoleUseCaseParams): Promise<Result<UpdateLeagueMemberRoleResultDTO, ApplicationErrorCode<'MEMBERSHIP_NOT_FOUND'>>> {
|
||||
const memberships = await this.leagueMembershipRepository.getLeagueMembers(params.leagueId);
|
||||
const membership = memberships.find(m => m.driverId === params.targetDriverId);
|
||||
if (!membership) {
|
||||
@@ -21,6 +22,6 @@ export class UpdateLeagueMemberRoleUseCase {
|
||||
...membership,
|
||||
role: params.newRole,
|
||||
});
|
||||
return Result.ok(undefined);
|
||||
return Result.ok({ success: true });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user