From e3d4e2e6872bc6aa22175a7723f09575dca5573d Mon Sep 17 00:00:00 2001 From: Frank Tovar Date: Thu, 5 Feb 2026 17:15:30 +0100 Subject: [PATCH] Enforce phase for suggestions with joker allowance --- Endpoints/SuggestEndpoints.cs | 5 +++-- Infrastructure/PhaseOrJokerFilter.cs | 29 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 Infrastructure/PhaseOrJokerFilter.cs diff --git a/Endpoints/SuggestEndpoints.cs b/Endpoints/SuggestEndpoints.cs index def8b21..d28db58 100644 --- a/Endpoints/SuggestEndpoints.cs +++ b/Endpoints/SuggestEndpoints.cs @@ -3,6 +3,7 @@ using GameList.Data; using GameList.Domain; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using GameList.Infrastructure; namespace GameList.Endpoints; @@ -71,7 +72,6 @@ public static class SuggestEndpoints var usingJoker = phase == Phase.Vote && player.HasJoker; if (phase != Phase.Suggest && !usingJoker) return EndpointHelpers.PhaseMismatch(Phase.Suggest, phase); - if (string.IsNullOrWhiteSpace(player.DisplayName)) { return Results.BadRequest(new { error = "Set a display name before submitting suggestions." }); @@ -107,7 +107,8 @@ public static class SuggestEndpoints await db.SaveChangesAsync(); return Results.Created($"/api/suggestions/{suggestion.Id}", new { suggestion.Id }); - }); + }) + .AddEndpointFilter(new PhaseOrJokerFilter()); group.MapDelete("/{id:int}", async (int id, HttpContext ctx, AppDbContext db) => { diff --git a/Infrastructure/PhaseOrJokerFilter.cs b/Infrastructure/PhaseOrJokerFilter.cs new file mode 100644 index 0000000..f26d0e2 --- /dev/null +++ b/Infrastructure/PhaseOrJokerFilter.cs @@ -0,0 +1,29 @@ +using GameList.Data; +using GameList.Domain; +using GameList.Endpoints; + +namespace GameList.Infrastructure; + +/// +/// Allows Suggest phase, or Vote phase when the player has a joker available. +/// Used for creating suggestions during Vote with joker. +/// +public class PhaseOrJokerFilter : IEndpointFilter +{ + public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) + { + var httpContext = context.HttpContext; + var db = httpContext.RequestServices.GetRequiredService(); + var player = await EndpointHelpers.GetAuthenticatedPlayer(httpContext, db); + if (player is null) return Results.Unauthorized(); + + var phase = await EndpointHelpers.GetPhase(db, player.Id); + var allow = phase == Phase.Suggest || (phase == Phase.Vote && player.HasJoker); + if (!allow) + { + return EndpointHelpers.PhaseMismatch(Phase.Suggest, phase); + } + + return await next(context); + } +}