1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-12 15:12:16 -05:00

Rename ProviderClientOrganizationSignUpCommand

This commit is contained in:
Rui Tome 2025-05-02 12:09:37 +01:00
parent 974ca2724c
commit 753d1311d4
No known key found for this signature in database
GPG Key ID: 526239D96A8EC066
3 changed files with 42 additions and 59 deletions

View File

@ -1,15 +0,0 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.Entities;
using Bit.Core.Models.Business;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
public interface ISignUpProviderClientOrganizationCommand
{
/// <summary>
/// Sign up a new client organization for a provider.
/// </summary>
/// <param name="signup">The signup information.</param>
/// <returns>A tuple containing the new organization and its default collection.</returns>
Task<(Organization organization, Collection defaultCollection)> SignUpClientOrganizationAsync(OrganizationSignup signup);
}

View File

@ -1,5 +1,4 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.Billing.Pricing; using Bit.Core.Billing.Pricing;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
@ -16,7 +15,21 @@ using Bit.Core.Utilities;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations; namespace Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrganizationCommand public record ProviderClientOrganizationSignUpResponse(
Organization Organization,
Collection DefaultCollection);
public interface IProviderClientOrganizationSignUpCommand
{
/// <summary>
/// Sign up a new client organization for a provider.
/// </summary>
/// <param name="signup">The signup information.</param>
/// <returns>A tuple containing the new organization and its default collection.</returns>
Task<ProviderClientOrganizationSignUpResponse> SignUpClientOrganizationAsync(OrganizationSignup signup);
}
public class ProviderClientOrganizationSignUpCommand : IProviderClientOrganizationSignUpCommand
{ {
private readonly ICurrentContext _currentContext; private readonly ICurrentContext _currentContext;
private readonly IPricingClient _pricingClient; private readonly IPricingClient _pricingClient;
@ -25,19 +38,15 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository; private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
private readonly IApplicationCacheService _applicationCacheService; private readonly IApplicationCacheService _applicationCacheService;
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IDeviceRepository _deviceRepository;
private readonly IPaymentService _paymentService;
public SignUpProviderClientOrganizationCommand( public ProviderClientOrganizationSignUpCommand(
ICurrentContext currentContext, ICurrentContext currentContext,
IPricingClient pricingClient, IPricingClient pricingClient,
IReferenceEventService referenceEventService, IReferenceEventService referenceEventService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IOrganizationApiKeyRepository organizationApiKeyRepository, IOrganizationApiKeyRepository organizationApiKeyRepository,
IApplicationCacheService applicationCacheService, IApplicationCacheService applicationCacheService,
ICollectionRepository collectionRepository, ICollectionRepository collectionRepository)
IDeviceRepository deviceRepository,
IPaymentService paymentService)
{ {
_currentContext = currentContext; _currentContext = currentContext;
_pricingClient = pricingClient; _pricingClient = pricingClient;
@ -46,15 +55,13 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
_organizationApiKeyRepository = organizationApiKeyRepository; _organizationApiKeyRepository = organizationApiKeyRepository;
_applicationCacheService = applicationCacheService; _applicationCacheService = applicationCacheService;
_collectionRepository = collectionRepository; _collectionRepository = collectionRepository;
_deviceRepository = deviceRepository;
_paymentService = paymentService;
} }
public async Task<(Organization organization, Collection defaultCollection)> SignUpClientOrganizationAsync(OrganizationSignup signup) public async Task<ProviderClientOrganizationSignUpResponse> SignUpClientOrganizationAsync(OrganizationSignup signup)
{ {
var plan = await _pricingClient.GetPlanOrThrow(signup.Plan); var plan = await _pricingClient.GetPlanOrThrow(signup.Plan);
ValidatePlan(plan, signup.AdditionalSeats, "Password Manager"); ValidatePlan(plan, signup.AdditionalSeats);
var organization = new Organization var organization = new Organization
{ {
@ -101,38 +108,37 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
{ {
PlanName = plan.Name, PlanName = plan.Name,
PlanType = plan.Type, PlanType = plan.Type,
Seats = returnValue.Item1.Seats, Seats = returnValue.Organization.Seats,
SignupInitiationPath = signup.InitiationPath, SignupInitiationPath = signup.InitiationPath,
Storage = returnValue.Item1.MaxStorageGb, Storage = returnValue.Organization.MaxStorageGb,
}); });
return returnValue; return returnValue;
} }
private static void ValidatePlan(Plan plan, int additionalSeats, string productType) private static void ValidatePlan(Plan plan, int additionalSeats)
{ {
if (plan is null) if (plan is null)
{ {
throw new BadRequestException($"{productType} Plan was null."); throw new BadRequestException("Password Manager Plan was null.");
} }
if (plan.Disabled) if (plan.Disabled)
{ {
throw new BadRequestException($"{productType} Plan not found."); throw new BadRequestException("Password Manager Plan is disabled.");
} }
if (additionalSeats < 0) if (additionalSeats < 0)
{ {
throw new BadRequestException($"You can't subtract {productType} seats!"); throw new BadRequestException("You can't subtract Password Manager seats!");
} }
} }
/// <summary> /// <summary>
/// Private helper method to create a new organization. /// Private helper method to create a new organization.
/// This is common code used by both the cloud and self-hosted methods.
/// </summary> /// </summary>
private async Task<(Organization organization, Collection defaultCollection)> SignUpAsync(Organization organization, private async Task<ProviderClientOrganizationSignUpResponse> SignUpAsync(
string collectionName) Organization organization, string collectionName)
{ {
try try
{ {
@ -160,7 +166,7 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
await _collectionRepository.CreateAsync(defaultCollection, null, null); await _collectionRepository.CreateAsync(defaultCollection, null, null);
} }
return (organization, defaultCollection); return new ProviderClientOrganizationSignUpResponse(organization, defaultCollection);
} }
catch catch
{ {
@ -173,12 +179,4 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
throw; throw;
} }
} }
private async Task<IEnumerable<string>> GetUserDeviceIdsAsync(Guid userId)
{
var devices = await _deviceRepository.GetManyByUserIdAsync(userId);
return devices
.Where(d => !string.IsNullOrWhiteSpace(d.PushToken))
.Select(d => d.Id.ToString());
}
} }

