Files
gridpilot.gg/core/identity/application/use-cases/OpenAdminVoteSessionUseCase.ts
2025-12-29 22:27:33 +01:00

145 lines
4.2 KiB
TypeScript

import { IAdminVoteSessionRepository } from '../../domain/repositories/IAdminVoteSessionRepository';
import { AdminVoteSession } from '../../domain/entities/AdminVoteSession';
import { OpenAdminVoteSessionInput, OpenAdminVoteSessionOutput } from '../dtos/AdminVoteSessionDto';
/**
* Use Case: OpenAdminVoteSessionUseCase
*
* Opens a new admin vote session for a league.
* Follows CQRS Light: command side operation.
*
* Per plans section 7.1.1
*/
export class OpenAdminVoteSessionUseCase {
constructor(
private readonly adminVoteSessionRepository: IAdminVoteSessionRepository,
) {}
async execute(input: OpenAdminVoteSessionInput): Promise<OpenAdminVoteSessionOutput> {
try {
// Validate input
const errors = this.validateInput(input);
if (errors.length > 0) {
return {
success: false,
voteSessionId: input.voteSessionId,
errors,
};
}
// Check if session already exists
const existing = await this.adminVoteSessionRepository.findById(input.voteSessionId);
if (existing) {
return {
success: false,
voteSessionId: input.voteSessionId,
errors: ['Vote session with this ID already exists'],
};
}
// Check for overlapping active sessions for this admin in this league
const activeSessions = await this.adminVoteSessionRepository.findActiveForAdmin(
input.adminId,
input.leagueId
);
const startDate = new Date(input.startDate);
const endDate = new Date(input.endDate);
for (const session of activeSessions) {
// Check for overlap
if (
(startDate >= session.startDate && startDate <= session.endDate) ||
(endDate >= session.startDate && endDate <= session.endDate) ||
(startDate <= session.startDate && endDate >= session.endDate)
) {
return {
success: false,
voteSessionId: input.voteSessionId,
errors: ['Active vote session already exists for this admin in this league with overlapping dates'],
};
}
}
// Create the vote session
const session = AdminVoteSession.create({
voteSessionId: input.voteSessionId,
leagueId: input.leagueId,
adminId: input.adminId,
startDate,
endDate,
eligibleVoters: input.eligibleVoters,
});
// Save to repository
await this.adminVoteSessionRepository.save(session);
return {
success: true,
voteSessionId: input.voteSessionId,
};
} catch (error) {
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
return {
success: false,
voteSessionId: input.voteSessionId,
errors: [`Failed to open vote session: ${errorMsg}`],
};
}
}
private validateInput(input: OpenAdminVoteSessionInput): string[] {
const errors: string[] = [];
if (!input.voteSessionId || input.voteSessionId.trim().length === 0) {
errors.push('voteSessionId is required');
}
if (!input.leagueId || input.leagueId.trim().length === 0) {
errors.push('leagueId is required');
}
if (!input.adminId || input.adminId.trim().length === 0) {
errors.push('adminId is required');
}
if (!input.startDate) {
errors.push('startDate is required');
}
if (!input.endDate) {
errors.push('endDate is required');
}
if (input.startDate && input.endDate) {
const startDate = new Date(input.startDate);
const endDate = new Date(input.endDate);
if (isNaN(startDate.getTime())) {
errors.push('startDate must be a valid date');
}
if (isNaN(endDate.getTime())) {
errors.push('endDate must be a valid date');
}
if (startDate >= endDate) {
errors.push('startDate must be before endDate');
}
}
if (!input.eligibleVoters || input.eligibleVoters.length === 0) {
errors.push('At least one eligible voter is required');
} else {
// Check for duplicates
const uniqueVoters = new Set(input.eligibleVoters);
if (uniqueVoters.size !== input.eligibleVoters.length) {
errors.push('Duplicate eligible voters are not allowed');
}
}
return errors;
}
}