From e10b7cc78f56b0ba1ee919602fb716c2973b667f Mon Sep 17 00:00:00 2001 From: jrmccannon Date: Fri, 21 Feb 2025 12:04:11 -0600 Subject: [PATCH] First test of new command. --- .../InviteOrganizationUsersCommand.cs | 5 + .../PasswordManagerSubscriptionUpdate.cs | 10 +- .../SecretsManagerSubscriptionUpdate.cs | 14 ++- .../InviteOrganizationUserCommandTests.cs | 93 +++++++++++++++++++ 4 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs index ff0cec3548..cd22ba00e8 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs @@ -73,6 +73,11 @@ public class InviteOrganizationUsersCommand(IEventService eventService, .Select(email => OrganizationUserInviteDto.Create(email, invite, request.Organization.OrganizationId)) ); + if (invitesToSend.Any() is false) + { + return new Success>([]); + } + // Validate we can add those seats var validationResult = await inviteUsersValidation.ValidateAsync(new InviteUserOrganizationValidationRequest { diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/PasswordManagerSubscriptionUpdate.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/PasswordManagerSubscriptionUpdate.cs index 34f0928858..16d2de0e10 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/PasswordManagerSubscriptionUpdate.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/PasswordManagerSubscriptionUpdate.cs @@ -50,9 +50,13 @@ public class PasswordManagerSubscriptionUpdate organizationDto.Plan.PasswordManager); } - public static PasswordManagerSubscriptionUpdate Create(InviteUserOrganizationValidationRequest refined) + public static PasswordManagerSubscriptionUpdate Create(InviteUserOrganizationValidationRequest validationRequest) { - return new PasswordManagerSubscriptionUpdate(refined.Organization.Seats, refined.Organization.MaxAutoScaleSeats, - refined.OccupiedPmSeats, refined.Invites.Length, refined.Organization.Plan.PasswordManager); + return new PasswordManagerSubscriptionUpdate( + validationRequest.Organization.Seats, + validationRequest.Organization.MaxAutoScaleSeats, + validationRequest.OccupiedPmSeats, + validationRequest.Invites.Length, + validationRequest.Organization.Plan.PasswordManager); } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/SecretsManagerSubscriptionUpdate.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/SecretsManagerSubscriptionUpdate.cs index b813e7fdd4..773585ea06 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/SecretsManagerSubscriptionUpdate.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Models/SecretsManagerSubscriptionUpdate.cs @@ -1,4 +1,5 @@ -using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; +using Bit.Core.AdminConsole.Models.Business; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.Models.StaticStore; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models; @@ -33,6 +34,17 @@ public class SecretsManagerSubscriptionUpdate SecretsManagerPlan = plan; } + public static SecretsManagerSubscriptionUpdate Create(OrganizationDto organizationDto, int occupiedSeats, int seatsToAdd, int passwordManagerSeatTotal) + { + return new SecretsManagerSubscriptionUpdate(organizationDto.UseSecretsManager, + organizationDto.SmSeats, + organizationDto.SmMaxAutoScaleSeats, + occupiedSeats, + seatsToAdd, + passwordManagerSeatTotal, + organizationDto.Plan.SecretsManager); + } + public static SecretsManagerSubscriptionUpdate Create(InviteUserOrganizationValidationRequest refined, PasswordManagerSubscriptionUpdate passwordManagerSubscriptionUpdate) { return new SecretsManagerSubscriptionUpdate(refined.Organization.UseSecretsManager, diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs new file mode 100644 index 0000000000..04d48f7b03 --- /dev/null +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs @@ -0,0 +1,93 @@ +using System.Net.Mail; +using Bit.Core.AdminConsole.Entities; +using Bit.Core.AdminConsole.Models.Business; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models; +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Models.Commands; +using Bit.Core.Models.Data; +using Bit.Core.Models.StaticStore; +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 Microsoft.Extensions.Time.Testing; +using NSubstitute; +using Xunit; + +namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; + +[SutProviderCustomize] +public class InviteOrganizationUserCommandTests +{ + [Theory] + [BitAutoData] + public async Task InviteScimOrganizationUserAsync_WhenEmailAlreadyExists_ThenNoInviteIsSentAndNoSeatsAreAdjusted( + MailAddress address, + Organization organization, + OrganizationUser user, + FakeTimeProvider timeProvider, + string externalId, + SutProvider sutProvider) + { + // Arrange + user.Email = address.Address; + + var organizationDto = OrganizationDto.FromOrganization(organization); + + var request = InviteScimOrganizationUserRequest.Create( + OrganizationUserSingleEmailInvite.Create( + user.Email, + [], + OrganizationUserType.User, + new Permissions(), + false), + organizationDto, + timeProvider.GetUtcNow(), + externalId + ); + + sutProvider.GetDependency() + .SelectKnownEmailsAsync(organization.Id, Arg.Any>(), false) + .Returns([user.Email]); + + var validationRequest = new InviteUserOrganizationValidationRequest + { + Invites = [], + Organization = organizationDto, + PerformedBy = Guid.Empty, + PerformedAt = request.PerformedAt, + OccupiedPmSeats = 0, + OccupiedSmSeats = 0, + PasswordManagerSubscriptionUpdate = PasswordManagerSubscriptionUpdate.Create(organizationDto, 0, 0), + SecretsManagerSubscriptionUpdate = SecretsManagerSubscriptionUpdate.Create(organizationDto, 0, 0, 0) + }; + + sutProvider.GetDependency() + .ValidateAsync(Arg.Any()) + .Returns(new Valid(validationRequest)); + + // Act + var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); + + // Assert + Assert.IsType>(result); + + sutProvider.GetDependency() + .DidNotReceiveWithAnyArgs() + .AdjustSeatsAsync(Arg.Any(), Arg.Any(), Arg.Any()); + + sutProvider.GetDependency() + .DidNotReceiveWithAnyArgs() + .SendInvitesAsync(Arg.Any()); + + sutProvider.GetDependency() + .DidNotReceiveWithAnyArgs() + .UpdateSubscriptionAsync(Arg.Any()); + } + +}