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.
52 lines
2.4 KiB
C#
52 lines
2.4 KiB
C#
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;
|
|
}
|
|
}
|