1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-20 19:14:32 -05:00

Handle case where Stripe IDs do not relate to Stripe entities (#4021)

This commit is contained in:
Alex Morask 2024-04-25 11:07:47 -04:00 committed by GitHub
parent 78b57ba99f
commit f7aa56b324
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 163 additions and 49 deletions

View File

@ -24,16 +24,27 @@ public class SubscriberQueries(
return null; return null;
} }
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions); try
if (customer != null)
{ {
return customer; var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions);
if (customer != null)
{
return customer;
}
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})",
subscriber.GatewayCustomerId, subscriber.Id);
return null;
} }
catch (StripeException exception)
{
logger.LogError("An error occurred while trying to retrieve Stripe customer ({CustomerID}) for subscriber ({SubscriberID}): {Error}",
subscriber.GatewayCustomerId, subscriber.Id, exception.Message);
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})", subscriber.GatewayCustomerId, subscriber.Id); return null;
}
return null;
} }
public async Task<Subscription> GetSubscription( public async Task<Subscription> GetSubscription(
@ -49,41 +60,28 @@ public class SubscriberQueries(
return null; return null;
} }
var subscription = await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions); try
if (subscription != null)
{ {
return subscription; var subscription =
await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
if (subscription != null)
{
return subscription;
}
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})",
subscriber.GatewaySubscriptionId, subscriber.Id);
return null;
} }
catch (StripeException exception)
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})", subscriber.GatewaySubscriptionId, subscriber.Id);
return null;
}
public async Task<Subscription> GetSubscriptionOrThrow(
ISubscriber subscriber,
SubscriptionGetOptions subscriptionGetOptions = null)
{
ArgumentNullException.ThrowIfNull(subscriber);
if (string.IsNullOrEmpty(subscriber.GatewaySubscriptionId))
{ {
logger.LogError("Cannot retrieve subscription for subscriber ({SubscriberID}) with no {FieldName}", subscriber.Id, nameof(subscriber.GatewaySubscriptionId)); logger.LogError("An error occurred while trying to retrieve Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID}): {Error}",
subscriber.GatewaySubscriptionId, subscriber.Id, exception.Message);
throw ContactSupport(); return null;
} }
var subscription = await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
if (subscription != null)
{
return subscription;
}
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})", subscriber.GatewaySubscriptionId, subscriber.Id);
throw ContactSupport();
} }
public async Task<Customer> GetCustomerOrThrow( public async Task<Customer> GetCustomerOrThrow(
@ -99,15 +97,63 @@ public class SubscriberQueries(
throw ContactSupport(); throw ContactSupport();
} }
var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions); try
if (customer != null)
{ {
return customer; var customer = await stripeAdapter.CustomerGetAsync(subscriber.GatewayCustomerId, customerGetOptions);
if (customer != null)
{
return customer;
}
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})",
subscriber.GatewayCustomerId, subscriber.Id);
throw ContactSupport();
}
catch (StripeException exception)
{
logger.LogError("An error occurred while trying to retrieve Stripe customer ({CustomerID}) for subscriber ({SubscriberID}): {Error}",
subscriber.GatewayCustomerId, subscriber.Id, exception.Message);
throw ContactSupport("An error occurred while trying to retrieve a Stripe Customer", exception);
}
}
public async Task<Subscription> GetSubscriptionOrThrow(
ISubscriber subscriber,
SubscriptionGetOptions subscriptionGetOptions = null)
{
ArgumentNullException.ThrowIfNull(subscriber);
if (string.IsNullOrEmpty(subscriber.GatewaySubscriptionId))
{
logger.LogError("Cannot retrieve subscription for subscriber ({SubscriberID}) with no {FieldName}", subscriber.Id, nameof(subscriber.GatewaySubscriptionId));
throw ContactSupport();
} }
logger.LogError("Could not find Stripe customer ({CustomerID}) for subscriber ({SubscriberID})", subscriber.GatewayCustomerId, subscriber.Id); try
{
var subscription =
await stripeAdapter.SubscriptionGetAsync(subscriber.GatewaySubscriptionId, subscriptionGetOptions);
throw ContactSupport(); if (subscription != null)
{
return subscription;
}
logger.LogError("Could not find Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID})",
subscriber.GatewaySubscriptionId, subscriber.Id);
throw ContactSupport();
}
catch (StripeException exception)
{
logger.LogError("An error occurred while trying to retrieve Stripe subscription ({SubscriptionID}) for subscriber ({SubscriberID}): {Error}",
subscriber.GatewaySubscriptionId, subscriber.Id, exception.Message);
throw ContactSupport("An error occurred while trying to retrieve a Stripe Subscription", exception);
}
} }
} }

View File

