Make payments dependency injected based on the .env settings

This commit is contained in:
2025-06-20 18:31:18 -07:00
parent c4ad0f2c10
commit fb2a2c6ae9
8 changed files with 111 additions and 83 deletions
+2 -1
View File
@@ -12,4 +12,5 @@ trim_trailing_whitespace = false
[*.cs]
csharp_new_line_before_open_brace = none
csharp_new_line_before_catch = false
csharp_new_line_before_finally = false
csharp_new_line_before_finally = false
csharp_new_line_after_else = false
+3
View File
@@ -1,4 +1,7 @@
Payment_Service=StripeIntent # Options are [ StripeIntent ]
Stripe_Key=
Stripe_Endpoint_Secret=
MySQL_Server=mistox-database
MySQL_User=root
+1 -6
View File
@@ -1,5 +1,4 @@
Fix stripe payments *Updated API*
Havent Tested
Stripe payments aren't currently tested
After a new account is created notify a user that they need to verify their email before logging in
@@ -30,9 +29,5 @@ DTO
Cannot send dotnet List -> must be arrays
Need to update local server to use www-formdata instead of json
PaymentController
PaymentResponse is still tied to Stripe.
Need to change to Interface so different services can be interchanged
ProductController
Need to figure out new way to download purchased items as there is currently no way
+2
View File
@@ -5,7 +5,9 @@ services:
image: mistox-website:latest
restart: always
environment:
- PaymentService=${Payment_Service}
- StripeKey=${Stripe_Key}
- StripeEndpointSecret=&{Stripe_Endpoint_Secret}
- MySQLServer=${MySQL_Server}
- MySQLUser=${MySQL_User}
- MySQLPass=${MySQL_Pass}
@@ -2,107 +2,59 @@
using MistoxWebsite.Server.Controllers.Payment;
using MistoxWebsite.Server.Services.DatabaseService;
using MistoxWebsite.Server.Entities;
using Microsoft.Extensions.Primitives;
namespace MistoxWebsite.Server.Controllers {
[ApiController]
public class PaymentController : ControllerBase {
DatabaseService _databaseService;
IPayment _paymentService;
public PaymentController( DatabaseService databaseService ) {
public PaymentController(DatabaseService databaseService) {
_databaseService = databaseService;
if (IPayment._PaymentType == PaymentType.StripeIntent) {
_paymentService = new StripeIntent(_databaseService);
} else {
// Fallback
_paymentService = new StripeIntent(_databaseService);
}
// Add new payment plugins here
}
// Charges
[Route( "api/getCheckoutToken" )]
[Route("api/getCheckoutToken")]
[HttpPost]
public async Task<string> GetPaymentKey( [FromQuery] string userID ) {
string OrderNumber = Guid.NewGuid().ToString().Substring(0,10);
Account? acc = await _databaseService.GetAccount(userID);
if (acc != null) {
List<Cart> cart = await _databaseService.GetCart(acc);
IPayment PaymentPlugin = new StripeIntent(_databaseService);
(bool, string) PaymentResponse = await PaymentPlugin.Purchase(OrderNumber, acc, cart);
(bool, string) PaymentResponse = await _paymentService.TryGetCheckoutToken(OrderNumber, acc, cart);
if (PaymentResponse.Item1) {
// Returns client secret
return PaymentResponse.Item2;
}
else {
} else {
Console.WriteLine("An error has occured in the payment plugin\n\n");
Console.WriteLine(PaymentResponse.Item2);
Console.WriteLine("\n");
return "0";
return "An error has occured in the payment plugin";
}
} else {
return "Unable to find account";
}
return "0";
}
[Route( "/api/payment/response" )]
[HttpPost]
public async Task<IActionResult> paymentWebhook() {
try {
const string endpointSecret = "whsec_HCO7uv2BPIPmUPOiSg9tfwLZul8usCGG";
string body = await new StreamReader(Request.Body).ReadToEndAsync();
Stripe.Event e = Stripe.EventUtility.ConstructEvent( body, Request.Headers["Stripe-Signature"], endpointSecret );
if( e.Type == "payment_intent.succeeded" ) {
// Extract Data from payment confirm
Stripe.PaymentIntent intent = (Stripe.PaymentIntent)e.Data.Object;
string orderNumber = "";
int userID = 0;
List<int> productIDs = new List<int>();
int subtotal = 0;
int total = 0;
KeyValuePair<string, string>[] y = intent.Metadata.ToArray();
foreach( KeyValuePair<string, string> cur in y ) {
string val = cur.Key;
if( val == "ordernumber" ) {
orderNumber = cur.Value;
} else if( val == "user" ) {
userID = int.Parse( cur.Value );
} else if( val == "products" ) {
string[] products = cur.Value.Split(',');
foreach( string product in products ) {
if ( !string.IsNullOrEmpty(product) ) {
productIDs.Add( Convert.ToInt32( product ) );
}
}
} else if( val == "subtotal" ) {
subtotal = int.Parse( cur.Value );
} else if( val == "total" ) {
total = int.Parse( cur.Value );
}
}
// Clear the cart
Account account = new() {
ID = userID
};
await _databaseService.ClearCart( account );
// Add data to misox receipt
for( int i = 0; i < productIDs.Count; i++ ) {
int product = productIDs[i];
await _databaseService.NewReceipt( new Receipt {
AccountID = userID,
ProductID = product,
ReceiptID = orderNumber,
Time = DateTime.Now,
TaxAmount = total - subtotal,
TotalCost = total,
LineItem = i
} );
}
} else {
Console.WriteLine( "Unhandled event type: {0}", e.Type );
}
await _paymentService.ValidatePurchase(body, Request.Headers["Stripe-Signature"].ToString());
return Ok();
} catch( Exception ex ) {
return Content(ex.ToString());
} catch (Exception ex) {
return NotFound(ex.ToString());
}
}
@@ -4,8 +4,16 @@ namespace MistoxWebsite.Server.Controllers.Payment {
public interface IPayment {
public Task<(bool, string)> Purchase(string OrderNumber, Account user, List<Cart> cart);
public static PaymentType _PaymentType;
public static string _EndpointSecret = "";
public Task<(bool, string)> TryGetCheckoutToken(string OrderNumber, Account user, List<Cart> cart);
public Task ValidatePurchase(string WebHookData, string Headers);
}
public enum PaymentType {
StripeIntent
}
}
@@ -8,11 +8,11 @@ namespace MistoxWebsite.Server.Controllers {
DatabaseService _databaseService;
public StripeIntent( DatabaseService databaseService ) {
public StripeIntent(DatabaseService databaseService) {
_databaseService = databaseService;
}
public async Task<(bool, string)> Purchase(string OrderNumber, Account user, List<Cart> cart) {
public async Task<(bool, string)> TryGetCheckoutToken(string OrderNumber, Account user, List<Cart> cart) {
try {
// build Recipt and calculate Tax
var options = new Stripe.Tax.CalculationCreateOptions {
@@ -72,12 +72,71 @@ namespace MistoxWebsite.Server.Controllers {
Stripe.PaymentIntent x = await intentService.CreateAsync(paymentIntent);
return (true, x.ClientSecret);
} catch(Exception e) {
} catch (Exception e) {
return (false, e.ToString());
}
}
public async Task ValidatePurchase(string WebHookData, string Headers) {
Stripe.Event e = Stripe.EventUtility.ConstructEvent( WebHookData, Headers, IPayment._EndpointSecret );
if (e.Type == "payment_intent.succeeded") {
// Extract Data from payment confirm
Stripe.PaymentIntent intent = (Stripe.PaymentIntent)e.Data.Object;
string orderNumber = "";
int userID = 0;
List<int> productIDs = new List<int>();
int subtotal = 0;
int total = 0;
KeyValuePair<string, string>[] y = intent.Metadata.ToArray();
foreach (KeyValuePair<string, string> cur in y) {
string val = cur.Key;
if (val == "ordernumber") {
orderNumber = cur.Value;
}
else if (val == "user") {
userID = int.Parse(cur.Value);
}
else if (val == "products") {
string[] products = cur.Value.Split(',');
foreach (string product in products) {
if (!string.IsNullOrEmpty(product)) {
productIDs.Add(Convert.ToInt32(product));
}
}
}
else if (val == "subtotal") {
subtotal = int.Parse(cur.Value);
}
else if (val == "total") {
total = int.Parse(cur.Value);
}
}
// Clear the cart
Account account = new() {
ID = userID
};
await _databaseService.ClearCart(account);
// Add data to misox receipt
for (int i = 0; i < productIDs.Count; i++) {
int product = productIDs[i];
await _databaseService.NewReceipt(new Receipt {
AccountID = userID,
ProductID = product,
ReceiptID = orderNumber,
Time = DateTime.Now,
TaxAmount = total - subtotal,
TotalCost = total,
LineItem = i
});
}
} else {
Console.WriteLine("Unhandled event type: {0}", e.Type);
}
}
}
}
+10 -2
View File
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using MistoxWebsite.Server.Controllers;
using MistoxWebsite.Server.Controllers.Payment;
using MistoxWebsite.Server.Services;
using MistoxWebsite.Server.Services.DatabaseService;
using Stripe;
@@ -37,8 +38,15 @@ EmailService Emailservice = new EmailService( EmailServer, EmailPort, EmailAddre
builder.Services.Add( new ServiceDescriptor( typeof( EmailService ), Emailservice ));
// Payment Service
string? StripeKey = Environment.GetEnvironmentVariable("StripeKey");
StripeConfiguration.ApiKey = StripeKey;
string? PaymentService = Environment.GetEnvironmentVariable("PaymentService");
IPayment._PaymentType = (PaymentType)Enum.Parse(typeof(PaymentType), PaymentService, true);
if (IPayment._PaymentType == PaymentType.StripeIntent) {
string? StripeKey = Environment.GetEnvironmentVariable("StripeKey");
StripeConfiguration.ApiKey = StripeKey;
string? StripeEndpointKey = Environment.GetEnvironmentVariable("StripeEndpointSecret");
IPayment._EndpointSecret = string.IsNullOrEmpty(StripeEndpointKey) ? "" : StripeEndpointKey ;
}
// Authentication Service
builder.Services.AddAuthentication( options => {