From e80bbe1caac699f6f072c5134b4e50c7cea6db3e Mon Sep 17 00:00:00 2001 From: jrmccannon Date: Wed, 2 Apr 2025 20:44:17 -0500 Subject: [PATCH] Corrected model name. Corrected SM seat calculation. Added test for it. --- .../InviteOrganizationUsersCommand.cs | 25 +++---- .../Models/InviteOrganizationUsersResponse.cs | 6 +- ...viteOrganizationUsersValidationRequest.cs} | 8 +-- .../InviteOrganizationUserValidator.cs | 31 +++++---- .../PasswordManagerSubscriptionUpdate.cs | 14 ++-- ...OrganizationServiceCollectionExtensions.cs | 2 +- ...serOrganizationValidationRequestHelpers.cs | 6 +- .../InviteOrganizationUserCommandTests.cs | 34 +++++----- .../InviteOrganizationUsersValidatorTests.cs | 66 +++++++++++++++++++ 9 files changed, 129 insertions(+), 63 deletions(-) rename src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/{InviteUserOrganizationValidationRequest.cs => InviteOrganizationUsersValidationRequest.cs} (81%) create mode 100644 test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUsersValidatorTests.cs diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs index 9cffc20d4d..4eacb9386a 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs @@ -87,7 +87,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, new InviteOrganizationUsersResponse(request.InviteOrganization.OrganizationId))); } - var validationResult = await inviteUsersValidator.ValidateAsync(new InviteUserOrganizationValidationRequest + var validationResult = await inviteUsersValidator.ValidateAsync(new InviteOrganizationUsersValidationRequest { Invites = invitesToSend.ToArray(), InviteOrganization = request.InviteOrganization, @@ -97,12 +97,12 @@ public class InviteOrganizationUsersCommand(IEventService eventService, OccupiedSmSeats = await organizationUserRepository.GetOccupiedSmSeatCountByOrganizationIdAsync(request.InviteOrganization.OrganizationId) }); - if (validationResult is Invalid invalid) + if (validationResult is Invalid invalid) { return invalid.MapToFailure(r => new InviteOrganizationUsersResponse(r)); } - var validatedRequest = validationResult as Valid; + var validatedRequest = validationResult as Valid; var organizationUserToInviteEntities = invitesToSend .Select(x => x.MapToDataModel(request.PerformedAt, validatedRequest!.Value.InviteOrganization)) @@ -135,8 +135,9 @@ public class InviteOrganizationUsersCommand(IEventService eventService, await RevertPasswordManagerChangesAsync(validatedRequest, organization); - return new Failure(new FailedToInviteUsersError( - new InviteOrganizationUsersResponse(validatedRequest.Value))); + return new Failure( + new FailedToInviteUsersError( + new InviteOrganizationUsersResponse(validatedRequest.Value))); } return new Success( @@ -156,7 +157,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, .ToArray(); } - private async Task RevertPasswordManagerChangesAsync(Valid validatedResult, Organization organization) + private async Task RevertPasswordManagerChangesAsync(Valid validatedResult, Organization organization) { if (validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd > 0) { @@ -173,7 +174,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, } } - private async Task RevertSecretsManagerChangesAsync(Valid validatedResult, Organization organization, int? initialSmSeats) + private async Task RevertSecretsManagerChangesAsync(Valid validatedResult, Organization organization, int? initialSmSeats) { if (validatedResult.Value.SecretsManagerSubscriptionUpdate?.SmSeatsChanged is true) { @@ -189,7 +190,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, } } - private async Task PublishReferenceEventAsync(Valid validatedResult, + private async Task PublishReferenceEventAsync(Valid validatedResult, Organization organization) => await referenceEventService.RaiseEventAsync( new ReferenceEvent(ReferenceEventType.InvitedUsers, organization, currentContext) @@ -203,12 +204,12 @@ public class InviteOrganizationUsersCommand(IEventService eventService, users.Select(x => x.OrganizationUser), organization)); - private async Task SendAdditionalEmailsAsync(Valid validatedResult, Organization organization) + private async Task SendAdditionalEmailsAsync(Valid validatedResult, Organization organization) { await SendPasswordManagerMaxSeatLimitEmailsAsync(validatedResult, organization); } - private async Task SendPasswordManagerMaxSeatLimitEmailsAsync(Valid validatedResult, Organization organization) + private async Task SendPasswordManagerMaxSeatLimitEmailsAsync(Valid validatedResult, Organization organization) { if (!validatedResult.Value.PasswordManagerSubscriptionUpdate.MaxSeatsReached) { @@ -246,7 +247,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, .Select(u => u.Email).Distinct(); } - private async Task AdjustSecretsManagerSeatsAsync(Valid validatedResult) + private async Task AdjustSecretsManagerSeatsAsync(Valid validatedResult) { if (validatedResult.Value.SecretsManagerSubscriptionUpdate?.SmSeatsChanged is true) { @@ -255,7 +256,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, } - private async Task AdjustPasswordManagerSeatsAsync(Valid validatedResult, Organization organization) + private async Task AdjustPasswordManagerSeatsAsync(Valid validatedResult, Organization organization) { if (validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd <= 0) { diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs index cc0bd23b2a..ac7d864dd4 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs @@ -7,10 +7,10 @@ public class InviteOrganizationUsersResponse(Guid organizationId) public IEnumerable InvitedUsers { get; } = []; public Guid OrganizationId { get; } = organizationId; - public InviteOrganizationUsersResponse(InviteUserOrganizationValidationRequest validationRequest) - : this(validationRequest.InviteOrganization.OrganizationId) + public InviteOrganizationUsersResponse(InviteOrganizationUsersValidationRequest usersValidationRequest) + : this(usersValidationRequest.InviteOrganization.OrganizationId) { - InvitedUsers = validationRequest.Invites.Select(x => new OrganizationUser { Email = x.Email }); + InvitedUsers = usersValidationRequest.Invites.Select(x => new OrganizationUser { Email = x.Email }); } public InviteOrganizationUsersResponse(IEnumerable invitedOrganizationUsers, Guid organizationId) diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersValidationRequest.cs similarity index 81% rename from src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs rename to src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersValidationRequest.cs index e35b3f8628..f45c705cab 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersValidationRequest.cs @@ -4,13 +4,13 @@ using Bit.Core.Models.Business; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; -public class InviteUserOrganizationValidationRequest +public class InviteOrganizationUsersValidationRequest { - public InviteUserOrganizationValidationRequest() + public InviteOrganizationUsersValidationRequest() { } - public InviteUserOrganizationValidationRequest(InviteUserOrganizationValidationRequest request) + public InviteOrganizationUsersValidationRequest(InviteOrganizationUsersValidationRequest request) { Invites = request.Invites; InviteOrganization = request.InviteOrganization; @@ -20,7 +20,7 @@ public class InviteUserOrganizationValidationRequest OccupiedSmSeats = request.OccupiedSmSeats; } - public InviteUserOrganizationValidationRequest(InviteUserOrganizationValidationRequest request, + public InviteOrganizationUsersValidationRequest(InviteOrganizationUsersValidationRequest request, PasswordManagerSubscriptionUpdate subscriptionUpdate, SecretsManagerSubscriptionUpdate smSubscriptionUpdate) : this(request) diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs index e3f41d7c39..345d678fdb 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs @@ -1,5 +1,4 @@ using Bit.Core.AdminConsole.Errors; -using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager; using Bit.Core.AdminConsole.Shared.Validation; @@ -11,15 +10,15 @@ using OrganizationUserInvite = Bit.Core.AdminConsole.OrganizationFeatures.Organi namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation; -public interface IInviteUsersValidator : IValidator; +public interface IInviteUsersValidator : IValidator; -public class InviteUsersValidator( +public class InviteOrganizationUsersValidator( IOrganizationRepository organizationRepository, IInviteUsersPasswordManagerValidator inviteUsersPasswordManagerValidator, IUpdateSecretsManagerSubscriptionCommand secretsManagerSubscriptionCommand, IPaymentService paymentService) : IInviteUsersValidator { - public async Task> ValidateAsync(InviteUserOrganizationValidationRequest request) + public async Task> ValidateAsync(InviteOrganizationUsersValidationRequest request) { var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(request); @@ -34,7 +33,7 @@ public class InviteUsersValidator( // This is an expensive call, so we're doing it now to delay the check as long as possible. if (await paymentService.HasSecretsManagerStandalone(request.InviteOrganization)) { - request = new InviteUserOrganizationValidationRequest(request) + request = new InviteOrganizationUsersValidationRequest(request) { Invites = request.Invites .Select(x => new OrganizationUserInvite(x, accessSecretsManager: true)) @@ -47,14 +46,14 @@ public class InviteUsersValidator( return await ValidateSecretsManagerSubscriptionUpdateAsync(request, subscriptionUpdate); } - return new Valid(new InviteUserOrganizationValidationRequest( + return new Valid(new InviteOrganizationUsersValidationRequest( request, subscriptionUpdate, null)); } - private async Task> ValidateSecretsManagerSubscriptionUpdateAsync( - InviteUserOrganizationValidationRequest request, + private async Task> ValidateSecretsManagerSubscriptionUpdateAsync( + InviteOrganizationUsersValidationRequest request, PasswordManagerSubscriptionUpdate subscriptionUpdate) { try @@ -63,24 +62,24 @@ public class InviteUsersValidator( organization: await organizationRepository.GetByIdAsync(request.InviteOrganization.OrganizationId), plan: request.InviteOrganization.Plan, autoscaling: true) - .AdjustSeats(GetSecretManagerSeatAdjustment( - occupiedSeats: request.OccupiedSmSeats, - organization: request.InviteOrganization, - invitesToSend: request.Invites.Count(x => x.AccessSecretsManager))); + .AdjustSeats(GetSecretManagerSeatAdjustment(request)); await secretsManagerSubscriptionCommand.ValidateUpdateAsync(smSubscriptionUpdate); - return new Valid(new InviteUserOrganizationValidationRequest( + return new Valid(new InviteOrganizationUsersValidationRequest( request, subscriptionUpdate, smSubscriptionUpdate)); } catch (Exception ex) { - return new Invalid(new Error(ex.Message, request)); + return new Invalid(new Error(ex.Message, request)); } - int GetSecretManagerSeatAdjustment(int occupiedSeats, InviteOrganization organization, int invitesToSend) => - organization.SmSeats - (occupiedSeats + invitesToSend) ?? 0; + int GetSecretManagerSeatAdjustment(InviteOrganizationUsersValidationRequest request) => + Math.Abs( + request.InviteOrganization.SmSeats - + request.OccupiedSmSeats - + request.Invites.Count(x => x.AccessSecretsManager) ?? 0); } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/PasswordManager/PasswordManagerSubscriptionUpdate.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/PasswordManager/PasswordManagerSubscriptionUpdate.cs index cf499efa5e..f6126fd8f5 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/PasswordManager/PasswordManagerSubscriptionUpdate.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/PasswordManager/PasswordManagerSubscriptionUpdate.cs @@ -77,13 +77,13 @@ public class PasswordManagerSubscriptionUpdate inviteOrganization: inviteOrganization) { } - public PasswordManagerSubscriptionUpdate(InviteUserOrganizationValidationRequest validationRequest) : + public PasswordManagerSubscriptionUpdate(InviteOrganizationUsersValidationRequest usersValidationRequest) : this( - organizationSeats: validationRequest.InviteOrganization.Seats, - organizationAutoScaleSeatLimit: validationRequest.InviteOrganization.MaxAutoScaleSeats, - currentSeats: validationRequest.OccupiedPmSeats, - newUsersToAdd: validationRequest.Invites.Length, - plan: validationRequest.InviteOrganization.Plan.PasswordManager, - inviteOrganization: validationRequest.InviteOrganization) + organizationSeats: usersValidationRequest.InviteOrganization.Seats, + organizationAutoScaleSeatLimit: usersValidationRequest.InviteOrganization.MaxAutoScaleSeats, + currentSeats: usersValidationRequest.OccupiedPmSeats, + newUsersToAdd: usersValidationRequest.Invites.Length, + plan: usersValidationRequest.InviteOrganization.Plan.PasswordManager, + inviteOrganization: usersValidationRequest.InviteOrganization) { } } diff --git a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs index 9c0ed13669..c76345972a 100644 --- a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs +++ b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs @@ -183,7 +183,7 @@ public static class OrganizationServiceCollectionExtensions services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Helpers/InviteUserOrganizationValidationRequestHelpers.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Helpers/InviteUserOrganizationValidationRequestHelpers.cs index 4ffdfedc84..f4f7cd5662 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Helpers/InviteUserOrganizationValidationRequestHelpers.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Helpers/InviteUserOrganizationValidationRequestHelpers.cs @@ -8,7 +8,7 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.Invi public static class InviteUserOrganizationValidationRequestHelpers { - public static InviteUserOrganizationValidationRequest GetInviteValidationRequestMock(InviteOrganizationUsersRequest request, + public static InviteOrganizationUsersValidationRequest GetInviteValidationRequestMock(InviteOrganizationUsersRequest request, InviteOrganization inviteOrganization, Organization organization) => new() { @@ -23,7 +23,7 @@ public static class InviteUserOrganizationValidationRequestHelpers .AdjustSeats(request.Invites.Count(x => x.AccessSecretsManager)) }; - public static InviteUserOrganizationValidationRequest WithPasswordManagerUpdate(this InviteUserOrganizationValidationRequest request, PasswordManagerSubscriptionUpdate passwordManagerSubscriptionUpdate) => + public static InviteOrganizationUsersValidationRequest WithPasswordManagerUpdate(this InviteOrganizationUsersValidationRequest request, PasswordManagerSubscriptionUpdate passwordManagerSubscriptionUpdate) => new() { Invites = request.Invites, @@ -36,7 +36,7 @@ public static class InviteUserOrganizationValidationRequestHelpers SecretsManagerSubscriptionUpdate = request.SecretsManagerSubscriptionUpdate }; - public static InviteUserOrganizationValidationRequest WithSecretsManagerUpdate(this InviteUserOrganizationValidationRequest request, SecretsManagerSubscriptionUpdate secretsManagerSubscriptionUpdate) => + public static InviteOrganizationUsersValidationRequest WithSecretsManagerUpdate(this InviteOrganizationUsersValidationRequest request, SecretsManagerSubscriptionUpdate secretsManagerSubscriptionUpdate) => new() { Invites = request.Invites, diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs index 2b79bb7dd7..ba7605d682 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs @@ -72,8 +72,8 @@ public class InviteOrganizationUserCommandTests .Returns([user.Email]); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization))); + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization))); // Act var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); @@ -134,8 +134,8 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization))); + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization))); // Act var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); @@ -198,9 +198,9 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Invalid( - new Error(errorMessage, validationRequest))); + .ValidateAsync(Arg.Any()) + .Returns(new Invalid( + new Error(errorMessage, validationRequest))); // Act var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); @@ -268,8 +268,8 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) .WithPasswordManagerUpdate(new PasswordManagerSubscriptionUpdate(inviteOrganization, organization.Seats.Value, 1)))); // Act @@ -338,8 +338,8 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) .WithPasswordManagerUpdate(passwordManagerUpdate))); // Act @@ -414,8 +414,8 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) .WithSecretsManagerUpdate(secretsManagerSubscriptionUpdate))); // Act @@ -486,8 +486,8 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) .WithPasswordManagerUpdate(passwordManagerSubscriptionUpdate) .WithSecretsManagerUpdate(secretsManagerSubscriptionUpdate))); @@ -581,8 +581,8 @@ public class InviteOrganizationUserCommandTests .Returns(organization); sutProvider.GetDependency() - .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) + .ValidateAsync(Arg.Any()) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization, organization) .WithPasswordManagerUpdate(passwordManagerSubscriptionUpdate) .WithSecretsManagerUpdate(secretsManagerSubscriptionUpdate))); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUsersValidatorTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUsersValidatorTests.cs new file mode 100644 index 0000000000..fdc58cbdda --- /dev/null +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUsersValidatorTests.cs @@ -0,0 +1,66 @@ +using Bit.Core.AdminConsole.Entities; +using Bit.Core.AdminConsole.Models.Business; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation; +using Bit.Core.Billing.Models.StaticStore.Plans; +using Bit.Core.Models.Business; +using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using Xunit; +using OrganizationUserInvite = Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.OrganizationUserInvite; + +namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation; + +[SutProviderCustomize] +public class InviteOrganizationUsersValidatorTests +{ + [Theory] + [BitAutoData] + public async Task ValidateAsync_WhenOrganizationHasSecretsManagerInvites_ThenShouldCorrectlyCalculateSeatsToAdd( + Organization organization, + SutProvider sutProvider + ) + { + organization.Seats = null; + organization.SmSeats = 10; + organization.UseSecretsManager = true; + + var request = new InviteOrganizationUsersValidationRequest + { + Invites = + [ + new OrganizationUserInvite( + email: "test@email.com", + externalId: "test-external-id"), + new OrganizationUserInvite( + email: "test2@email.com", + externalId: "test-external-id2"), + new OrganizationUserInvite( + email: "test3@email.com", + externalId: "test-external-id3") + ], + InviteOrganization = new InviteOrganization(organization, new Enterprise2023Plan(true)), + OccupiedPmSeats = 0, + OccupiedSmSeats = 9 + }; + + sutProvider.GetDependency() + .HasSecretsManagerStandalone(request.InviteOrganization) + .Returns(true); + + sutProvider.GetDependency() + .GetByIdAsync(organization.Id) + .Returns(organization); + + _ = await sutProvider.Sut.ValidateAsync(request); + + sutProvider.GetDependency() + .Received(1) + .ValidateUpdateAsync(Arg.Is(x => + x.SmSeatsChanged == true && x.SmSeats == 12)); + } +}