@ -4,6 +4,7 @@ using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
using NSubstitute.ExceptionExtensions;
using NSubstitute.ReturnsExtensions; using NSubstitute.ReturnsExtensions;
using Stripe; using Stripe;
using Xunit; using Xunit;
@ -48,6 +49,20 @@ public class SubscriberQueriesTests
Assert.Null(customer); Assert.Null(customer);
} }
[Theory, BitAutoData]
public async Task GetCustomer_StripeException_ReturnsNull(
Organization organization,
SutProvider<SubscriberQueries> sutProvider)
{
sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId)
.ThrowsAsync<StripeException>();
var customer = await sutProvider.Sut.GetCustomer(organization);
Assert.Null(customer);
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetCustomer_Succeeds( public async Task GetCustomer_Succeeds(
Organization organization, Organization organization,
@ -98,6 +113,20 @@ public class SubscriberQueriesTests
Assert.Null(subscription); Assert.Null(subscription);
} }
[Theory, BitAutoData]
public async Task GetSubscription_StripeException_ReturnsNull(
Organization organization,
SutProvider<SubscriberQueries> sutProvider)
{
sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId)
.ThrowsAsync<StripeException>();
var subscription = await sutProvider.Sut.GetSubscription(organization);
Assert.Null(subscription);
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetSubscription_Succeeds( public async Task GetSubscription_Succeeds(
Organization organization, Organization organization,
@ -123,7 +152,7 @@ public class SubscriberQueriesTests
async () => await sutProvider.Sut.GetCustomerOrThrow(null)); async () => await sutProvider.Sut.GetCustomerOrThrow(null));
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetCustomerOrThrow_NoGatewaySubscriptionId_ThrowsGatewayException( public async Task GetCustomerOrThrow_NoGatewayCustomerId_ContactSupport(
Organization organization, Organization organization,
SutProvider<SubscriberQueries> sutProvider) SutProvider<SubscriberQueries> sutProvider)
{ {
@ -133,7 +162,7 @@ public class SubscriberQueriesTests
} }
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetSubscriptionOrThrow_NoCustomer_ThrowsGatewayException( public async Task GetCustomerOrThrow_NoCustomer_ContactSupport(
Organization organization, Organization organization,
SutProvider<SubscriberQueries> sutProvider) SutProvider<SubscriberQueries> sutProvider)
{ {
@ -144,6 +173,23 @@ public class SubscriberQueriesTests
await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetCustomerOrThrow(organization)); await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetCustomerOrThrow(organization));
} }
[Theory, BitAutoData]
public async Task GetCustomerOrThrow_StripeException_ContactSupport(
Organization organization,
SutProvider<SubscriberQueries> sutProvider)
{
var stripeException = new StripeException();
sutProvider.GetDependency<IStripeAdapter>()
.CustomerGetAsync(organization.GatewayCustomerId)
.ThrowsAsync(stripeException);
await ThrowsContactSupportAsync(
async () => await sutProvider.Sut.GetCustomerOrThrow(organization),
"An error occurred while trying to retrieve a Stripe Customer",
stripeException);
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetCustomerOrThrow_Succeeds( public async Task GetCustomerOrThrow_Succeeds(
Organization organization, Organization organization,
@ -169,7 +215,7 @@ public class SubscriberQueriesTests
async () => await sutProvider.Sut.GetSubscriptionOrThrow(null)); async () => await sutProvider.Sut.GetSubscriptionOrThrow(null));
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetSubscriptionOrThrow_NoGatewaySubscriptionId_ThrowsGatewayException( public async Task GetSubscriptionOrThrow_NoGatewaySubscriptionId_ContactSupport(
Organization organization, Organization organization,
SutProvider<SubscriberQueries> sutProvider) SutProvider<SubscriberQueries> sutProvider)
{ {
@ -179,7 +225,7 @@ public class SubscriberQueriesTests
} }
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetSubscriptionOrThrow_NoSubscription_ThrowsGatewayException( public async Task GetSubscriptionOrThrow_NoSubscription_ContactSupport(
Organization organization, Organization organization,
SutProvider<SubscriberQueries> sutProvider) SutProvider<SubscriberQueries> sutProvider)
{ {
@ -190,6 +236,23 @@ public class SubscriberQueriesTests
await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization)); await ThrowsContactSupportAsync(async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization));
} }
[Theory, BitAutoData]
public async Task GetSubscriptionOrThrow_StripeException_ContactSupport(
Organization organization,
SutProvider<SubscriberQueries> sutProvider)
{
var stripeException = new StripeException();
sutProvider.GetDependency<IStripeAdapter>()
.SubscriptionGetAsync(organization.GatewaySubscriptionId)
.ThrowsAsync(stripeException);
await ThrowsContactSupportAsync(
async () => await sutProvider.Sut.GetSubscriptionOrThrow(organization),
"An error occurred while trying to retrieve a Stripe Subscription",
stripeException);
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetSubscriptionOrThrow_Succeeds( public async Task GetSubscriptionOrThrow_Succeeds(
Organization organization, Organization organization,

View File

@ -7,12 +7,17 @@ namespace Bit.Core.Test.Billing;
public static class Utilities public static class Utilities
{ {
public static async Task ThrowsContactSupportAsync(Func<Task> function) public static async Task ThrowsContactSupportAsync(
Func<Task> function,
string internalMessage = null,
Exception innerException = null)
{ {
var contactSupport = ContactSupport(); var contactSupport = ContactSupport(internalMessage, innerException);
var exception = await Assert.ThrowsAsync<BillingException>(function); var exception = await Assert.ThrowsAsync<BillingException>(function);
Assert.Equal(contactSupport.ClientFriendlyMessage, exception.ClientFriendlyMessage);
Assert.Equal(contactSupport.Message, exception.Message); Assert.Equal(contactSupport.Message, exception.Message);
Assert.Equal(contactSupport.InnerException, exception.InnerException);
} }
} }