feat: pivot to social media workflow app
Some checks failed
Backend CI/CD / build_and_deploy (push) Has been cancelled
Frontend CI/CD / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-04-24 12:58:35 -04:00
parent 0f4acc1b6d
commit df3e602015
349 changed files with 18685 additions and 16010 deletions

View File

@@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations;
namespace Hutopy.Infrastructure.Payments.Stripe.Configuration;
namespace Socialize.Infrastructure.Payments.Stripe.Configuration;
public class StripeOptions
{
@@ -10,5 +10,5 @@ public class StripeOptions
[Required] public required string WebhookSecret { get; init; }
[Required] [Range(0, 1)] public required decimal HutopyRate { get; init; }
[Required] [Range(0, 1)] public required decimal SocializeRate { get; init; }
}

View File

@@ -1,28 +0,0 @@
using Hutopy.Modules.Memberships.Contracts;
using Stripe;
namespace Hutopy.Infrastructure.Payments.Stripe.Services;
public sealed class MembershipCancellationProcessor
: IMembershipCancellationProcessor
{
public async Task<DateTimeOffset?> CancelAsync(
string subscriptionId,
CancellationToken ct = default)
{
SubscriptionService subscriptionService = new();
// Stripe - Cancel Subscription immediately
// var subscription = await subscriptionService.CancelAsync(
// subscriptionId,
// cancellationToken: ct);
// Stripe - Cancel Subscription AtPeriodEnd
Subscription? subscription = await subscriptionService.UpdateAsync(
subscriptionId,
new SubscriptionUpdateOptions { CancelAtPeriodEnd = true },
cancellationToken: ct);
return subscription.CancelAt ?? subscription.CanceledAt;
}
}

View File

@@ -1,68 +0,0 @@
using Hutopy.Infrastructure.Payments.Stripe.Configuration;
using Hutopy.Modules.Creators.Contracts;
using Hutopy.Modules.Memberships.Contracts;
using Microsoft.Extensions.Options;
using Stripe;
using Stripe.Checkout;
namespace Hutopy.Infrastructure.Payments.Stripe.Services;
public class MembershipPaymentProcessor(
IOptions<StripeOptions> stripeOptions)
: IMembershipPaymentProcessor
{
public async Task<MembershipCheckoutSession> CreateCheckoutSessionAsync(
Guid userId,
CreatorReference creatorReference,
Guid tierId,
string priceId,
string successUrl,
string cancelUrl)
{
StripeConfiguration.ApiKey = stripeOptions.Value.SecretKey;
// Create Stripe customer for the user if not already created
CustomerService customerService = new();
Customer? customer = await customerService.CreateAsync(
new CustomerCreateOptions
{
Metadata = new Dictionary<string, string> { { "userId", userId.ToString() } }
});
// Create Checkout Session for the subscription
SessionService sessionService = new();
Session? session = await sessionService.CreateAsync(
new SessionCreateOptions
{
Customer = customer.Id,
PaymentMethodTypes = ["card"],
LineItems =
[
new SessionLineItemOptions { Price = priceId, Quantity = 1 }
],
Mode = "subscription",
SubscriptionData = new SessionSubscriptionDataOptions
{
ApplicationFeePercent = stripeOptions.Value.HutopyRate,
TransferData =
new SessionSubscriptionDataTransferDataOptions
{
Destination = creatorReference.StripeAccountId
}
},
SuccessUrl = successUrl, // Redirect after successful payment
CancelUrl = cancelUrl, // Redirect after canceled payment
Metadata = new Dictionary<string, string>
{
{ "userId", userId.ToString() },
{ "creatorId", creatorReference.Id.ToString() },
{ "creatorName", creatorReference.Name },
{ "tierId", tierId.ToString() }
}
});
return new MembershipCheckoutSession(
session.Id,
session.Url);
}
}

View File

@@ -1,43 +0,0 @@
using Hutopy.Infrastructure.Payments.Stripe.Configuration;
using Hutopy.Modules.Memberships.Contracts;
using Microsoft.Extensions.Options;
using Stripe;
namespace Hutopy.Infrastructure.Payments.Stripe.Services;
public sealed class MembershipTierProcessor(
IOptions<StripeOptions> stripeOptions)
: IMembershipTierProcessor
{
public async Task<string> CreateAsync(
Guid creatorId,
Guid tierId,
string productName,
string currencyCode,
decimal amount)
{
StripeConfiguration.ApiKey = stripeOptions.Value.SecretKey;
// Create the product
ProductService productService = new();
Product? product = await productService.CreateAsync(
new ProductCreateOptions
{
Name = productName,
Metadata = { { "creatorId", creatorId.ToString() }, { "tierId", tierId.ToString() } }
});
// Create the price for the product
PriceService priceService = new();
await priceService.CreateAsync(
new PriceCreateOptions
{
Product = product.Id,
UnitAmountDecimal = amount * 100, // Convert amount to cents
Currency = currencyCode,
Recurring = new PriceRecurringOptions { Interval = "month" }
});
return product.Id;
}
}

View File

@@ -1,70 +0,0 @@
using Hutopy.Infrastructure.Payments.Stripe.Configuration;
using Hutopy.Modules.Creators.Contracts;
using Hutopy.Modules.Tipping.Contracts;
using Microsoft.Extensions.Options;
using Stripe;
using Stripe.Checkout;
namespace Hutopy.Infrastructure.Payments.Stripe.Services;
internal class StripeTipProcessor(
IOptions<StripeOptions> stripeOptions)
: ITipProcessor
{
public async Task<TipCheckoutSession> CreateCheckoutSessionAsync(
Guid tipId,
CreatorReference creator,
decimal amount,
string currency,
string message,
Uri successUrl,
Uri cancelUrl,
CancellationToken ct = default)
{
var applicationFeeAmount = Convert.ToInt64(amount * stripeOptions.Value.HutopyRate);
StripeConfiguration.ApiKey = stripeOptions.Value.SecretKey;
var sessionService = new SessionService();
var options = new SessionCreateOptions
{
ClientReferenceId = tipId.ToString(),
Mode = "payment",
LineItems =
[
new SessionLineItemOptions
{
PriceData = new SessionLineItemPriceDataOptions
{
Currency = currency,
UnitAmountDecimal = amount, // Amount in cents
ProductData = new SessionLineItemPriceDataProductDataOptions
{
Name = $"Tip for {creator.Name}",
Metadata = new Dictionary<string, string> { { "creatorId", creator.Id.ToString() } }
}
},
Quantity = 1
}
],
PaymentIntentData = new SessionPaymentIntentDataOptions { ApplicationFeeAmount = applicationFeeAmount },
Metadata = new Dictionary<string, string>
{
{ "creatorId", creator.Id.ToString() }, { "creatorName", creator.Name }, { "message", message }
},
SuccessUrl = successUrl.ToString(), // Redirect after successful payment
CancelUrl = cancelUrl.ToString(), // Redirect after canceled payment
};
var requestOptions = new RequestOptions { StripeAccount = creator.StripeAccountId };
var session = await sessionService.CreateAsync(
options,
requestOptions,
cancellationToken: ct)
.ConfigureAwait(false);
return new TipCheckoutSession(session.Id, session.Url);
}
}