using Hutopy.Infrastructure.Configuration; using Hutopy.Infrastructure.Payments.Stripe.Configuration; using Hutopy.Infrastructure.Security; using Hutopy.Modules.Creators.Data; using Microsoft.Extensions.Options; using Stripe; namespace Hutopy.Modules.Creators.Features; [PublicAPI] public record ConnectStripeResponse( string Url); public class ConnectStripeIdHandler( IOptionsSnapshot websiteOptions, IOptionsSnapshot stripeOptions, CreatorsDbContext dbContext) : EndpointWithoutRequest { public override void Configure() { Post("/api/stripe/connect"); Options(o => o.WithTags("Creators")); } public override async Task HandleAsync( CancellationToken ct) { // 1. Get the creator's information Guid creatorId = HttpContext.User.GetUserId(); string email = HttpContext.User.GetEmail(); // 2. Get or create the creator Creator? creator = await dbContext .Creators .SingleOrDefaultAsync( c => c.Id == creatorId, ct); if (creator is null) { await SendNotFoundAsync(ct); return; } // 3. Create a Stripe account StripeConfiguration.ApiKey = stripeOptions.Value.SecretKey; AccountService accountService = new(); if (string.IsNullOrWhiteSpace(creator.StripeAccountId)) { Account? account = await accountService.CreateAsync( new AccountCreateOptions { Type = "express", Capabilities = new AccountCapabilitiesOptions { Transfers = new AccountCapabilitiesTransfersOptions { Requested = true } }, Email = email }, cancellationToken: ct); // 5. Update the creator's Stripe account ID creator.StripeAccountId = account.Id; await dbContext.SaveChangesAsync(ct); } // 4. Check if the creator already has a Stripe account if (creator is { IsStripeDetailsSubmitted: true, IsStripeChargesEnabled: true, IsStripePayoutReady: true }) { await SendErrorsAsync(cancellation: ct); return; } // 5. Create an account link AccountLinkService accountLinkService = new(); AccountLink? accountLink = await accountLinkService.CreateAsync( new AccountLinkCreateOptions { Account = creator.StripeAccountId, RefreshUrl = $"{websiteOptions.Value.FrontendBaseUrl}/profile?stripe=retry", ReturnUrl = $"{websiteOptions.Value.FrontendBaseUrl}/profile?stripe=complete", Type = "account_onboarding" }, cancellationToken: ct); // 6. Return the account link URL to the client await SendOkAsync(new ConnectStripeResponse(accountLink.Url), ct); } }