Add OpenAPI contract and generated frontend client
This commit is contained in:
@@ -9,36 +9,36 @@ public static class AdminEndpoints
|
||||
{
|
||||
public static void MapAdminEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var admin = app.MapGroup("/api/admin").RequireAuthorization().RequireRateLimiting("admin-sensitive").AddEndpointFilter<AdminOnlyFilter>();
|
||||
var admin = app.MapGroup("/api/admin").WithTags("Admin").RequireAuthorization().RequireRateLimiting("admin-sensitive").AddEndpointFilter<AdminOnlyFilter>();
|
||||
|
||||
admin.MapPost("/results", async ([FromBody] ResultsOpenRequest request, AdminWorkflowService service) =>
|
||||
{
|
||||
var result = await service.SetResultsOpenAsync(request.ResultsOpen);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("SetResultsOpen");
|
||||
|
||||
admin.MapGet("/vote-status", async (AdminWorkflowService service) =>
|
||||
{
|
||||
var result = await service.GetVoteStatusAsync();
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GetVoteStatus");
|
||||
|
||||
admin.MapPost("/joker", async ([FromBody] GrantJokerRequest request, AdminWorkflowService service) =>
|
||||
{
|
||||
var result = await service.GrantJokerAsync(request.PlayerId);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GrantJoker");
|
||||
|
||||
admin.MapPost("/player-phase", async ([FromBody] SetPlayerPhaseRequest request, AdminWorkflowService service) =>
|
||||
{
|
||||
var result = await service.SetPlayerPhaseAsync(request.PlayerId, request.Phase);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("SetPlayerPhase");
|
||||
admin.MapPost("/player-admin", async ([FromBody] SetPlayerAdminRequest request, AdminWorkflowService service) =>
|
||||
{
|
||||
var result = await service.SetPlayerAdminAsync(request.PlayerId, request.IsAdmin);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("SetPlayerAdmin");
|
||||
|
||||
admin.MapDelete("/players/{playerId:guid}", async (Guid playerId, [FromBody] AdminPasswordRequest request, HttpContext ctx, AppDbContext db, AdminWorkflowService service) =>
|
||||
{
|
||||
@@ -48,7 +48,7 @@ public static class AdminEndpoints
|
||||
|
||||
var result = await service.DeletePlayerAsync(playerId, player.Id, request.Password, ctx);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("DeletePlayer");
|
||||
|
||||
admin.MapPost("/link-suggestions", async ([FromBody] LinkSuggestionsRequest request, HttpContext ctx, AppDbContext db, AdminWorkflowService service) =>
|
||||
{
|
||||
@@ -58,7 +58,7 @@ public static class AdminEndpoints
|
||||
|
||||
var result = await service.LinkSuggestionsAsync(player.Id, request.SourceSuggestionId, request.TargetSuggestionId);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("LinkSuggestions");
|
||||
|
||||
admin.MapPost("/unlink-suggestions", async ([FromBody] UnlinkSuggestionsRequest request, HttpContext ctx, AppDbContext db, AdminWorkflowService service) =>
|
||||
{
|
||||
@@ -68,7 +68,7 @@ public static class AdminEndpoints
|
||||
|
||||
var result = await service.UnlinkSuggestionsAsync(player.Id, request.SuggestionId);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("UnlinkSuggestions");
|
||||
|
||||
admin.MapPost("/reset", async ([FromBody] AdminPasswordRequest request, HttpContext ctx, AppDbContext db, AdminWorkflowService service) =>
|
||||
{
|
||||
@@ -78,7 +78,7 @@ public static class AdminEndpoints
|
||||
|
||||
var result = await service.ResetAsync(player.Id, request.Password, ctx);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("Reset");
|
||||
|
||||
admin.MapPost("/factory-reset", async ([FromBody] AdminPasswordRequest request, HttpContext ctx, AppDbContext db, AdminWorkflowService service) =>
|
||||
{
|
||||
@@ -88,7 +88,7 @@ public static class AdminEndpoints
|
||||
|
||||
var result = await service.FactoryResetAsync(player.Id, request.Password, ctx);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("FactoryReset");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ public static class AuthEndpoints
|
||||
{
|
||||
public static void MapAuthEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api/auth").RequireRateLimiting("auth-sensitive");
|
||||
var group = app.MapGroup("/api/auth").WithTags("Auth").RequireRateLimiting("auth-sensitive");
|
||||
|
||||
group.MapGet("/options", async (AppDbContext db) =>
|
||||
{
|
||||
var ownerExists = await db.Players.AsNoTracking().AnyAsync(p => p.IsOwner);
|
||||
return Results.Ok(new AuthOptionsResponse(ownerExists));
|
||||
});
|
||||
}).WithName("GetAuthOptions");
|
||||
|
||||
group.MapPost("/register", async ([FromBody] RegisterRequest request, HttpContext ctx, AppDbContext db, IConfiguration config, AuthAttemptMonitor authAttemptMonitor) =>
|
||||
{
|
||||
@@ -94,7 +94,7 @@ public static class AuthEndpoints
|
||||
player.DisplayName,
|
||||
player.IsAdmin
|
||||
));
|
||||
});
|
||||
}).WithName("Register");
|
||||
|
||||
group.MapPost("/login", async ([FromBody] LoginRequest request, HttpContext ctx, AppDbContext db, AuthAttemptMonitor authAttemptMonitor) =>
|
||||
{
|
||||
@@ -137,13 +137,13 @@ public static class AuthEndpoints
|
||||
player.DisplayName,
|
||||
player.IsAdmin
|
||||
));
|
||||
});
|
||||
}).WithName("Login");
|
||||
|
||||
group.MapPost("/logout", async (HttpContext ctx) =>
|
||||
{
|
||||
await PlayerIdentityExtensions.SignOutPlayerAsync(ctx);
|
||||
return Results.NoContent();
|
||||
});
|
||||
}).WithName("Logout");
|
||||
}
|
||||
|
||||
private static string NormalizeActor(string? username) => string.IsNullOrWhiteSpace(username) ? "(missing)" : username.Trim();
|
||||
|
||||
@@ -9,6 +9,7 @@ public static class ResultsEndpoints
|
||||
public static void MapResultsEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api/results")
|
||||
.WithTags("Results")
|
||||
.RequireAuthorization()
|
||||
.AddEndpointFilter(new PhaseRequirementFilter(Phase.Results));
|
||||
|
||||
@@ -20,7 +21,7 @@ public static class ResultsEndpoints
|
||||
|
||||
var result = await service.GetResultsAsync(player.Id);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GetResults");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ public static class StateEndpoints
|
||||
{
|
||||
public static void MapStateEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api").RequireAuthorization();
|
||||
var group = app.MapGroup("/api").WithTags("State").RequireAuthorization();
|
||||
|
||||
group.MapGet("/state", async (HttpContext ctx, AppDbContext db, StateWorkflowService service, StateChangeNotifier notifier) =>
|
||||
{
|
||||
@@ -28,7 +28,7 @@ public static class StateEndpoints
|
||||
ctx.Response.Headers.ETag = notifier.CurrentEtag;
|
||||
return Results.Ok(payload);
|
||||
});
|
||||
});
|
||||
}).WithName("GetState");
|
||||
|
||||
group.MapGet("/events/state", async (HttpContext ctx, AppDbContext db, StateChangeNotifier notifier) =>
|
||||
{
|
||||
@@ -73,7 +73,7 @@ public static class StateEndpoints
|
||||
}
|
||||
|
||||
return Results.Empty;
|
||||
});
|
||||
}).WithName("GetStateEvents");
|
||||
|
||||
group.MapGet("/me", async (HttpContext ctx, AppDbContext db, StateWorkflowService service) =>
|
||||
{
|
||||
@@ -83,7 +83,7 @@ public static class StateEndpoints
|
||||
|
||||
var result = await service.GetMeAsync(player);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GetMe");
|
||||
|
||||
group.MapPost("/me/phase/next", async (HttpContext ctx, AppDbContext db, StateWorkflowService service) =>
|
||||
{
|
||||
@@ -93,7 +93,7 @@ public static class StateEndpoints
|
||||
|
||||
var result = await service.NextPhaseAsync(player);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("NextPhase");
|
||||
|
||||
group.MapPost("/me/phase/prev", async (HttpContext ctx, AppDbContext db, StateWorkflowService service) =>
|
||||
{
|
||||
@@ -103,7 +103,7 @@ public static class StateEndpoints
|
||||
|
||||
var result = await service.PrevPhaseAsync(player);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("PrevPhase");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ public static class SuggestEndpoints
|
||||
{
|
||||
public static void MapSuggestEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api/suggestions").RequireAuthorization();
|
||||
var group = app.MapGroup("/api/suggestions").WithTags("Suggestions").RequireAuthorization();
|
||||
|
||||
group.MapGet("/mine", async (HttpContext ctx, AppDbContext db, SuggestionWorkflowService service) =>
|
||||
{
|
||||
@@ -19,7 +19,7 @@ public static class SuggestEndpoints
|
||||
|
||||
var result = await service.GetMineAsync(player.Id);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GetMySuggestions");
|
||||
|
||||
group.MapPost("/", async ([FromBody] SuggestionRequest request, HttpContext ctx, AppDbContext db, SuggestionWorkflowService service) =>
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public static class SuggestEndpoints
|
||||
);
|
||||
|
||||
return result.ToHttpResult(payload => Results.Created($"/api/suggestions/{payload.Id}", payload));
|
||||
}).AddEndpointFilter(new PhaseOrJokerFilter());
|
||||
}).AddEndpointFilter(new PhaseOrJokerFilter()).WithName("CreateSuggestion");
|
||||
|
||||
group.MapDelete("/{id:int}", async (int id, HttpContext ctx, AppDbContext db, SuggestionWorkflowService service) =>
|
||||
{
|
||||
@@ -52,7 +52,7 @@ public static class SuggestEndpoints
|
||||
|
||||
var result = await service.DeleteAsync(player.Id, id);
|
||||
return result.ToHttpResult(Results.NoContent);
|
||||
});
|
||||
}).WithName("DeleteSuggestion");
|
||||
|
||||
group.MapPut("/{id:int}", async (int id, [FromBody] SuggestionRequest request, HttpContext ctx, AppDbContext db, SuggestionWorkflowService service) =>
|
||||
{
|
||||
@@ -76,7 +76,7 @@ public static class SuggestEndpoints
|
||||
);
|
||||
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("UpdateSuggestion");
|
||||
|
||||
group.MapGet("/all", async (HttpContext ctx, AppDbContext db, SuggestionWorkflowService service) =>
|
||||
{
|
||||
@@ -86,7 +86,7 @@ public static class SuggestEndpoints
|
||||
|
||||
var result = await service.GetAllAsync(player.Id);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GetAllSuggestions");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ public static class VoteEndpoints
|
||||
{
|
||||
public static void MapVoteEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api/votes").RequireAuthorization().AddEndpointFilter(new PhaseRequirementFilter(Phase.Vote));
|
||||
var group = app.MapGroup("/api/votes").WithTags("Votes").RequireAuthorization().AddEndpointFilter(new PhaseRequirementFilter(Phase.Vote));
|
||||
|
||||
group.MapGet("/mine", async (HttpContext ctx, AppDbContext db, VoteWorkflowService service) =>
|
||||
{
|
||||
@@ -19,7 +19,7 @@ public static class VoteEndpoints
|
||||
|
||||
var result = await service.GetMineAsync(player.Id);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("GetMyVotes");
|
||||
|
||||
group.MapPost("/", async (VoteRequest request, HttpContext ctx, AppDbContext db, VoteWorkflowService service) =>
|
||||
{
|
||||
@@ -29,7 +29,7 @@ public static class VoteEndpoints
|
||||
|
||||
var result = await service.UpsertAsync(player.Id, request.SuggestionId, request.Score);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("UpsertVote");
|
||||
|
||||
group.MapPost("/finalize", async (VoteFinalizeRequest request, HttpContext ctx, AppDbContext db, VoteWorkflowService service) =>
|
||||
{
|
||||
@@ -39,7 +39,7 @@ public static class VoteEndpoints
|
||||
|
||||
var result = await service.SetFinalizeAsync(player.Id, request.Final);
|
||||
return result.ToHttpResult(Results.Ok);
|
||||
});
|
||||
}).WithName("SetVotesFinalized");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user