Files
social-media/backend/Modules/Memberships/Handlers/HandleStripe.cs
2025-06-13 02:22:35 -04:00

91 lines
3.5 KiB
C#

using System.Diagnostics;
using Hutopy.Infrastructure.Payments.Stripe.Configuration;
using Hutopy.Modules.Memberships.Contracts;
using Hutopy.Modules.Tipping.Contracts;
using Microsoft.Extensions.Options;
using Stripe;
using Stripe.Checkout;
namespace Hutopy.Modules.Memberships.Handlers;
public class StripeWebhookEndpoint(
ITipPaymentNotifier tipPaymentNotifier,
IMembershipNotifier membershipNotifier,
IOptions<StripeOptions> options)
: EndpointWithoutRequest
{
public override void Configure()
{
Post("/api/stripe");
AllowAnonymous();
Options(o => o.WithTags( "Webhooks"));
}
public override async Task HandleAsync(CancellationToken ct)
{
using var streamReader = new StreamReader(HttpContext.Request.Body);
var json = await streamReader.ReadToEndAsync(ct);
var signatureHeader = HttpContext.Request.Headers["Stripe-Signature"];
var stripeEvent = EventUtility.ConstructEvent(json, signatureHeader, options.Value.WebhookSecret);
var stripeSession = stripeEvent.Data.Object as Session;
var stripeSubscription = stripeEvent.Data.Object as Subscription;
switch (stripeEvent.Type)
{
case "checkout.session.completed":
Debug.Assert(stripeSession != null);
switch (stripeSession.Mode)
{
// Check if this is a one-time tip
case "payment" when stripeSession.PaymentIntentId != null
&& stripeSession.PaymentIntent.Status == "paid":
await tipPaymentNotifier.NotifyPaymentSucceedAsync(
stripeSession.Id,
stripeSession.Invoice.HostedInvoiceUrl,
ct);
break;
// Check if this is a subscription
case "subscription" when stripeSession.SubscriptionId != null:
await membershipNotifier.NotifyPaymentSucceedAsync(
stripeSession.SubscriptionId,
stripeSession.Invoice.HostedInvoiceUrl,
stripeSession.Invoice.Total,
stripeSession.Invoice.Currency,
cancellationToken: ct);
break;
}
break;
case "invoice.payment_succeeded":
var invoice = (stripeEvent.Data.Object as Invoice);
Debug.Assert(invoice != null);
Debug.Assert(invoice.Subscription != null);
await membershipNotifier.NotifyPaymentSucceedAsync(
invoice.SubscriptionId,
invoice.HostedInvoiceUrl,
invoice.Total,
invoice.Currency,
cancellationToken: ct);
break;
case "customer.subscription.updated":
Debug.Assert(stripeSubscription != null);
await membershipNotifier.NotifySubscriptionUpdatedAsync(
stripeSubscription.Id,
stripeSubscription.CancelAt ?? stripeSubscription.CanceledAt,
ct);
break;
case "customer.subscription.deleted":
Debug.Assert(stripeSubscription != null);
await membershipNotifier.NotifySubscriptionDeletedAsync(
stripeSubscription.Id,
ct);
break;
}
await SendOkAsync(ct);
}
}