Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/Core/Billing/Licenses/Queries/GetUserLicenseQuery.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
ο»Ώusing Bit.Core.Billing.Models.Business;
ο»Ώusing Bit.Core.Billing.Constants;
using Bit.Core.Billing.Models.Business;
using Bit.Core.Billing.Services;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Services;

namespace Bit.Core.Billing.Licenses.Queries;
Expand All @@ -10,10 +13,26 @@ public interface IGetUserLicenseQuery
}

public class GetUserLicenseQuery(
IUserService userService) : IGetUserLicenseQuery
IUserService userService,
IStripePaymentService paymentService) : IGetUserLicenseQuery
{
public async Task<UserLicense> Run(User user)
{
var subscriptionInfo = await paymentService.GetSubscriptionAsync(user);

if (subscriptionInfo.Subscription is null)
{
throw new BadRequestException("No active subscription found.");
}

if (subscriptionInfo.Subscription.Status is StripeConstants.SubscriptionStatus.Canceled
or StripeConstants.SubscriptionStatus.Incomplete
or StripeConstants.SubscriptionStatus.IncompleteExpired)
{
throw new BadRequestException(
"Unable to generate license due to a payment issue. Please update your billing information or contact support for assistance.");
}

return await userService.GenerateLicenseAsync(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Billing.Services;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Platform.Installations;
using Bit.Core.Services;

namespace Bit.Core.Billing.Organizations.Queries;

Expand All @@ -25,20 +25,17 @@ public class GetCloudOrganizationLicenseQuery : IGetCloudOrganizationLicenseQuer
private readonly IStripePaymentService _paymentService;
private readonly ILicensingService _licensingService;
private readonly IProviderRepository _providerRepository;
private readonly IFeatureService _featureService;

public GetCloudOrganizationLicenseQuery(
IInstallationRepository installationRepository,
IStripePaymentService paymentService,
ILicensingService licensingService,
IProviderRepository providerRepository,
IFeatureService featureService)
IProviderRepository providerRepository)
{
_installationRepository = installationRepository;
_paymentService = paymentService;
_licensingService = licensingService;
_providerRepository = providerRepository;
_featureService = featureService;
}

public async Task<OrganizationLicense> GetLicenseAsync(Organization organization, Guid installationId,
Expand All @@ -51,6 +48,20 @@ public async Task<OrganizationLicense> GetLicenseAsync(Organization organization
}

var subscriptionInfo = await GetSubscriptionAsync(organization);

if (subscriptionInfo.Subscription is null)
{
throw new BadRequestException("No active subscription found.");
}

if (subscriptionInfo.Subscription.Status is StripeConstants.SubscriptionStatus.Canceled
or StripeConstants.SubscriptionStatus.Incomplete
or StripeConstants.SubscriptionStatus.IncompleteExpired)
{
throw new BadRequestException(
"Unable to generate license due to a payment issue. Please update your billing information or contact support for assistance.");
}

var license = new OrganizationLicense(organization, subscriptionInfo, installationId, _licensingService, version);
license.Token = await _licensingService.CreateOrganizationTokenAsync(organization, installationId, subscriptionInfo);

Expand Down
154 changes: 154 additions & 0 deletions test/Core.Test/Billing/Licenses/Queries/GetUserLicenseQueryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
ο»Ώusing Bit.Core.Billing.Licenses.Queries;
using Bit.Core.Billing.Models.Business;
using Bit.Core.Billing.Services;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Stripe;
using Xunit;

namespace Bit.Core.Test.Billing.Licenses.Queries;

[SutProviderCustomize]
public class GetUserLicenseQueryTests
{
[Theory]
[BitAutoData]
public async Task RunAsync_CanceledSubscription_Throws(
SutProvider<GetUserLicenseQuery> sutProvider,
User user)
{
var subInfo = new SubscriptionInfo
{
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "canceled" })
};
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);

var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
await sutProvider.Sut.Run(user));
Assert.Contains("Unable to generate license due to a payment issue", exception.Message);
}

[Theory]
[BitAutoData]
public async Task RunAsync_IncompleteSubscription_Throws(
SutProvider<GetUserLicenseQuery> sutProvider,
User user)
{
var subInfo = new SubscriptionInfo
{
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "incomplete" })
};
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);

var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
await sutProvider.Sut.Run(user));
Assert.Contains("Unable to generate license due to a payment issue", exception.Message);
}

[Theory]
[BitAutoData]
public async Task RunAsync_IncompleteExpiredSubscription_Throws(
SutProvider<GetUserLicenseQuery> sutProvider,
User user)
{
var subInfo = new SubscriptionInfo
{
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "incomplete_expired" })
};
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);

var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
await sutProvider.Sut.Run(user));
Assert.Contains("Unable to generate license due to a payment issue", exception.Message);
}

[Theory]
[BitAutoData]
public async Task RunAsync_NullSubscription_Throws(
SutProvider<GetUserLicenseQuery> sutProvider,
User user)
{
var subInfo = new SubscriptionInfo { Subscription = null };
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);

var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
await sutProvider.Sut.Run(user));
Assert.Contains("No active subscription found", exception.Message);
}

[Theory]
[BitAutoData]
public async Task RunAsync_ActiveSubscription_Succeeds(
SutProvider<GetUserLicenseQuery> sutProvider,
User user, UserLicense userLicense)
{
var subInfo = new SubscriptionInfo
{
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "active" })
};
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);
sutProvider.GetDependency<IUserService>().GenerateLicenseAsync(user).Returns(userLicense);

var result = await sutProvider.Sut.Run(user);

Assert.NotNull(result);
Assert.Equal(userLicense, result);
}

[Theory]
[BitAutoData]
public async Task RunAsync_TrialingSubscription_Succeeds(
SutProvider<GetUserLicenseQuery> sutProvider,
User user, UserLicense userLicense)
{
var subInfo = new SubscriptionInfo
{
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "trialing" })
};
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);
sutProvider.GetDependency<IUserService>().GenerateLicenseAsync(user).Returns(userLicense);

var result = await sutProvider.Sut.Run(user);

Assert.NotNull(result);
Assert.Equal(userLicense, result);
}

[Theory]
[BitAutoData]
public async Task RunAsync_PastDueSubscription_Succeeds(
SutProvider<GetUserLicenseQuery> sutProvider,
User user, UserLicense userLicense)
{
var subInfo = new SubscriptionInfo
{
Subscription = new SubscriptionInfo.BillingSubscription(new Subscription { Status = "past_due" })
};
sutProvider.GetDependency<IStripePaymentService>()
.GetSubscriptionAsync(user)
.Returns(subInfo);
sutProvider.GetDependency<IUserService>().GenerateLicenseAsync(user).Returns(userLicense);

var result = await sutProvider.Sut.Run(user);

Assert.NotNull(result);
Assert.Equal(userLicense, result);
}
}
Loading
Loading