many fixes and improvements - rework for modules/ and common/
feat(emailer): add Postmark and Resend providers
This commit is contained in:
116
backend/Modules/Tipping/Handlers/SendTip.cs
Normal file
116
backend/Modules/Tipping/Handlers/SendTip.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using Hutopy.Infrastructure.Security;
|
||||
using Hutopy.Modules.Creators.Contracts;
|
||||
using Hutopy.Modules.Tipping.Contracts;
|
||||
using Hutopy.Modules.Tipping.Data;
|
||||
|
||||
namespace Hutopy.Modules.Tipping.Handlers;
|
||||
|
||||
[PublicAPI]
|
||||
public record SendTipRequest(
|
||||
Guid CreatorId,
|
||||
decimal Amount,
|
||||
string Currency,
|
||||
string Message,
|
||||
string CheckoutSuccessUrl,
|
||||
string CheckoutCancelledUrl);
|
||||
|
||||
[PublicAPI]
|
||||
public record SendTipResponse(
|
||||
string Id,
|
||||
string Url);
|
||||
|
||||
[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(
|
||||
TippingDbContext dbContext,
|
||||
ITipProcessor tipProcessor,
|
||||
ICreatorLookup creatorLookup)
|
||||
: Endpoint<SendTipRequest, SendTipResponse>
|
||||
{
|
||||
private static readonly Guid AnonymousUserId = Guid.Parse("AAAAAAAA-0000-0000-0000-000000000000");
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/api/tips");
|
||||
Options(o => o.WithTags("Memberships"));
|
||||
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(
|
||||
SendTipRequest req,
|
||||
CancellationToken ct)
|
||||
{
|
||||
CreatorReference? creator = await creatorLookup.GetCreatorAsync(req.CreatorId, ct);
|
||||
if (creator == null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!creator.AcceptCharges)
|
||||
{
|
||||
await SendErrorsAsync(StatusCodes.Status400BadRequest, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
Guid tipId = Guid.CreateVersion7();
|
||||
|
||||
TipCheckoutSession checkout = await tipProcessor.CreateCheckoutSessionAsync(
|
||||
tipId,
|
||||
creator,
|
||||
req.Amount,
|
||||
req.Currency,
|
||||
req.Message,
|
||||
req.CheckoutSuccessUrl,
|
||||
req.CheckoutCancelledUrl,
|
||||
ct);
|
||||
|
||||
Guid userId = User.Identity?.IsAuthenticated == true
|
||||
? User.GetUserId()
|
||||
: AnonymousUserId;
|
||||
|
||||
Tip tip = new()
|
||||
{
|
||||
Id = tipId,
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
StripeSessionId = checkout.Id,
|
||||
CreatedBy = userId,
|
||||
CreatorId = req.CreatorId,
|
||||
Status = TipStatus.Pending,
|
||||
Amount = req.Amount,
|
||||
Currency = req.Currency,
|
||||
Message = req.Message
|
||||
};
|
||||
|
||||
dbContext.Tips.Add(tip);
|
||||
|
||||
await dbContext.SaveChangesAsync(ct);
|
||||
|
||||
await SendAsync(
|
||||
new SendTipResponse(checkout.Id, checkout.Url),
|
||||
cancellation: ct);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user