View File

@ -19,10 +19,10 @@ using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations; namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations.OrganizationSignUp;
[SutProviderCustomize] [SutProviderCustomize]
public class SignUpProviderClientOrganizationCommandTests public class ProviderClientOrganizationSignUpCommandTests
{ {
[Theory] [Theory]
[BitAutoData(PlanType.TeamsAnnually)] [BitAutoData(PlanType.TeamsAnnually)]
@ -33,7 +33,7 @@ public class SignUpProviderClientOrganizationCommandTests
PlanType planType, PlanType planType,
OrganizationSignup signup, OrganizationSignup signup,
string collectionName, string collectionName,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider) SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{ {
signup.Plan = planType; signup.Plan = planType;
signup.AdditionalSeats = 15; signup.AdditionalSeats = 15;
@ -46,9 +46,9 @@ public class SignUpProviderClientOrganizationCommandTests
var result = await sutProvider.Sut.SignUpClientOrganizationAsync(signup); var result = await sutProvider.Sut.SignUpClientOrganizationAsync(signup);
Assert.NotNull(result.organization); Assert.NotNull(result.Organization);
Assert.NotNull(result.defaultCollection); Assert.NotNull(result.DefaultCollection);
Assert.Equal(collectionName, result.defaultCollection.Name); Assert.Equal(collectionName, result.DefaultCollection.Name);
await sutProvider.GetDependency<IOrganizationRepository>() await sutProvider.GetDependency<IOrganizationRepository>()
.Received(1) .Received(1)
@ -71,8 +71,8 @@ public class SignUpProviderClientOrganizationCommandTests
referenceEvent.Type == ReferenceEventType.Signup && referenceEvent.Type == ReferenceEventType.Signup &&
referenceEvent.PlanName == plan.Name && referenceEvent.PlanName == plan.Name &&
referenceEvent.PlanType == plan.Type && referenceEvent.PlanType == plan.Type &&
referenceEvent.Seats == result.organization.Seats && referenceEvent.Seats == result.Organization.Seats &&
referenceEvent.Storage == result.organization.MaxStorageGb && referenceEvent.Storage == result.Organization.MaxStorageGb &&
referenceEvent.SignupInitiationPath == signup.InitiationPath referenceEvent.SignupInitiationPath == signup.InitiationPath
)); ));
@ -81,7 +81,7 @@ public class SignUpProviderClientOrganizationCommandTests
.CreateAsync( .CreateAsync(
Arg.Is<Collection>(c => Arg.Is<Collection>(c =>
c.Name == collectionName && c.Name == collectionName &&
c.OrganizationId == result.organization.Id c.OrganizationId == result.Organization.Id
), ),
Arg.Any<IEnumerable<CollectionAccessSelection>>(), Arg.Any<IEnumerable<CollectionAccessSelection>>(),
Arg.Any<IEnumerable<CollectionAccessSelection>>() Arg.Any<IEnumerable<CollectionAccessSelection>>()
@ -91,21 +91,21 @@ public class SignUpProviderClientOrganizationCommandTests
.Received(1) .Received(1)
.CreateAsync( .CreateAsync(
Arg.Is<OrganizationApiKey>(k => Arg.Is<OrganizationApiKey>(k =>
k.OrganizationId == result.organization.Id && k.OrganizationId == result.Organization.Id &&
k.Type == OrganizationApiKeyType.Default k.Type == OrganizationApiKeyType.Default
) )
); );
await sutProvider.GetDependency<IApplicationCacheService>() await sutProvider.GetDependency<IApplicationCacheService>()
.Received(1) .Received(1)
.UpsertOrganizationAbilityAsync(Arg.Is<Organization>(o => o.Id == result.organization.Id)); .UpsertOrganizationAbilityAsync(Arg.Is<Organization>(o => o.Id == result.Organization.Id));
} }
[Theory] [Theory]
[BitAutoData] [BitAutoData]
public async Task SignupClientAsync_NullPlan_ThrowsBadRequestException( public async Task SignupClientAsync_NullPlan_ThrowsBadRequestException(
OrganizationSignup signup, OrganizationSignup signup,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider) SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{ {
sutProvider.GetDependency<IPricingClient>() sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(signup.Plan) .GetPlanOrThrow(signup.Plan)
@ -121,7 +121,7 @@ public class SignUpProviderClientOrganizationCommandTests
[BitAutoData] [BitAutoData]
public async Task SignupClientAsync_NegativeAdditionalSeats_ThrowsBadRequestException( public async Task SignupClientAsync_NegativeAdditionalSeats_ThrowsBadRequestException(
OrganizationSignup signup, OrganizationSignup signup,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider) SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{ {
signup.Plan = PlanType.TeamsMonthly; signup.Plan = PlanType.TeamsMonthly;
signup.AdditionalSeats = -5; signup.AdditionalSeats = -5;
@ -142,7 +142,7 @@ public class SignUpProviderClientOrganizationCommandTests
public async Task SignupClientAsync_WhenExceptionIsThrown_CleanupIsPerformed( public async Task SignupClientAsync_WhenExceptionIsThrown_CleanupIsPerformed(
PlanType planType, PlanType planType,
OrganizationSignup signup, OrganizationSignup signup,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider) SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{ {
signup.Plan = planType; signup.Plan = planType;