Transit
This commit is contained in:
95
backend/src/Web/Features/Contents/Handlers/ReserveSlug.cs
Normal file
95
backend/src/Web/Features/Contents/Handlers/ReserveSlug.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Net;
|
||||
using FluentValidation.Results;
|
||||
using Hutopy.Web.Common.Security;
|
||||
using Hutopy.Web.Features.Contents.Data;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Npgsql;
|
||||
|
||||
namespace Hutopy.Web.Features.Contents.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record ReserveSlugRequest
|
||||
{
|
||||
public string Slug { get; set; } = null!;
|
||||
public required Guid ReservationId { get; set; }
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class ReserveSlugRequestValidator : Validator<ReserveSlugRequest>
|
||||
{
|
||||
public ReserveSlugRequestValidator()
|
||||
{
|
||||
RuleFor(r => r.Slug)
|
||||
.NotEmpty()
|
||||
.NotNull()
|
||||
.WithMessage("You should specify a valid Slug");
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class ReserveSlug(
|
||||
ContentDbContext context,
|
||||
IOptions<ContentOptions> opts)
|
||||
: Endpoint<ReserveSlugRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/api/creators/@{Slug}/reserve");
|
||||
Options(o => o.WithTags("Contents"));
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
ReserveSlugRequest req,
|
||||
CancellationToken ct)
|
||||
{
|
||||
await using var transaction = await context.Database.BeginTransactionAsync(ct);
|
||||
|
||||
try
|
||||
{
|
||||
await context.Slugs.AddAsync(
|
||||
new Slugs
|
||||
{
|
||||
Id = req.ReservationId,
|
||||
Active = false,
|
||||
Name = req.Slug,
|
||||
ReservedUntil = DateTimeOffset.UtcNow + opts.Value.SlugReservationDuration,
|
||||
CreatedBy = User.GetUserId(),
|
||||
},
|
||||
cancellationToken: ct);
|
||||
|
||||
await context.SaveChangesAsync(ct);
|
||||
|
||||
await transaction.CommitAsync(ct);
|
||||
|
||||
await SendOkAsync(new { Message = "Slug reserved." }, ct);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync(ct);
|
||||
|
||||
Logger.LogError("Transaction failed: {Message}", e.Message);
|
||||
|
||||
if (e.InnerException is PostgresException innerException)
|
||||
{
|
||||
if (innerException.ConstraintName == "IX_Slugs_NormalizedName")
|
||||
{
|
||||
await SendResultAsync(new ProblemDetails(
|
||||
[
|
||||
new ValidationFailure(nameof(Slugs.Name),
|
||||
"The name is already taken.")
|
||||
],
|
||||
(int)HttpStatusCode.Conflict));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendResultAsync(new ProblemDetails(
|
||||
[
|
||||
new ValidationFailure(nameof(Slugs.Name),
|
||||
e.Message)
|
||||
],
|
||||
(int)HttpStatusCode.Conflict));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user