✅ FASE 3 COMPLETADA: Torneos y Ligas
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
This commit is contained in:
298
backend/src/controllers/tournament.controller.ts
Normal file
298
backend/src/controllers/tournament.controller.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user