Files
app-padel/backend/src/controllers/tournament.controller.ts
Ivan Alcaraz 6494e2b38b 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
2026-01-31 08:38:54 +00:00

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;