Split API into phase-specific endpoint files
This commit is contained in:
134
Endpoints/SuggestEndpoints.cs
Normal file
134
Endpoints/SuggestEndpoints.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using GameList.Contracts;
|
||||
using GameList.Data;
|
||||
using GameList.Domain;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace GameList.Endpoints;
|
||||
|
||||
public static class SuggestEndpoints
|
||||
{
|
||||
public static void MapSuggestEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
app.MapGet("/api/suggestions/mine", async (HttpContext ctx, AppDbContext db) =>
|
||||
{
|
||||
var phase = await EndpointHelpers.GetPhase(db);
|
||||
if (phase != Phase.Suggest)
|
||||
return EndpointHelpers.PhaseMismatch(Phase.Suggest, phase);
|
||||
|
||||
var player = await EndpointHelpers.GetOrCreatePlayer(ctx, db);
|
||||
var mine = await db.Suggestions.AsNoTracking()
|
||||
.Where(s => s.PlayerId == player.Id)
|
||||
.Select(s => new
|
||||
{
|
||||
s.Id,
|
||||
s.Name,
|
||||
s.Genre,
|
||||
s.Description,
|
||||
s.ScreenshotUrl,
|
||||
s.YoutubeUrl,
|
||||
s.CreatedAt
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var ordered = mine
|
||||
.OrderBy(s => s.CreatedAt)
|
||||
.Select(s => new SuggestionDto(s.Id, s.Name, s.Genre, s.Description, s.ScreenshotUrl, s.YoutubeUrl));
|
||||
|
||||
return Results.Ok(ordered);
|
||||
});
|
||||
|
||||
app.MapPost("/api/suggestions", async ([FromBody] SuggestionRequest request, HttpContext ctx, AppDbContext db) =>
|
||||
{
|
||||
var phase = await EndpointHelpers.GetPhase(db);
|
||||
if (phase != Phase.Suggest)
|
||||
return EndpointHelpers.PhaseMismatch(Phase.Suggest, phase);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Name) || request.Name.Length > 100)
|
||||
{
|
||||
return Results.BadRequest(new { error = "Name is required and must be <= 100 characters." });
|
||||
}
|
||||
|
||||
var player = await EndpointHelpers.GetOrCreatePlayer(ctx, db);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(player.DisplayName))
|
||||
{
|
||||
return Results.BadRequest(new { error = "Set a display name before submitting suggestions." });
|
||||
}
|
||||
|
||||
var existingCount = await db.Suggestions.CountAsync(s => s.PlayerId == player.Id);
|
||||
if (existingCount >= 3)
|
||||
{
|
||||
return Results.BadRequest(new { error = "You have reached the 3 suggestion limit." });
|
||||
}
|
||||
|
||||
var suggestion = new Suggestion
|
||||
{
|
||||
PlayerId = player.Id,
|
||||
Name = request.Name.Trim(),
|
||||
Genre = EndpointHelpers.TrimTo(request.Genre, 50),
|
||||
Description = EndpointHelpers.TrimTo(request.Description, 500),
|
||||
ScreenshotUrl = EndpointHelpers.TrimTo(request.ScreenshotUrl, 2048),
|
||||
YoutubeUrl = EndpointHelpers.TrimTo(request.YoutubeUrl, 2048)
|
||||
};
|
||||
|
||||
db.Suggestions.Add(suggestion);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.Created($"/api/suggestions/{suggestion.Id}", new { suggestion.Id });
|
||||
});
|
||||
|
||||
app.MapDelete("/api/suggestions/{id:int}", async (int id, HttpContext ctx, AppDbContext db) =>
|
||||
{
|
||||
var phase = await EndpointHelpers.GetPhase(db);
|
||||
if (phase != Phase.Suggest)
|
||||
return EndpointHelpers.PhaseMismatch(Phase.Suggest, phase);
|
||||
|
||||
var player = await EndpointHelpers.GetOrCreatePlayer(ctx, db);
|
||||
var suggestion = await db.Suggestions.FirstOrDefaultAsync(s => s.Id == id && s.PlayerId == player.Id);
|
||||
if (suggestion == null)
|
||||
return Results.NotFound(new { error = "Suggestion not found." });
|
||||
|
||||
db.Suggestions.Remove(suggestion);
|
||||
await db.SaveChangesAsync();
|
||||
return Results.NoContent();
|
||||
});
|
||||
|
||||
app.MapGet("/api/suggestions/all", async (AppDbContext db) =>
|
||||
{
|
||||
var phase = await EndpointHelpers.GetPhase(db);
|
||||
if (phase < Phase.Reveal)
|
||||
return EndpointHelpers.PhaseMismatch(Phase.Reveal, phase);
|
||||
|
||||
var all = await db.Suggestions.AsNoTracking()
|
||||
.Include(s => s.Player)
|
||||
.Select(s => new
|
||||
{
|
||||
s.Id,
|
||||
s.Name,
|
||||
s.Genre,
|
||||
s.Description,
|
||||
s.ScreenshotUrl,
|
||||
s.YoutubeUrl,
|
||||
Author = s.Player!.DisplayName,
|
||||
s.CreatedAt
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var ordered = all
|
||||
.OrderBy(s => s.CreatedAt)
|
||||
.Select(s => new
|
||||
{
|
||||
s.Id,
|
||||
s.Name,
|
||||
s.Genre,
|
||||
s.Description,
|
||||
s.ScreenshotUrl,
|
||||
s.YoutubeUrl,
|
||||
s.Author
|
||||
});
|
||||
|
||||
return Results.Ok(ordered);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user