Files
social-media/backend/src/Web/Features/Memberships/Handlers/SendTip.cs

96 lines
2.4 KiB
C#

using Hutopy.Web.Common.Security;
using Hutopy.Web.Features.Memberships.Data;
using Hutopy.Web.Features.Memberships.Infrastructure;
namespace Hutopy.Web.Features.Memberships.Handlers;
[PublicAPI]
public record SendTipRequest(
Guid CreatorId,
decimal Amount,
string Currency,
string Message,
string CheckoutSuccessUrl,
string CheckoutCancelledUrl);
[PublicAPI]
public record SendTipResponse(
string Status,
string StripeCheckoutUrl);
[PublicAPI]
public class SendTipRequestValidator : Validator<SendTipRequest>
{
public SendTipRequestValidator()
{
RuleFor(x => x.Amount)
.GreaterThan(0)
.WithMessage("Tip amount must be greater than 0");
RuleFor(x => x.CreatorId)
.NotEmpty()
.WithMessage("Creator ID is required");
RuleFor(x => x.CheckoutSuccessUrl)
.NotEmpty()
.WithMessage("CheckoutSuccessUrl is required");
RuleFor(x => x.CheckoutCancelledUrl)
.NotEmpty()
.WithMessage("CheckoutCancelledUrl is required");
}
}
[PublicAPI]
public class SendTipHandler(
MembershipDbContext dbContext,
StripeService stripeService,
ILogger<SendTipHandler> logger)
: Endpoint<SendTipRequest, SendTipResponse>
{
public override void Configure()
{
Post("/api/tips");
Options(o => o.WithTags("Memberships"));
AllowAnonymous();
}
public override async Task HandleAsync(
SendTipRequest req,
CancellationToken ct)
{
try
{
var creator = await dbContext.Creators.FindAsync(
[req.CreatorId],
cancellationToken: ct);
if (creator == null)
{
await SendNotFoundAsync(ct);
return;
}
var checkoutSession = await stripeService.CreateTipCheckoutSessionAsync(
creator.Id,
creator.Name,
req.Amount,
req.Currency,
req.Message,
creator.StripeAccountId!,
req.CheckoutSuccessUrl,
req.CheckoutCancelledUrl,
ct);
await SendAsync(
new SendTipResponse("Pending", checkoutSession.Url),
cancellation: ct);
}
catch (Exception e)
{
logger.LogError(e.Message);
}
}
}