Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AC-2379] Stripe webhook update provider status #4012

Closed
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,38 @@ public async Task DeleteAsync(Provider provider)
await _applicationCacheService.DeleteProviderAbilityAsync(provider.Id);
}

public async Task EnableAsync(Guid providerId)
{
var provider = await _providerRepository.GetByIdAsync(providerId);

if (provider is not { Enabled: false, Gateway: not null })
{
return;
}

provider.Enabled = true;
provider.RevisionDate = DateTime.UtcNow;

await _providerRepository.ReplaceAsync(provider);
await _applicationCacheService.UpsertProviderAbilityAsync(provider);
}

public async Task DisableAsync(Guid providerId)
{
var provider = await _providerRepository.GetByIdAsync(providerId);

if (provider is not { Enabled: true })
{
return;
}

provider.Enabled = false;
provider.RevisionDate = DateTime.UtcNow;

await _providerRepository.ReplaceAsync(provider);
await _applicationCacheService.UpsertProviderAbilityAsync(provider);
}

private async Task SendInviteAsync(ProviderUser providerUser, Provider provider)
{
var nowMillis = CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@ public static void AddCommercialCoreServices(this IServiceCollection services)
{
services.AddScoped<IProviderService, ProviderService>();
services.AddScoped<ICreateProviderCommand, CreateProviderCommand>();
services.AddScoped<IRemoveOrganizationFromProviderCommand, RemoveOrganizationFromProviderCommand>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,70 @@ Provider provider
await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.DeleteAsync(provider, validToken));
}

[Theory, BitAutoData]
public async Task EnableAsync_Success(Provider provider, SutProvider<ProviderService> sutProvider)
{
// Arrange
provider.Enabled = false;
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
providerRepository.GetByIdAsync(provider.Id).Returns(provider);

// Act
await sutProvider.Sut.EnableAsync(provider.Id);

// Assert
Assert.True(provider.Enabled);
await providerRepository.Received().ReplaceAsync(provider);
}

[Theory, BitAutoData]
public async Task EnableAsync_AlreadyEnabled_DoesNothing(Provider provider, SutProvider<ProviderService> sutProvider)
{
// Arrange
provider.Enabled = true;
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
providerRepository.GetByIdAsync(provider.Id).Returns(provider);

// Act
await sutProvider.Sut.EnableAsync(provider.Id);

// Assert
Assert.True(provider.Enabled);
await providerRepository.DidNotReceive().ReplaceAsync(provider);
}

[Theory, BitAutoData]
public async Task DisableAsync_Success(Provider provider, SutProvider<ProviderService> sutProvider)
{
// Arrange
provider.Enabled = true;
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
providerRepository.GetByIdAsync(provider.Id).Returns(provider);

// Act
await sutProvider.Sut.DisableAsync(provider.Id);

// Assert
Assert.False(provider.Enabled);
await providerRepository.Received().ReplaceAsync(provider);
}

[Theory, BitAutoData]
public async Task DisableAsync_AlreadyDisabled_DoesNothing(Provider provider, SutProvider<ProviderService> sutProvider)
{
// Arrange
provider.Enabled = false;
var providerRepository = sutProvider.GetDependency<IProviderRepository>();
providerRepository.GetByIdAsync(provider.Id).Returns(provider);

// Act
await sutProvider.Sut.DisableAsync(provider.Id);

// Assert
Assert.False(provider.Enabled);
await providerRepository.DidNotReceive().ReplaceAsync(provider);
}

private static SubscriptionUpdateOptions SubscriptionUpdateRequest(string expectedPlanId, Subscription subscriptionItem) =>
new()
{
Expand Down
1 change: 1 addition & 0 deletions src/Billing/Billing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<PropertyGroup Condition=" '$(RunConfiguration)' == 'Billing' " />
<ItemGroup>
<ProjectReference Include="..\..\bitwarden_license\src\Commercial.Core\Commercial.Core.csproj" />
<ProjectReference Include="..\SharedWeb\SharedWeb.csproj" />
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
Expand Down
36 changes: 24 additions & 12 deletions src/Billing/Controllers/StripeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Bit.Billing.Services;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Billing.Constants;
using Bit.Core.Context;
using Bit.Core.Enums;
Expand Down Expand Up @@ -55,6 +56,7 @@
private readonly IStripeEventService _stripeEventService;
private readonly IStripeFacade _stripeFacade;
private readonly IFeatureService _featureService;
private readonly IProviderService _providerService;

public StripeController(
GlobalSettings globalSettings,
Expand All @@ -74,7 +76,8 @@
ICurrentContext currentContext,
IStripeEventService stripeEventService,
IStripeFacade stripeFacade,
IFeatureService featureService)
IFeatureService featureService,
IProviderService providerService)

Check warning on line 80 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L79-L80

Added lines #L79 - L80 were not covered by tests
{
_billingSettings = billingSettings?.Value;
_hostingEnvironment = hostingEnvironment;
Expand Down Expand Up @@ -102,6 +105,7 @@
_stripeEventService = stripeEventService;
_stripeFacade = stripeFacade;
_featureService = featureService;
_providerService = providerService;

Check warning on line 108 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L108

Added line #L108 was not covered by tests
}

