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.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.Billing.Pricing;
using Bit.Core.Context;
using Bit.Core.Entities;
@ -16,7 +15,21 @@ using Bit.Core.Utilities;
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 IPricingClient _pricingClient;
@ -25,19 +38,15 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly ICollectionRepository _collectionRepository;
private readonly IDeviceRepository _deviceRepository;
private readonly IPaymentService _paymentService;
public SignUpProviderClientOrganizationCommand(
public ProviderClientOrganizationSignUpCommand(
ICurrentContext currentContext,
IPricingClient pricingClient,
IReferenceEventService referenceEventService,
IOrganizationRepository organizationRepository,
IOrganizationApiKeyRepository organizationApiKeyRepository,
IApplicationCacheService applicationCacheService,
ICollectionRepository collectionRepository,
IDeviceRepository deviceRepository,
IPaymentService paymentService)
ICollectionRepository collectionRepository)
{
_currentContext = currentContext;
_pricingClient = pricingClient;
@ -46,15 +55,13 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
_organizationApiKeyRepository = organizationApiKeyRepository;
_applicationCacheService = applicationCacheService;
_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);
ValidatePlan(plan, signup.AdditionalSeats, "Password Manager");
ValidatePlan(plan, signup.AdditionalSeats);
var organization = new Organization
{
@ -101,38 +108,37 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
{
PlanName = plan.Name,
PlanType = plan.Type,
Seats = returnValue.Item1.Seats,
Seats = returnValue.Organization.Seats,
SignupInitiationPath = signup.InitiationPath,
Storage = returnValue.Item1.MaxStorageGb,
Storage = returnValue.Organization.MaxStorageGb,
});
return returnValue;
}
private static void ValidatePlan(Plan plan, int additionalSeats, string productType)
private static void ValidatePlan(Plan plan, int additionalSeats)
{
if (plan is null)
{
throw new BadRequestException($"{productType} Plan was null.");
throw new BadRequestException("Password Manager Plan was null.");
}
if (plan.Disabled)
{
throw new BadRequestException($"{productType} Plan not found.");
throw new BadRequestException("Password Manager Plan is disabled.");
}
if (additionalSeats < 0)
{
throw new BadRequestException($"You can't subtract {productType} seats!");
throw new BadRequestException("You can't subtract Password Manager seats!");
}
}
/// <summary>
/// Private helper method to create a new organization.
/// This is common code used by both the cloud and self-hosted methods.
/// </summary>
private async Task<(Organization organization, Collection defaultCollection)> SignUpAsync(Organization organization,
string collectionName)
private async Task<ProviderClientOrganizationSignUpResponse> SignUpAsync(
Organization organization, string collectionName)
{
try
{
@ -160,7 +166,7 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
await _collectionRepository.CreateAsync(defaultCollection, null, null);
}
return (organization, defaultCollection);
return new ProviderClientOrganizationSignUpResponse(organization, defaultCollection);
}
catch
{
@ -173,12 +179,4 @@ public class SignUpProviderClientOrganizationCommand : ISignUpProviderClientOrga
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 Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations.OrganizationSignUp;
[SutProviderCustomize]
public class SignUpProviderClientOrganizationCommandTests
public class ProviderClientOrganizationSignUpCommandTests
{
[Theory]
[BitAutoData(PlanType.TeamsAnnually)]
@ -33,7 +33,7 @@ public class SignUpProviderClientOrganizationCommandTests
PlanType planType,
OrganizationSignup signup,
string collectionName,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider)
SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{
signup.Plan = planType;
signup.AdditionalSeats = 15;
@ -46,9 +46,9 @@ public class SignUpProviderClientOrganizationCommandTests
var result = await sutProvider.Sut.SignUpClientOrganizationAsync(signup);
Assert.NotNull(result.organization);
Assert.NotNull(result.defaultCollection);
Assert.Equal(collectionName, result.defaultCollection.Name);
Assert.NotNull(result.Organization);
Assert.NotNull(result.DefaultCollection);
Assert.Equal(collectionName, result.DefaultCollection.Name);
await sutProvider.GetDependency<IOrganizationRepository>()
.Received(1)
@ -71,8 +71,8 @@ public class SignUpProviderClientOrganizationCommandTests
referenceEvent.Type == ReferenceEventType.Signup &&
referenceEvent.PlanName == plan.Name &&
referenceEvent.PlanType == plan.Type &&
referenceEvent.Seats == result.organization.Seats &&
referenceEvent.Storage == result.organization.MaxStorageGb &&
referenceEvent.Seats == result.Organization.Seats &&
referenceEvent.Storage == result.Organization.MaxStorageGb &&
referenceEvent.SignupInitiationPath == signup.InitiationPath
));
@ -81,7 +81,7 @@ public class SignUpProviderClientOrganizationCommandTests
.CreateAsync(
Arg.Is<Collection>(c =>
c.Name == collectionName &&
c.OrganizationId == result.organization.Id
c.OrganizationId == result.Organization.Id
),
Arg.Any<IEnumerable<CollectionAccessSelection>>(),
Arg.Any<IEnumerable<CollectionAccessSelection>>()
@ -91,21 +91,21 @@ public class SignUpProviderClientOrganizationCommandTests
.Received(1)
.CreateAsync(
Arg.Is<OrganizationApiKey>(k =>
k.OrganizationId == result.organization.Id &&
k.OrganizationId == result.Organization.Id &&
k.Type == OrganizationApiKeyType.Default
)
);
await sutProvider.GetDependency<IApplicationCacheService>()
.Received(1)
.UpsertOrganizationAbilityAsync(Arg.Is<Organization>(o => o.Id == result.organization.Id));
.UpsertOrganizationAbilityAsync(Arg.Is<Organization>(o => o.Id == result.Organization.Id));
}
[Theory]
[BitAutoData]
public async Task SignupClientAsync_NullPlan_ThrowsBadRequestException(
OrganizationSignup signup,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider)
SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{
sutProvider.GetDependency<IPricingClient>()
.GetPlanOrThrow(signup.Plan)
@ -121,7 +121,7 @@ public class SignUpProviderClientOrganizationCommandTests
[BitAutoData]
public async Task SignupClientAsync_NegativeAdditionalSeats_ThrowsBadRequestException(
OrganizationSignup signup,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider)
SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{
signup.Plan = PlanType.TeamsMonthly;
signup.AdditionalSeats = -5;
@ -142,7 +142,7 @@ public class SignUpProviderClientOrganizationCommandTests
public async Task SignupClientAsync_WhenExceptionIsThrown_CleanupIsPerformed(
PlanType planType,
OrganizationSignup signup,
SutProvider<SignUpProviderClientOrganizationCommand> sutProvider)
SutProvider<ProviderClientOrganizationSignUpCommand> sutProvider)
{
signup.Plan = planType;