integration tests
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export interface ApproveMembershipRequestCommand {
|
||||
leagueId: string;
|
||||
requestId: string;
|
||||
}
|
||||
4
core/leagues/application/ports/DemoteAdminCommand.ts
Normal file
4
core/leagues/application/ports/DemoteAdminCommand.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface DemoteAdminCommand {
|
||||
leagueId: string;
|
||||
targetDriverId: string;
|
||||
}
|
||||
4
core/leagues/application/ports/JoinLeagueCommand.ts
Normal file
4
core/leagues/application/ports/JoinLeagueCommand.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface JoinLeagueCommand {
|
||||
leagueId: string;
|
||||
driverId: string;
|
||||
}
|
||||
@@ -25,16 +25,24 @@ export interface LeagueAccessedEvent {
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
export interface LeagueRosterAccessedEvent {
|
||||
type: 'LeagueRosterAccessedEvent';
|
||||
leagueId: string;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
export interface LeagueEventPublisher {
|
||||
emitLeagueCreated(event: LeagueCreatedEvent): Promise<void>;
|
||||
emitLeagueUpdated(event: LeagueUpdatedEvent): Promise<void>;
|
||||
emitLeagueDeleted(event: LeagueDeletedEvent): Promise<void>;
|
||||
emitLeagueAccessed(event: LeagueAccessedEvent): Promise<void>;
|
||||
emitLeagueRosterAccessed(event: LeagueRosterAccessedEvent): Promise<void>;
|
||||
|
||||
getLeagueCreatedEventCount(): number;
|
||||
getLeagueUpdatedEventCount(): number;
|
||||
getLeagueDeletedEventCount(): number;
|
||||
getLeagueAccessedEventCount(): number;
|
||||
getLeagueRosterAccessedEventCount(): number;
|
||||
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
@@ -128,6 +128,20 @@ export interface LeagueComplexResolutionTimeMetrics {
|
||||
stewardingActionAppealPenaltyProtestResolutionTime2: number;
|
||||
}
|
||||
|
||||
export interface LeagueMember {
|
||||
driverId: string;
|
||||
name: string;
|
||||
role: 'owner' | 'admin' | 'steward' | 'member';
|
||||
joinDate: Date;
|
||||
}
|
||||
|
||||
export interface LeaguePendingRequest {
|
||||
id: string;
|
||||
driverId: string;
|
||||
name: string;
|
||||
requestDate: Date;
|
||||
}
|
||||
|
||||
export interface LeagueRepository {
|
||||
create(league: LeagueData): Promise<LeagueData>;
|
||||
findById(id: string): Promise<LeagueData | null>;
|
||||
@@ -166,4 +180,7 @@ export interface LeagueRepository {
|
||||
|
||||
getComplexResolutionTimeMetrics(leagueId: string): Promise<LeagueComplexResolutionTimeMetrics>;
|
||||
updateComplexResolutionTimeMetrics(leagueId: string, metrics: LeagueComplexResolutionTimeMetrics): Promise<LeagueComplexResolutionTimeMetrics>;
|
||||
|
||||
getLeagueMembers(leagueId: string): Promise<LeagueMember[]>;
|
||||
getPendingRequests(leagueId: string): Promise<LeaguePendingRequest[]>;
|
||||
}
|
||||
|
||||
3
core/leagues/application/ports/LeagueRosterQuery.ts
Normal file
3
core/leagues/application/ports/LeagueRosterQuery.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface LeagueRosterQuery {
|
||||
leagueId: string;
|
||||
}
|
||||
4
core/leagues/application/ports/LeaveLeagueCommand.ts
Normal file
4
core/leagues/application/ports/LeaveLeagueCommand.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface LeaveLeagueCommand {
|
||||
leagueId: string;
|
||||
driverId: string;
|
||||
}
|
||||
4
core/leagues/application/ports/PromoteMemberCommand.ts
Normal file
4
core/leagues/application/ports/PromoteMemberCommand.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface PromoteMemberCommand {
|
||||
leagueId: string;
|
||||
targetDriverId: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface RejectMembershipRequestCommand {
|
||||
leagueId: string;
|
||||
requestId: string;
|
||||
}
|
||||
4
core/leagues/application/ports/RemoveMemberCommand.ts
Normal file
4
core/leagues/application/ports/RemoveMemberCommand.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface RemoveMemberCommand {
|
||||
leagueId: string;
|
||||
targetDriverId: string;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { ApproveMembershipRequestCommand } from '../ports/ApproveMembershipRequestCommand';
|
||||
|
||||
export class ApproveMembershipRequestUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: ApproveMembershipRequestCommand): Promise<void> {
|
||||
// TODO: Implement approve membership request logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the admin has permission to approve
|
||||
// 3. Find the pending request
|
||||
// 4. Add the driver to the league as a member
|
||||
// 5. Remove the pending request
|
||||
// 6. Emit appropriate events
|
||||
throw new Error('ApproveMembershipRequestUseCase not implemented');
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,10 @@ export class CreateLeagueUseCase {
|
||||
throw new Error('League name is required');
|
||||
}
|
||||
|
||||
if (command.name.length > 255) {
|
||||
throw new Error('League name is too long');
|
||||
}
|
||||
|
||||
if (!command.ownerId || command.ownerId.trim() === '') {
|
||||
throw new Error('Owner ID is required');
|
||||
}
|
||||
|
||||
24
core/leagues/application/use-cases/DemoteAdminUseCase.ts
Normal file
24
core/leagues/application/use-cases/DemoteAdminUseCase.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { DemoteAdminCommand } from '../ports/DemoteAdminCommand';
|
||||
|
||||
export class DemoteAdminUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: DemoteAdminCommand): Promise<void> {
|
||||
// TODO: Implement demote admin logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the admin has permission to demote
|
||||
// 3. Find the admin to demote
|
||||
// 4. Update the admin's role to member
|
||||
// 5. Emit appropriate events
|
||||
throw new Error('DemoteAdminUseCase not implemented');
|
||||
}
|
||||
}
|
||||
81
core/leagues/application/use-cases/GetLeagueRosterUseCase.ts
Normal file
81
core/leagues/application/use-cases/GetLeagueRosterUseCase.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { LeagueRosterQuery } from '../ports/LeagueRosterQuery';
|
||||
import { LeagueEventPublisher, LeagueRosterAccessedEvent } from '../ports/LeagueEventPublisher';
|
||||
|
||||
export interface LeagueRosterResult {
|
||||
leagueId: string;
|
||||
members: Array<{
|
||||
driverId: string;
|
||||
name: string;
|
||||
role: 'owner' | 'admin' | 'steward' | 'member';
|
||||
joinDate: Date;
|
||||
}>;
|
||||
pendingRequests: Array<{
|
||||
requestId: string;
|
||||
driverId: string;
|
||||
name: string;
|
||||
requestDate: Date;
|
||||
}>;
|
||||
stats: {
|
||||
adminCount: number;
|
||||
driverCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class GetLeagueRosterUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly eventPublisher: LeagueEventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(query: LeagueRosterQuery): Promise<LeagueRosterResult> {
|
||||
// Validate query
|
||||
if (!query.leagueId || query.leagueId.trim() === '') {
|
||||
throw new Error('League ID is required');
|
||||
}
|
||||
|
||||
// Find league
|
||||
const league = await this.leagueRepository.findById(query.leagueId);
|
||||
if (!league) {
|
||||
throw new Error(`League with id ${query.leagueId} not found`);
|
||||
}
|
||||
|
||||
// Get league members (simplified - in real implementation would get from membership repository)
|
||||
const members = await this.leagueRepository.getLeagueMembers(query.leagueId);
|
||||
|
||||
// Get pending requests (simplified)
|
||||
const pendingRequests = await this.leagueRepository.getPendingRequests(query.leagueId);
|
||||
|
||||
// Calculate stats
|
||||
const adminCount = members.filter(m => m.role === 'owner' || m.role === 'admin').length;
|
||||
const driverCount = members.filter(m => m.role === 'member').length;
|
||||
|
||||
// Emit event
|
||||
const event: LeagueRosterAccessedEvent = {
|
||||
type: 'LeagueRosterAccessedEvent',
|
||||
leagueId: query.leagueId,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
await this.eventPublisher.emitLeagueRosterAccessed(event);
|
||||
|
||||
return {
|
||||
leagueId: query.leagueId,
|
||||
members: members.map(m => ({
|
||||
driverId: m.driverId,
|
||||
name: m.name,
|
||||
role: m.role,
|
||||
joinDate: m.joinDate,
|
||||
})),
|
||||
pendingRequests: pendingRequests.map(r => ({
|
||||
requestId: r.id,
|
||||
driverId: r.driverId,
|
||||
name: r.name,
|
||||
requestDate: r.requestDate,
|
||||
})),
|
||||
stats: {
|
||||
adminCount,
|
||||
driverCount,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
26
core/leagues/application/use-cases/JoinLeagueUseCase.ts
Normal file
26
core/leagues/application/use-cases/JoinLeagueUseCase.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { JoinLeagueCommand } from '../ports/JoinLeagueCommand';
|
||||
|
||||
export class JoinLeagueUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: JoinLeagueCommand): Promise<void> {
|
||||
// TODO: Implement join league logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the driver exists
|
||||
// 3. Check if the driver is already a member
|
||||
// 4. Check if the league is full
|
||||
// 5. Check if approval is required
|
||||
// 6. Add the driver to the league (or create a pending request)
|
||||
// 7. Emit appropriate events
|
||||
throw new Error('JoinLeagueUseCase not implemented');
|
||||
}
|
||||
}
|
||||
24
core/leagues/application/use-cases/LeaveLeagueUseCase.ts
Normal file
24
core/leagues/application/use-cases/LeaveLeagueUseCase.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { LeaveLeagueCommand } from '../ports/LeaveLeagueCommand';
|
||||
|
||||
export class LeaveLeagueUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: LeaveLeagueCommand): Promise<void> {
|
||||
// TODO: Implement leave league logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the driver exists
|
||||
// 3. Check if the driver is a member of the league
|
||||
// 4. Remove the driver from the league
|
||||
// 5. Emit appropriate events
|
||||
throw new Error('LeaveLeagueUseCase not implemented');
|
||||
}
|
||||
}
|
||||
24
core/leagues/application/use-cases/PromoteMemberUseCase.ts
Normal file
24
core/leagues/application/use-cases/PromoteMemberUseCase.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { PromoteMemberCommand } from '../ports/PromoteMemberCommand';
|
||||
|
||||
export class PromoteMemberUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: PromoteMemberCommand): Promise<void> {
|
||||
// TODO: Implement promote member logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the admin has permission to promote
|
||||
// 3. Find the member to promote
|
||||
// 4. Update the member's role to admin
|
||||
// 5. Emit appropriate events
|
||||
throw new Error('PromoteMemberUseCase not implemented');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { RejectMembershipRequestCommand } from '../ports/RejectMembershipRequestCommand';
|
||||
|
||||
export class RejectMembershipRequestUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: RejectMembershipRequestCommand): Promise<void> {
|
||||
// TODO: Implement reject membership request logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the admin has permission to reject
|
||||
// 3. Find the pending request
|
||||
// 4. Remove the pending request
|
||||
// 5. Emit appropriate events
|
||||
throw new Error('RejectMembershipRequestUseCase not implemented');
|
||||
}
|
||||
}
|
||||
24
core/leagues/application/use-cases/RemoveMemberUseCase.ts
Normal file
24
core/leagues/application/use-cases/RemoveMemberUseCase.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { LeagueRepository } from '../ports/LeagueRepository';
|
||||
import { DriverRepository } from '../ports/DriverRepository';
|
||||
import { EventPublisher } from '../ports/EventPublisher';
|
||||
import { RemoveMemberCommand } from '../ports/RemoveMemberCommand';
|
||||
|
||||
export class RemoveMemberUseCase {
|
||||
constructor(
|
||||
private readonly leagueRepository: LeagueRepository,
|
||||
private readonly driverRepository: DriverRepository,
|
||||
private readonly eventPublisher: EventPublisher,
|
||||
) {}
|
||||
|
||||
async execute(command: RemoveMemberCommand): Promise<void> {
|
||||
// TODO: Implement remove member logic
|
||||
// This is a placeholder implementation
|
||||
// In a real implementation, this would:
|
||||
// 1. Validate the league exists
|
||||
// 2. Validate the admin has permission to remove
|
||||
// 3. Find the member to remove
|
||||
// 4. Remove the member from the league
|
||||
// 5. Emit appropriate events
|
||||
throw new Error('RemoveMemberUseCase not implemented');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user