Implementados 3 módulos con agent swarm: 1. SISTEMA DE TORNEOS - Tipos: Eliminación, Round Robin, Suizo, Consolación - Categorías: Masculina, Femenina, Mixta - Inscripciones con validación de niveles - Gestión de pagos y estados 2. CUADROS Y PARTIDOS - Generación automática de cuadros - Algoritmos: Circle method (Round Robin), Swiss pairing - Avance automático de ganadores - Asignación de canchas y horarios - Registro y confirmación de resultados 3. LIGAS POR EQUIPOS - Creación de equipos con capitán - Calendario round-robin automático - Tabla de clasificación con desempates - Estadísticas por equipo Modelos DB: - Tournament, TournamentParticipant, TournamentMatch - League, LeagueTeam, LeagueTeamMember, LeagueMatch, LeagueStanding Nuevos endpoints: - /tournaments/* - Gestión de torneos - /tournaments/:id/draw/* - Cuadros - /tournaments/:id/matches/* - Partidos de torneo - /leagues/* - Ligas - /league-teams/* - Equipos - /league-schedule/* - Calendario - /league-standings/* - Clasificación - /league-matches/* - Partidos de liga Datos de prueba: - Torneo de Verano 2024 (Eliminatoria) - Liga de Invierno (Round Robin) - Liga de Club 2024
299 lines
7.3 KiB
TypeScript
299 lines
7.3 KiB
TypeScript
import { Request, Response, NextFunction } from 'express';
|
|
import { TournamentService } from '../services/tournament.service';
|
|
import { ApiError } from '../middleware/errorHandler';
|
|
import { UserRole } from '../utils/constants';
|
|
|
|
export class TournamentController {
|
|
// Crear un torneo
|
|
static async create(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const {
|
|
name,
|
|
description,
|
|
type,
|
|
category,
|
|
allowedLevels,
|
|
maxParticipants,
|
|
registrationStartDate,
|
|
registrationEndDate,
|
|
startDate,
|
|
endDate,
|
|
courtIds,
|
|
price,
|
|
} = req.body;
|
|
|
|
const tournament = await TournamentService.createTournament(req.user.userId, {
|
|
name,
|
|
description,
|
|
type,
|
|
category,
|
|
allowedLevels,
|
|
maxParticipants,
|
|
registrationStartDate: new Date(registrationStartDate),
|
|
registrationEndDate: new Date(registrationEndDate),
|
|
startDate: new Date(startDate),
|
|
endDate: new Date(endDate),
|
|
courtIds,
|
|
price,
|
|
});
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
message: 'Torneo creado exitosamente',
|
|
data: tournament,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Obtener todos los torneos
|
|
static async getAll(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const filters = {
|
|
status: req.query.status as string,
|
|
type: req.query.type as string,
|
|
category: req.query.category as string,
|
|
upcoming: req.query.upcoming === 'true',
|
|
open: req.query.open === 'true',
|
|
};
|
|
|
|
const tournaments = await TournamentService.getTournaments(filters);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
count: tournaments.length,
|
|
data: tournaments,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Obtener un torneo por ID
|
|
static async getById(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const { id } = req.params;
|
|
const tournament = await TournamentService.getTournamentById(id);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
data: tournament,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Actualizar un torneo
|
|
static async update(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const {
|
|
name,
|
|
description,
|
|
type,
|
|
category,
|
|
allowedLevels,
|
|
maxParticipants,
|
|
registrationStartDate,
|
|
registrationEndDate,
|
|
startDate,
|
|
endDate,
|
|
courtIds,
|
|
price,
|
|
status,
|
|
} = req.body;
|
|
|
|
const updateData: any = {
|
|
name,
|
|
description,
|
|
type,
|
|
category,
|
|
allowedLevels,
|
|
maxParticipants,
|
|
courtIds,
|
|
price,
|
|
status,
|
|
};
|
|
|
|
// Convertir fechas si se proporcionan
|
|
if (registrationStartDate) {
|
|
updateData.registrationStartDate = new Date(registrationStartDate);
|
|
}
|
|
if (registrationEndDate) {
|
|
updateData.registrationEndDate = new Date(registrationEndDate);
|
|
}
|
|
if (startDate) {
|
|
updateData.startDate = new Date(startDate);
|
|
}
|
|
if (endDate) {
|
|
updateData.endDate = new Date(endDate);
|
|
}
|
|
|
|
const tournament = await TournamentService.updateTournament(
|
|
id,
|
|
req.user.userId,
|
|
updateData
|
|
);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Torneo actualizado exitosamente',
|
|
data: tournament,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Eliminar (cancelar) un torneo
|
|
static async delete(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const tournament = await TournamentService.deleteTournament(id, req.user.userId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Torneo cancelado exitosamente',
|
|
data: tournament,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Abrir inscripciones
|
|
static async openRegistration(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const tournament = await TournamentService.openRegistration(id, req.user.userId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Inscripciones abiertas exitosamente',
|
|
data: tournament,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Cerrar inscripciones
|
|
static async closeRegistration(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const tournament = await TournamentService.closeRegistration(id, req.user.userId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Inscripciones cerradas exitosamente',
|
|
data: tournament,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Inscribirse a un torneo
|
|
static async register(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const participant = await TournamentService.registerParticipant(id, req.user.userId);
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
message: 'Inscripción realizada exitosamente',
|
|
data: participant,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Desinscribirse de un torneo
|
|
static async unregister(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { id } = req.params;
|
|
const participant = await TournamentService.unregisterParticipant(id, req.user.userId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Inscripción cancelada exitosamente',
|
|
data: participant,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Confirmar pago de inscripción
|
|
static async confirmPayment(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
if (!req.user) {
|
|
throw new ApiError('No autenticado', 401);
|
|
}
|
|
|
|
const { participantId } = req.params;
|
|
const participant = await TournamentService.confirmPayment(
|
|
participantId,
|
|
req.user.userId
|
|
);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Pago confirmado exitosamente',
|
|
data: participant,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
// Obtener participantes de un torneo
|
|
static async getParticipants(req: Request, res: Response, next: NextFunction) {
|
|
try {
|
|
const { id } = req.params;
|
|
const participants = await TournamentService.getParticipants(id);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
count: participants.length,
|
|
data: participants,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
export default TournamentController;
|