Sube carpetas API, API.Tests, Application y Domain del Backend
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
using Application.DTOs.Divisions.Request;
|
||||
using Application.Utils.Constants.Validation;
|
||||
|
||||
using Domain.Enums;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
/// <summary>
|
||||
/// One division within a CreateFullTournamentRequest; the TournamentId is implied by nesting.
|
||||
/// </summary>
|
||||
public class CreateFullDivisionRequest
|
||||
{
|
||||
[Required(ErrorMessage = "The Name field is required.")]
|
||||
[MaxLength(DivisionFieldLengths.NameMaxLength)]
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Marks a cross-division cup that draws teams from every zone.
|
||||
/// </summary>
|
||||
public bool IsCrossDivisionCup { get; set; } = false;
|
||||
|
||||
[Range(0, int.MaxValue, ErrorMessage = "PointsForWin cannot be negative.")]
|
||||
public int PointsForWin { get; set; } = 2;
|
||||
|
||||
[Range(0, int.MaxValue, ErrorMessage = "PointsForLoss cannot be negative.")]
|
||||
public int PointsForLoss { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How many teams qualify from each internal group of a multi-group cross-division cup; defaults to 1.
|
||||
/// </summary>
|
||||
[Range(1, int.MaxValue, ErrorMessage = "QualifiersPerGroup must be at least 1.")]
|
||||
public int QualifiersPerGroup { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Competitive category of the division; a mismatch with the parent tournament aborts the whole create.
|
||||
/// </summary>
|
||||
public TournamentCategory Category { get; set; } = TournamentCategory.Masculine;
|
||||
|
||||
/// <summary>
|
||||
/// Optional position-range to playoff-destination mappings.
|
||||
/// </summary>
|
||||
public List<PlayoffMappingRequest>? PlayoffMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The stages, group and cup elimination rounds alike, to create in this division.
|
||||
/// </summary>
|
||||
public List<CreateFullStageRequest> Stages { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Application.Utils.Constants.Stage;
|
||||
|
||||
using Domain.Enums;
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
/// <summary>
|
||||
/// One stage within a CreateFullDivisionRequest, mirroring CreateStageRequest minus the DivisionId.
|
||||
/// </summary>
|
||||
public class CreateFullStageRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Stage name field is required.")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[AllowedValues(StageType.Group, StageType.RoundOf16, StageType.QuarterFinal, StageType.SemiFinal, StageType.ThirdPlace, StageType.Final)]
|
||||
public required StageType StageType { get; set; } = StageType.Group;
|
||||
|
||||
/// <summary>
|
||||
/// Defaults to true when null.
|
||||
/// </summary>
|
||||
public bool? IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defaults to true for non-Group stage types when null.
|
||||
/// </summary>
|
||||
public bool? IsElimination { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Start date field is required.")]
|
||||
public required DateTime StartDate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "End date field is required.")]
|
||||
public required DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Groups parallel elimination brackets under a cup name.
|
||||
/// </summary>
|
||||
public string? BracketName { get; set; }
|
||||
|
||||
[AllowedValues(1, 3, 5, 7)]
|
||||
public int BestOf { get; set; } = 1;
|
||||
|
||||
[Range(RoundRobinFormat.MinLegs, RoundRobinFormat.MaxLegs)]
|
||||
public int RoundRobinLegs { get; set; } = RoundRobinFormat.MinLegs;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Domain.Enums;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
/// <summary>
|
||||
/// The whole tournament-wizard payload, persisted atomically so a failure leaves no partial tournament behind.
|
||||
/// </summary>
|
||||
public class CreateFullTournamentRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional; neither the create wizard nor the edit form require it.
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Name is required.")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Team registration deadline is required.")]
|
||||
public required DateTime TeamRegistrationDeadline { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Start date is required.")]
|
||||
public required DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Competitive category of the tournament; every division below must share this category.
|
||||
/// </summary>
|
||||
public TournamentCategory Category { get; set; } = TournamentCategory.Masculine;
|
||||
|
||||
/// <summary>
|
||||
/// Optional id of the season this tournament belongs to; omitting it leaves the tournament ungrouped.
|
||||
/// </summary>
|
||||
public Guid? SeasonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The divisions to create under this tournament, each with its own stages and playoff mappings.
|
||||
/// </summary>
|
||||
public List<CreateFullDivisionRequest> Divisions { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Domain.Enums;
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to create a new tournament.
|
||||
/// </summary>
|
||||
public class CreateTournamentRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The description of the tournament. Optional.
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Name is required.")]
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The deadline for team registrations; must be earlier than the tournament start date.
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Team registration deadline is required.")]
|
||||
public required DateTime TeamRegistrationDeadline { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Start date is required.")]
|
||||
public required DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Competitive category of the tournament; feminine and masculine competitions are separate tournaments.
|
||||
/// </summary>
|
||||
public TournamentCategory Category { get; set; } = TournamentCategory.Masculine;
|
||||
|
||||
/// <summary>
|
||||
/// Optional id of the season this tournament belongs to; omitting it leaves the tournament ungrouped.
|
||||
/// </summary>
|
||||
public Guid? SeasonId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
/// <summary>
|
||||
/// Payload for enrolling a single team into a tournament's registration phase.
|
||||
/// </summary>
|
||||
public class EnrollTeamRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The existing team to enroll; mutually exclusive with NewTeamName.
|
||||
/// </summary>
|
||||
public Guid? ExistingTeamId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of a brand-new team to create and enroll; mutually exclusive with ExistingTeamId.
|
||||
/// </summary>
|
||||
public string? NewTeamName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional source season whose roster is copied in; only allowed together with ExistingTeamId.
|
||||
/// </summary>
|
||||
public Guid? CopyRosterFromTournamentId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Application.DTOs.Abstract.Request;
|
||||
|
||||
using Domain.Enums;
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request to get filtered tournaments.
|
||||
/// </summary>
|
||||
public class GetTournamentsFilteredRequest : PaginatedFilterRequest
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public TournamentStatus? Status { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Domain.Enums;
|
||||
|
||||
namespace Application.DTOs.Tournament.Request;
|
||||
|
||||
public class UpdateTournamentRequest : CreateTournamentRequest
|
||||
{
|
||||
public TournamentStatus? Status { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Application.DTOs.Tournament.Response;
|
||||
|
||||
/// <summary>
|
||||
/// One completability violation, with every field except Code optional and populated only where relevant.
|
||||
/// </summary>
|
||||
public class CompletabilityIssue
|
||||
{
|
||||
/// <summary>
|
||||
/// The violated rule's stable code, one of the constants in CompletabilityIssueCodes.
|
||||
/// </summary>
|
||||
public required string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The offending division or zone name, when the rule is about a division.
|
||||
/// </summary>
|
||||
public string? DivisionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The offending team name, when the rule is about a team.
|
||||
/// </summary>
|
||||
public string? TeamName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The playoff range's first position, for PlayoffRangeExceedsTeams.
|
||||
/// </summary>
|
||||
public int? FromPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of teams assigned to the offending division or group, for the count-based rules.
|
||||
/// </summary>
|
||||
public int? AssignedTeams { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The offending team's habilitado player count, not its raw roster size, for TeamTooFewPlayers.
|
||||
/// </summary>
|
||||
public int? PlayerCount { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace Application.DTOs.Tournament.Response;
|
||||
|
||||
/// <summary>
|
||||
/// The stable, English and neutral codes for every completability violation, localized by the frontend.
|
||||
/// </summary>
|
||||
public static class CompletabilityIssueCodes
|
||||
{
|
||||
/// <summary>
|
||||
/// A regular zone has fewer than the required assigned teams.
|
||||
/// </summary>
|
||||
public const string ZoneTooFewTeams = nameof(ZoneTooFewTeams);
|
||||
|
||||
/// <summary>
|
||||
/// An enrolled team is not assigned to any regular zone.
|
||||
/// </summary>
|
||||
public const string TeamNotAssigned = nameof(TeamNotAssigned);
|
||||
|
||||
/// <summary>
|
||||
/// A team is assigned to more than one regular zone.
|
||||
/// </summary>
|
||||
public const string TeamInMultipleZones = nameof(TeamInMultipleZones);
|
||||
|
||||
/// <summary>
|
||||
/// A playoff range starts beyond the zone's assigned team count.
|
||||
/// </summary>
|
||||
public const string PlayoffRangeExceedsTeams = nameof(PlayoffRangeExceedsTeams);
|
||||
|
||||
/// <summary>
|
||||
/// A cross-division-cup group has fewer than the required assigned teams.
|
||||
/// </summary>
|
||||
public const string CrossCupGroupTooFewTeams = nameof(CrossCupGroupTooFewTeams);
|
||||
|
||||
/// <summary>
|
||||
/// An enrolled team has fewer than the required registered players.
|
||||
/// </summary>
|
||||
public const string TeamTooFewPlayers = nameof(TeamTooFewPlayers);
|
||||
|
||||
/// <summary>
|
||||
/// A regular division's sub-groups have a group below the minimum size or an imbalance across groups.
|
||||
/// </summary>
|
||||
public const string SubGroupTooFewTeams = nameof(SubGroupTooFewTeams);
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Application.DTOs.Tournament.Response;
|
||||
|
||||
/// <summary>
|
||||
/// The completability report for a tournament: whether it can be started, and the blocking issues if not.
|
||||
/// </summary>
|
||||
public class TournamentCompletabilityResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// True when the tournament has no completability issues and may be started.
|
||||
/// </summary>
|
||||
public bool CanStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Every completability violation found; empty when CanStart is true.
|
||||
/// </summary>
|
||||
public List<CompletabilityIssue> Issues { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Application.DTOs.Abstract.Response;
|
||||
using Application.DTOs.Divisions.Response;
|
||||
|
||||
using Domain.Enums;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace Application.DTOs.Tournament.Response;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the response containing details of a tournament.
|
||||
/// </summary>
|
||||
public class TournamentResponse : BaseEntityResponse
|
||||
{
|
||||
public required string Description { get; set; }
|
||||
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique, URL-friendly identifier used in public tournament links.
|
||||
/// </summary>
|
||||
public required string Slug { get; set; }
|
||||
|
||||
public required IEnumerable<MinimalDivisionResponse> Divisions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The deadline for team registrations; must be earlier than the tournament start date.
|
||||
/// </summary>
|
||||
public required DateTime TeamRegistrationDeadline { get; set; }
|
||||
|
||||
public required DateTime StartDate { get; set; }
|
||||
|
||||
public TournamentStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Competitive category of the tournament; the feminine competition is played as its own tournament.
|
||||
/// </summary>
|
||||
public TournamentCategory Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id of the season this tournament belongs to, or null when not grouped under any season.
|
||||
/// </summary>
|
||||
public Guid? SeasonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the season this tournament belongs to, when loaded; null otherwise.
|
||||
/// </summary>
|
||||
public string? SeasonName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Slug of the season this tournament belongs to, when loaded, for building a clean season link.
|
||||
/// </summary>
|
||||
public string? SeasonSlug { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Application.DTOs.Divisions.Response;
|
||||
|
||||
using Domain.Enums;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Application.DTOs.Tournament.Response;
|
||||
|
||||
/// <summary>
|
||||
/// A source tournament's pure structure tree (divisions, their stages and
|
||||
/// playoff mappings) for the tournament-cloning wizard-prefill flow (HU-cloning).
|
||||
/// Carries STRUCTURE ONLY — no rosters, matches, standings, sanctions, audit
|
||||
/// logs, or DrawnAt timestamps — so it can never leak instance data into a
|
||||
/// clone. Additive: never replaces TournamentResponse/DivisionResponse, which
|
||||
/// stay unchanged for their existing unrelated pages.
|
||||
/// </summary>
|
||||
public class TournamentStructureResponse
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source tournament's category, shown for reference only — the clone
|
||||
/// action always requires the organizer to choose the new category
|
||||
/// explicitly, never inheriting this value silently.
|
||||
/// </summary>
|
||||
public required TournamentCategory Category { get; set; }
|
||||
|
||||
public required List<DivisionStructureResponse> Divisions { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One division's cloneable structure: its scoring/cup configuration, playoff
|
||||
/// mappings, and full Stage list — everything the reverse-mapper needs to
|
||||
/// reconstruct a `ZoneConfig` or `CrossCupConfig` (D1), and nothing else.
|
||||
/// </summary>
|
||||
public class DivisionStructureResponse
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
|
||||
public bool IsCrossDivisionCup { get; set; }
|
||||
|
||||
public int PointsForWin { get; set; }
|
||||
|
||||
public int PointsForLoss { get; set; }
|
||||
|
||||
public int QualifiersPerGroup { get; set; }
|
||||
|
||||
public List<PlayoffMappingResponse> PlayoffMappings { get; set; } = [];
|
||||
|
||||
public required List<StageStructureResponse> Stages { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One stage's cloneable shape: its type, ordering, and bracket/series
|
||||
/// configuration. Carries no dates, no DrawnAt, and no match data.
|
||||
/// </summary>
|
||||
public class StageStructureResponse
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Groups parallel elimination brackets under a cup name; null for a
|
||||
/// division's default/group stage.
|
||||
/// </summary>
|
||||
public string? BracketName { get; set; }
|
||||
|
||||
public required StageType StageType { get; set; }
|
||||
|
||||
public bool IsElimination { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
public int BestOf { get; set; }
|
||||
|
||||
public int RoundRobinLegs { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user