mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Fixed billing webhook endpoints
This commit is contained in:
parent
4b0c3fa4c1
commit
162a8c5e4e
@ -36,8 +36,8 @@ namespace Teknik.BillingCore
|
|||||||
public abstract CheckoutSession CreateCheckoutSession(string customerId, string priceId, string successUrl, string cancelUrl);
|
public abstract CheckoutSession CreateCheckoutSession(string customerId, string priceId, string successUrl, string cancelUrl);
|
||||||
public abstract CheckoutSession GetCheckoutSession(string sessionId);
|
public abstract CheckoutSession GetCheckoutSession(string sessionId);
|
||||||
|
|
||||||
public abstract Task<Event> ParseEvent(HttpRequest request);
|
public abstract Task<Event> ParseEvent(HttpRequest request, string apiKey);
|
||||||
public abstract CheckoutSession ProcessCheckoutCompletedEvent(Event e);
|
public abstract CheckoutSession ProcessCheckoutCompletedEvent(Event e);
|
||||||
public abstract Customer ProcessCustomerEvent(Event e);
|
public abstract Subscription ProcessSubscriptionEvent(Event e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ namespace Teknik.BillingCore
|
|||||||
return ConvertCheckoutSession(session);
|
return ConvertCheckoutSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Models.Event> ParseEvent(HttpRequest request)
|
public override async Task<Models.Event> ParseEvent(HttpRequest request, string apiKey)
|
||||||
{
|
{
|
||||||
var json = await new StreamReader(request.Body).ReadToEndAsync();
|
var json = await new StreamReader(request.Body).ReadToEndAsync();
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ namespace Teknik.BillingCore
|
|||||||
var stripeEvent = EventUtility.ConstructEvent(
|
var stripeEvent = EventUtility.ConstructEvent(
|
||||||
json,
|
json,
|
||||||
request.Headers["Stripe-Signature"],
|
request.Headers["Stripe-Signature"],
|
||||||
Config.StripeWebhookSecret
|
apiKey
|
||||||
);
|
);
|
||||||
|
|
||||||
return ConvertEvent(stripeEvent);
|
return ConvertEvent(stripeEvent);
|
||||||
@ -292,12 +292,12 @@ namespace Teknik.BillingCore
|
|||||||
return ConvertCheckoutSession(session);
|
return ConvertCheckoutSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Models.Customer ProcessCustomerEvent(Models.Event ev)
|
public override Models.Subscription ProcessSubscriptionEvent(Models.Event ev)
|
||||||
{
|
{
|
||||||
// Handle the checkout.session.completed event
|
// Handle the checkout.session.completed event
|
||||||
var customer = ev.Data as Stripe.Customer;
|
var subscription = ev.Data as Stripe.Subscription;
|
||||||
|
|
||||||
return ConvertCustomer(customer);
|
return ConvertSubscription(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override CheckoutSession GetCheckoutSession(string sessionId)
|
public override CheckoutSession GetCheckoutSession(string sessionId)
|
||||||
@ -433,7 +433,7 @@ namespace Teknik.BillingCore
|
|||||||
return new CheckoutSession()
|
return new CheckoutSession()
|
||||||
{
|
{
|
||||||
PaymentIntentId = session.PaymentIntentId,
|
PaymentIntentId = session.PaymentIntentId,
|
||||||
CustomerId = session.Customer.Id,
|
CustomerId = session.Customer?.Id ?? session.CustomerId,
|
||||||
SubscriptionId = session.SubscriptionId,
|
SubscriptionId = session.SubscriptionId,
|
||||||
PaymentStatus = paymentStatus,
|
PaymentStatus = paymentStatus,
|
||||||
Url = session.Url
|
Url = session.Url
|
||||||
|
@ -11,7 +11,8 @@ namespace Teknik.Configuration
|
|||||||
public BillingType Type { get; set; }
|
public BillingType Type { get; set; }
|
||||||
public string StripePublishApiKey { get; set; }
|
public string StripePublishApiKey { get; set; }
|
||||||
public string StripeSecretApiKey { get; set; }
|
public string StripeSecretApiKey { get; set; }
|
||||||
public string StripeWebhookSecret { get; set; }
|
public string StripeCheckoutWebhookSecret { get; set; }
|
||||||
|
public string StripeCustomerWebhookSecret { get; set; }
|
||||||
|
|
||||||
public string UploadProductId { get; set; }
|
public string UploadProductId { get; set; }
|
||||||
public string EmailProductId { get; set; }
|
public string EmailProductId { get; set; }
|
||||||
@ -21,7 +22,8 @@ namespace Teknik.Configuration
|
|||||||
Type = BillingType.Stripe;
|
Type = BillingType.Stripe;
|
||||||
StripePublishApiKey = null;
|
StripePublishApiKey = null;
|
||||||
StripeSecretApiKey = null;
|
StripeSecretApiKey = null;
|
||||||
StripeWebhookSecret = null;
|
StripeCheckoutWebhookSecret = null;
|
||||||
|
StripeCustomerWebhookSecret = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,28 @@
|
|||||||
"action": "Dashboard"
|
"action": "Dashboard"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Name": "API.v1.HandleCheckoutComplete",
|
||||||
|
"HostTypes": [ "Full" ],
|
||||||
|
"SubDomains": [ "api" ],
|
||||||
|
"Pattern": "v1/Billing/HandleCheckoutComplete",
|
||||||
|
"Area": "API",
|
||||||
|
"Defaults": {
|
||||||
|
"controller": "BillingAPIv1",
|
||||||
|
"action": "HandleCheckoutCompleteEvent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "API.v1.HandleSubscriptionChange",
|
||||||
|
"HostTypes": [ "Full" ],
|
||||||
|
"SubDomains": [ "api" ],
|
||||||
|
"Pattern": "v1/Billing/HandleSubscriptionChange",
|
||||||
|
"Area": "API",
|
||||||
|
"Defaults": {
|
||||||
|
"controller": "BillingAPIv1",
|
||||||
|
"action": "HandleSubscriptionChange"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Name": "API.v1.Claims",
|
"Name": "API.v1.Claims",
|
||||||
"HostTypes": [ "Full" ],
|
"HostTypes": [ "Full" ],
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Teknik.Areas.Billing;
|
||||||
using Teknik.Areas.Users.Models;
|
using Teknik.Areas.Users.Models;
|
||||||
using Teknik.Areas.Users.Utility;
|
using Teknik.Areas.Users.Utility;
|
||||||
using Teknik.BillingCore;
|
using Teknik.BillingCore;
|
||||||
@ -24,7 +25,7 @@ namespace Teknik.Areas.API.V1.Controllers
|
|||||||
{
|
{
|
||||||
var billingService = BillingFactory.GetBillingService(_config.BillingConfig);
|
var billingService = BillingFactory.GetBillingService(_config.BillingConfig);
|
||||||
|
|
||||||
var billingEvent = await billingService.ParseEvent(Request);
|
var billingEvent = await billingService.ParseEvent(Request, _config.BillingConfig.StripeCheckoutWebhookSecret);
|
||||||
|
|
||||||
if (billingEvent == null)
|
if (billingEvent == null)
|
||||||
return BadRequest();
|
return BadRequest();
|
||||||
@ -34,7 +35,7 @@ namespace Teknik.Areas.API.V1.Controllers
|
|||||||
{
|
{
|
||||||
var subscription = billingService.GetSubscription(session.SubscriptionId);
|
var subscription = billingService.GetSubscription(session.SubscriptionId);
|
||||||
|
|
||||||
ProcessSubscription(session.CustomerId, subscription);
|
BillingHelper.ProcessSubscription(_config, _dbContext, session.CustomerId, subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
@ -44,61 +45,18 @@ namespace Teknik.Areas.API.V1.Controllers
|
|||||||
{
|
{
|
||||||
var billingService = BillingFactory.GetBillingService(_config.BillingConfig);
|
var billingService = BillingFactory.GetBillingService(_config.BillingConfig);
|
||||||
|
|
||||||
var billingEvent = await billingService.ParseEvent(Request);
|
var billingEvent = await billingService.ParseEvent(Request, _config.BillingConfig.StripeCustomerWebhookSecret);
|
||||||
|
|
||||||
if (billingEvent == null)
|
if (billingEvent == null)
|
||||||
return BadRequest();
|
return BadRequest();
|
||||||
|
|
||||||
var customerEvent = billingService.ProcessCustomerEvent(billingEvent);
|
var subscriptionEvent = billingService.ProcessSubscriptionEvent(billingEvent);
|
||||||
|
if (subscriptionEvent == null)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
foreach (var subscription in customerEvent.Subscriptions)
|
BillingHelper.ProcessSubscription(_config, _dbContext, subscriptionEvent.CustomerId, subscriptionEvent);
|
||||||
{
|
|
||||||
ProcessSubscription(customerEvent.CustomerId, subscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessSubscription(string customerId, Subscription subscription)
|
|
||||||
{
|
|
||||||
// They have paid, so let's get their subscription and update their user settings
|
|
||||||
var user = _dbContext.Users.FirstOrDefault(u => u.BillingCustomer != null &&
|
|
||||||
u.BillingCustomer.CustomerId == customerId);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
var isActive = subscription.Status == SubscriptionStatus.Active;
|
|
||||||
foreach (var price in subscription.Prices)
|
|
||||||
{
|
|
||||||
ProcessPrice(user, price, isActive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessPrice(User user, Price price, bool active)
|
|
||||||
{
|
|
||||||
// What type of subscription is this
|
|
||||||
if (_config.BillingConfig.UploadProductId == price.ProductId)
|
|
||||||
{
|
|
||||||
// Process Upload Settings
|
|
||||||
user.UploadSettings.MaxUploadStorage = active ? price.Storage : _config.UploadConfig.MaxStorage;
|
|
||||||
user.UploadSettings.MaxUploadFileSize = active ? price.FileSize : _config.UploadConfig.MaxUploadFileSize;
|
|
||||||
_dbContext.Entry(user).State = EntityState.Modified;
|
|
||||||
_dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
else if (_config.BillingConfig.EmailProductId == price.ProductId)
|
|
||||||
{
|
|
||||||
// Process an email subscription
|
|
||||||
string email = UserHelper.GetUserEmailAddress(_config, user.Username);
|
|
||||||
if (active)
|
|
||||||
{
|
|
||||||
UserHelper.EnableUserEmail(_config, email);
|
|
||||||
UserHelper.EditUserEmailMaxSize(_config, email, (int)price.Storage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UserHelper.DisableUserEmail(_config, email);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
Teknik/Areas/Billing/BillingHelper.cs
Normal file
56
Teknik/Areas/Billing/BillingHelper.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Linq;
|
||||||
|
using Teknik.Areas.Users.Models;
|
||||||
|
using Teknik.Areas.Users.Utility;
|
||||||
|
using Teknik.BillingCore;
|
||||||
|
using Teknik.BillingCore.Models;
|
||||||
|
using Teknik.Configuration;
|
||||||
|
using Teknik.Data;
|
||||||
|
|
||||||
|
namespace Teknik.Areas.Billing
|
||||||
|
{
|
||||||
|
public static class BillingHelper
|
||||||
|
{
|
||||||
|
public static void ProcessSubscription(Config config, TeknikEntities db, string customerId, Subscription subscription)
|
||||||
|
{
|
||||||
|
// They have paid, so let's get their subscription and update their user settings
|
||||||
|
var user = db.Users.FirstOrDefault(u => u.BillingCustomer != null &&
|
||||||
|
u.BillingCustomer.CustomerId == customerId);
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var isActive = subscription.Status == SubscriptionStatus.Active;
|
||||||
|
foreach (var price in subscription.Prices)
|
||||||
|
{
|
||||||
|
ProcessPrice(config, db, user, price, isActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ProcessPrice(Config config, TeknikEntities db, User user, Price price, bool active)
|
||||||
|
{
|
||||||
|
// What type of subscription is this
|
||||||
|
if (config.BillingConfig.UploadProductId == price.ProductId)
|
||||||
|
{
|
||||||
|
// Process Upload Settings
|
||||||
|
user.UploadSettings.MaxUploadStorage = active ? price.Storage : config.UploadConfig.MaxStorage;
|
||||||
|
user.UploadSettings.MaxUploadFileSize = active ? price.FileSize : config.UploadConfig.MaxUploadFileSize;
|
||||||
|
db.Entry(user).State = EntityState.Modified;
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
else if (config.BillingConfig.EmailProductId == price.ProductId)
|
||||||
|
{
|
||||||
|
// Process an email subscription
|
||||||
|
string email = UserHelper.GetUserEmailAddress(config, user.Username);
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
UserHelper.EnableUserEmail(config, email);
|
||||||
|
UserHelper.EditUserEmailMaxSize(config, email, (int)price.Storage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UserHelper.DisableUserEmail(config, email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
@ -11,8 +12,14 @@ namespace Teknik.Utilities.TagHelpers
|
|||||||
{
|
{
|
||||||
private const string _verFile = "version.json";
|
private const string _verFile = "version.json";
|
||||||
|
|
||||||
|
private readonly IWebHostEnvironment _env;
|
||||||
public string Source { get; set; }
|
public string Source { get; set; }
|
||||||
|
|
||||||
|
public VersionHelper(IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
_env = env;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||||
{
|
{
|
||||||
// Clear the initial wrap tag
|
// Clear the initial wrap tag
|
||||||
@ -32,7 +39,7 @@ namespace Teknik.Utilities.TagHelpers
|
|||||||
string commitVer = res["version"].ToString();
|
string commitVer = res["version"].ToString();
|
||||||
string commitHash = res["hash"].ToString();
|
string commitHash = res["hash"].ToString();
|
||||||
|
|
||||||
output.Content.AppendHtml($"Version: {commitVer} - Hash: <a href=\"{Source}{commitHash}\">{commitHash.Truncate(10)}</a>");
|
output.Content.AppendHtml($"Version: {commitVer} - Hash: <a href=\"{Source}{commitHash}\">{commitHash.Truncate(10)}</a> | {_env.EnvironmentName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user