Files
social-media/backend/Modules/Creators/Features/ChangeSlug.cs

99 lines
2.7 KiB
C#

using Hutopy.Infrastructure.Security;
using Hutopy.Modules.Creators.Data;
using Microsoft.EntityFrameworkCore.Storage;
namespace Hutopy.Modules.Creators.Features;
[PublicAPI]
public record ChangeSlugRequest(
Guid CreatorId,
Guid SlugReservationId);
[PublicAPI]
internal sealed class ChangeSlugRequestValidator
: Validator<ChangeSlugRequest>
{
public ChangeSlugRequestValidator()
{
RuleFor(r => r.CreatorId)
.NotNull().WithMessage("You should specify the CreatorId")
.NotEmpty().WithMessage("You should specify a valid/not empty CreatorId");
RuleFor(r => r.SlugReservationId)
.NotNull().WithMessage("You should specify the SlugReservationId")
.NotEmpty().WithMessage("You should specify a valid/not empty SlugReservationId");
}
}
[PublicAPI]
public class ChangeSlugHandler(
CreatorsDbContext context)
: Endpoint<ChangeSlugRequest>
{
public override void Configure()
{
Put("/api/creators/{CreatorId}/slug");
Options(o => o.WithTags("Creators"));
}
public override async Task HandleAsync(
ChangeSlugRequest request,
CancellationToken ct)
{
await using IDbContextTransaction transaction = await context.Database.BeginTransactionAsync(ct);
try
{
Creator creator = await context
.Creators
.SingleAsync(
c => c.Id == request.CreatorId,
ct);
if (creator.CreatedBy != User.GetUserId())
{
await SendUnauthorizedAsync(ct);
return;
}
Slugs? reservation = await context
.Slugs
.FirstOrDefaultAsync(
s => s.Id == request.SlugReservationId,
ct);
if (reservation is null)
{
await SendNotFoundAsync(ct);
return;
}
Slugs? previousReservation = await context
.Slugs
.FirstOrDefaultAsync(
s => s.UsedBy == request.CreatorId,
ct);
if (previousReservation is null)
{
await SendErrorsAsync(cancellation: ct);
return;
}
context.Remove(previousReservation);
reservation.UsedBy = creator.Id;
creator.Slug = reservation.NormalizedName;
await context.SaveChangesAsync(ct);
await transaction.CommitAsync(ct);
await SendOkAsync(ct);
}
catch
{
await transaction.RollbackAsync(ct);
}
}
}