diff --git a/Contracts/Dtos.cs b/Contracts/Dtos.cs index 995be2e..d9baa5f 100644 --- a/Contracts/Dtos.cs +++ b/Contracts/Dtos.cs @@ -19,5 +19,3 @@ public record LinkSuggestionsRequest(int SourceSuggestionId, int TargetSuggestio public record UnlinkSuggestionsRequest(int SuggestionId); public record GrantJokerRequest(Guid PlayerId); - -public record DeletePlayerRequest(Guid PlayerId); diff --git a/Endpoints/SuggestEndpoints.cs b/Endpoints/SuggestEndpoints.cs index 3f343e1..d992299 100644 --- a/Endpoints/SuggestEndpoints.cs +++ b/Endpoints/SuggestEndpoints.cs @@ -42,28 +42,9 @@ public static class SuggestEndpoints group.MapPost("/", async ([FromBody] SuggestionRequest request, HttpContext ctx, AppDbContext db, IHttpClientFactory http) => { - if (string.IsNullOrWhiteSpace(request.Name) || request.Name.Length > 100) - { - return Results.BadRequest(new { error = "Name is required and must be <= 100 characters." }); - } - - if (!EndpointHelpers.IsValidImageUrl(request.ScreenshotUrl)) - { - return Results.BadRequest(new { error = "Screenshot URL must be http(s) and end with an image file extension." }); - } - - if (!await EndpointHelpers.IsReachableImageAsync(request.ScreenshotUrl, http)) - { - return Results.BadRequest(new { error = "Screenshot URL could not be validated as an image. Use a public image link (http/https, no redirects, max 5 MB)." }); - } - - if (!EndpointHelpers.IsValidHttpUrl(request.GameUrl)) - return Results.BadRequest(new { error = "Game URL must be http or https." }); - if (!EndpointHelpers.IsValidHttpUrl(request.YoutubeUrl)) - return Results.BadRequest(new { error = "YouTube URL must be http or https." }); - - if (!ValidatePlayers(request.MinPlayers, request.MaxPlayers, out var playersError)) - return Results.BadRequest(new { error = playersError }); + var validationError = await SuggestionValidator.ValidateAsync(request, http); + if (validationError is not null) + return Results.BadRequest(new { error = validationError }); var player = await EndpointHelpers.GetAuthenticatedPlayer(ctx, db); if (player is null) @@ -149,28 +130,9 @@ public static class SuggestEndpoints if (!isAdmin && player is null) return Results.Unauthorized(); - if (string.IsNullOrWhiteSpace(request.Name) || request.Name.Length > 100) - { - return Results.BadRequest(new { error = "Name is required and must be <= 100 characters." }); - } - - if (!EndpointHelpers.IsValidImageUrl(request.ScreenshotUrl)) - { - return Results.BadRequest(new { error = "Screenshot URL must be http(s) and end with an image file extension." }); - } - - if (!await EndpointHelpers.IsReachableImageAsync(request.ScreenshotUrl, http)) - { - return Results.BadRequest(new { error = "Screenshot URL could not be validated as an image. Use a public image link (http/https, no redirects, max 5 MB)." }); - } - - if (!EndpointHelpers.IsValidHttpUrl(request.GameUrl)) - return Results.BadRequest(new { error = "Game URL must be http or https." }); - if (!EndpointHelpers.IsValidHttpUrl(request.YoutubeUrl)) - return Results.BadRequest(new { error = "YouTube URL must be http or https." }); - - if (!ValidatePlayers(request.MinPlayers, request.MaxPlayers, out var playersError)) - return Results.BadRequest(new { error = playersError }); + var validationError = await SuggestionValidator.ValidateAsync(request, http); + if (validationError is not null) + return Results.BadRequest(new { error = validationError }); var suggestion = await db.Suggestions.FirstOrDefaultAsync(s => s.Id == id); if (suggestion == null) @@ -294,38 +256,5 @@ public static class SuggestEndpoints return Results.Ok(ordered); }); } - - private static bool ValidatePlayers(int? minPlayers, int? maxPlayers, out string? error) - { - error = null; - if (minPlayers is null && maxPlayers is null) - return true; - - if (minPlayers is < 1 or > 32) - { - error = "Min players must be between 1 and 32."; - return false; - } - - if (maxPlayers is < 1 or > 32) - { - error = "Max players must be between 1 and 32."; - return false; - } - - if (minPlayers is null || maxPlayers is null) - { - error = "Provide both min and max players."; - return false; - } - - if (minPlayers > maxPlayers) - { - error = "Min players cannot exceed max players."; - return false; - } - - return true; - } } diff --git a/Endpoints/SuggestionValidator.cs b/Endpoints/SuggestionValidator.cs new file mode 100644 index 0000000..e998503 --- /dev/null +++ b/Endpoints/SuggestionValidator.cs @@ -0,0 +1,46 @@ +using GameList.Contracts; + +namespace GameList.Endpoints; + +internal static class SuggestionValidator +{ + public static async Task ValidateAsync(SuggestionRequest request, IHttpClientFactory httpFactory) + { + if (string.IsNullOrWhiteSpace(request.Name) || request.Name.Length > 100) + return "Name is required and must be <= 100 characters."; + + if (!EndpointHelpers.IsValidImageUrl(request.ScreenshotUrl)) + return "Screenshot URL must be http(s) and end with an image file extension."; + + if (!await EndpointHelpers.IsReachableImageAsync(request.ScreenshotUrl, httpFactory)) + return "Screenshot URL could not be validated as an image. Use a public image link (http/https, no redirects, max 5 MB)."; + + if (!EndpointHelpers.IsValidHttpUrl(request.GameUrl)) + return "Game URL must be http or https."; + + if (!EndpointHelpers.IsValidHttpUrl(request.YoutubeUrl)) + return "YouTube URL must be http or https."; + + return ValidatePlayers(request.MinPlayers, request.MaxPlayers); + } + + private static string? ValidatePlayers(int? minPlayers, int? maxPlayers) + { + if (minPlayers is null && maxPlayers is null) + return null; + + if (minPlayers is < 1 or > 32) + return "Min players must be between 1 and 32."; + + if (maxPlayers is < 1 or > 32) + return "Max players must be between 1 and 32."; + + if (minPlayers is null || maxPlayers is null) + return "Provide both min and max players."; + + if (minPlayers > maxPlayers) + return "Min players cannot exceed max players."; + + return null; + } +}