Replace chapter setting with multi-select locations; add chapter character summary
Chapters now carry many Locations (new Tags-style entity with cross-referencing) instead of a single free-text Setting field, with a Locations tab on the novel for browsing them and seeing every chapter set at each one. Also surfaces the distinct characters appearing in a chapter's beats, linked, under the beat/word count on the outline tab.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
using Novelly.Api.Common;
|
||||
using Novelly.Api.Common.Validation;
|
||||
|
||||
namespace Novelly.Api.Locations;
|
||||
|
||||
public static class LocationEndpoints
|
||||
{
|
||||
public static IEndpointRouteBuilder MapLocationEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var novelScoped = app.MapGroup("/api/novels/{novelId:guid}/locations").WithTags("Locations")
|
||||
.AddEndpointFilter<RequestLoggingEndpointFilter>()
|
||||
.AddEndpointFilter<ValidationEndpointFilter>();
|
||||
|
||||
novelScoped.MapGet("/", async (Guid novelId, LocationService service, CancellationToken ct) =>
|
||||
Results.Ok(await service.ListAsync(novelId, ct)))
|
||||
.WithSummary("List a novel's locations with usage counts.");
|
||||
|
||||
novelScoped.MapPost("/", async (
|
||||
Guid novelId, CreateLocationRequest request, LocationService service, CancellationToken ct) =>
|
||||
{
|
||||
var location = await service.CreateAsync(novelId, request, ct);
|
||||
if (location is null)
|
||||
{
|
||||
return Results.NotFound();
|
||||
}
|
||||
|
||||
var created = location.ToResponse();
|
||||
return Results.Created($"/api/locations/{created.Id}", created);
|
||||
})
|
||||
.WithSummary("Create a location. Locations are also created on demand when applied by name.");
|
||||
|
||||
var locations = app.MapGroup("/api/locations").WithTags("Locations")
|
||||
.AddEndpointFilter<RequestLoggingEndpointFilter>()
|
||||
.AddEndpointFilter<ValidationEndpointFilter>();
|
||||
|
||||
locations.MapGet("/{id:guid}/references", async (Guid id, LocationService service, CancellationToken ct) =>
|
||||
(await service.GetReferencesAsync(id, ct))?.ToReferencesResponse().ToApiResult())
|
||||
.WithSummary("Cross-reference: every chapter set at this location.");
|
||||
|
||||
locations.MapPatch("/{id:guid}", async (
|
||||
Guid id, UpdateLocationRequest request, LocationService service, CancellationToken ct) =>
|
||||
(await service.UpdateAsync(id, request, ct))?.ToResponse().ToApiResult())
|
||||
.WithSummary("Rename a location.");
|
||||
|
||||
locations.MapDelete("/{id:guid}", async (Guid id, LocationService service, CancellationToken ct) =>
|
||||
await service.DeleteAsync(id, ct) ? Results.NoContent() : Results.NotFound())
|
||||
.WithSummary("Delete a location. Whatever carried it is left alone.");
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user