[HttpPost("webhook")]
Expand Down Expand Up @@ -224,13 +228,8 @@
await _organizationService.DisableAsync(organizationId.Value, subscription.CurrentPeriodEnd);
break;
}
case StripeSubscriptionStatus.Unpaid or StripeSubscriptionStatus.IncompleteExpired:
case StripeSubscriptionStatus.Unpaid or StripeSubscriptionStatus.IncompleteExpired when userId.HasValue:
{
if (!userId.HasValue)
{
break;
}

if (subscription.Status is StripeSubscriptionStatus.Unpaid &&
subscription.Items.Any(i => i.Price.Id is PremiumPlanId or PremiumPlanIdAppStore))
{
Expand All @@ -240,19 +239,27 @@

await _userService.DisablePremiumAsync(userId.Value, subscription.CurrentPeriodEnd);

break;

Check warning on line 242 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L242

Added line #L242 was not covered by tests
}
case StripeSubscriptionStatus.Unpaid or StripeSubscriptionStatus.IncompleteExpired when providerId.HasValue:
{
await _providerService.DisableAsync(providerId.Value);

Check warning on line 246 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L245-L246

Added lines #L245 - L246 were not covered by tests
break;
}
case StripeSubscriptionStatus.Active when organizationId.HasValue:
{
await _organizationService.EnableAsync(organizationId.Value);
break;
}
case StripeSubscriptionStatus.Active:
case StripeSubscriptionStatus.Active when userId.HasValue:
{
if (userId.HasValue)
{
await _userService.EnablePremiumAsync(userId.Value, subscription.CurrentPeriodEnd);
}
await _userService.EnablePremiumAsync(userId.Value, subscription.CurrentPeriodEnd);

Check warning on line 256 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L256

Added line #L256 was not covered by tests

break;

Check warning on line 258 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L258

Added line #L258 was not covered by tests
}
case StripeSubscriptionStatus.Active when providerId.HasValue:
{
await _providerService.EnableAsync(providerId.Value);

Check warning on line 262 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L261-L262

Added lines #L261 - L262 were not covered by tests

break;
}
Expand All @@ -272,6 +279,7 @@
{
await _userService.UpdatePremiumExpirationAsync(userId.Value, subscription.CurrentPeriodEnd);
}
// No need to update the expiration date for providers as they don't have one
}

/// <summary>
Expand Down Expand Up @@ -355,6 +363,10 @@
{
await _userService.DisablePremiumAsync(userId.Value, subscription.CurrentPeriodEnd);
}
else if (providerId.HasValue)
{
await _providerService.DisableAsync(providerId.Value);
}

Check warning on line 369 in src/Billing/Controllers/StripeController.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Controllers/StripeController.cs#L367-L369

Added lines #L367 - L369 were not covered by tests
}

/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions src/Billing/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Globalization;
using Bit.Billing.Services;
using Bit.Billing.Services.Implementations;
using Bit.Core.Billing.Extensions;
using Bit.Core.Context;
using Bit.Core.SecretsManager.Repositories;
using Bit.Core.SecretsManager.Repositories.Noop;
Expand Down Expand Up @@ -66,6 +67,8 @@
// TODO: no longer be required - see PM-1880
services.AddScoped<IServiceAccountRepository, NoopServiceAccountRepository>();

services.AddBillingOperations();

Check warning on line 70 in src/Billing/Startup.cs

View check run for this annotation

Codecov / codecov/patch

src/Billing/Startup.cs#L70

Added line #L70 was not covered by tests

// Mvc
services.AddMvc(config =>
{
Expand Down
2 changes: 1 addition & 1 deletion src/Core/AdminConsole/Entities/Provider/Provider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Provider : ITableObject<Guid>, ISubscriber
public ProviderType Type { get; set; }
public bool Enabled { get; set; } = true;
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
public GatewayType? Gateway { get; set; }
public string GatewayCustomerId { get; set; }
public string GatewaySubscriptionId { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions src/Core/AdminConsole/Services/IProviderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ public interface IProviderService
Task InitiateDeleteAsync(Provider provider, string providerAdminEmail);
Task DeleteAsync(Provider provider, string token);
Task DeleteAsync(Provider provider);
Task EnableAsync(Guid providerId);
Task DisableAsync(Guid providerId);
}

Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@
public Task InitiateDeleteAsync(Provider provider, string providerAdminEmail) => throw new NotImplementedException();
public Task DeleteAsync(Provider provider, string token) => throw new NotImplementedException();
public Task DeleteAsync(Provider provider) => throw new NotImplementedException();
public Task EnableAsync(Guid providerId) => throw new NotImplementedException();
public Task DisableAsync(Guid providerId) => throw new NotImplementedException();

Check warning on line 42 in src/Core/AdminConsole/Services/NoopImplementations/NoopProviderService.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/AdminConsole/Services/NoopImplementations/NoopProviderService.cs#L41-L42

Added lines #L41 - L42 were not covered by tests
}