using Novelly.Api.Common; using Novelly.Api.Common.Validation; namespace Novelly.Api.Beats; public static class BeatEndpoints { public static IEndpointRouteBuilder MapBeatEndpoints(this IEndpointRouteBuilder app) { var chapterScoped = app.MapGroup("/api/chapters/{chapterId:guid}/beats").WithTags("Beats") .AddEndpointFilter() .AddEndpointFilter(); chapterScoped.MapGet("/", async (Guid chapterId, BeatService service, CancellationToken ct) => Results.Ok((await service.ListAsync(chapterId, ct)).Select(b => b.ToResponse()))) .WithSummary("Read a chapter's outline: its beats, in order."); chapterScoped.MapPost("/", async ( Guid chapterId, CreateBeatRequest request, BeatService service, CancellationToken ct) => { var beat = await service.CreateAsync(chapterId, request, ct); if (beat is null) { return Results.NotFound(); } var created = beat.ToResponse(); return Results.Created($"/api/beats/{created.Id}", created); }) .WithSummary("Add a beat to a chapter's outline."); chapterScoped.MapPost("/reorder", async ( Guid chapterId, ReorderBeatsRequest request, BeatService service, CancellationToken ct) => (await service.ReorderAsync(chapterId, request, ct))?.Select(b => b.ToResponse()).ToList().ToApiResult()) .WithSummary("Renumber a chapter's beats to match the order given."); chapterScoped.MapPost("/assign-character", async ( Guid chapterId, AssignCharacterToBeatsRequest request, BeatService service, CancellationToken ct) => (await service.AssignCharacterAsync(chapterId, request, ct))?.Select(b => b.ToResponse()).ToList().ToApiResult()) .WithSummary("Add a character to several beats at once, leaving each beat's existing characters alone."); chapterScoped.MapPost("/move", async ( Guid chapterId, MoveBeatsRequest request, BeatService service, CancellationToken ct) => (await service.MoveAsync(chapterId, request, ct))?.Select(b => b.ToResponse()).ToList().ToApiResult()) .WithSummary("Move one or more beats to another chapter, appending them to its end."); app.MapGet("/api/characters/{characterId:guid}/beats", async ( Guid characterId, BeatService service, CancellationToken ct) => (await service.ListForCharacterAsync(characterId, ct))?.Select(b => b.ToCharacterBeatResponse(characterId)).ToList().ToApiResult()) .WithTags("Beats") .WithSummary("Every beat this character appears in, in manuscript order."); var beats = app.MapGroup("/api/beats").WithTags("Beats") .AddEndpointFilter() .AddEndpointFilter(); beats.MapGet("/{id:guid}", async (Guid id, BeatService service, CancellationToken ct) => (await service.GetAsync(id, ct))?.ToResponse().ToApiResult()) .WithSummary("Read one beat."); beats.MapPatch("/{id:guid}", async ( Guid id, UpdateBeatRequest request, BeatService service, CancellationToken ct) => (await service.UpdateAsync(id, request, ct))?.ToResponse().ToApiResult()) .WithSummary("Update a beat. Sending a tag list replaces the beat's tags."); beats.MapDelete("/{id:guid}", async (Guid id, BeatService service, CancellationToken ct) => await service.DeleteAsync(id, ct) ? Results.NoContent() : Results.NotFound()) .WithSummary("Delete a beat."); return app; } }