diff --git a/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs b/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs index 16911d9078..6446af81de 100644 --- a/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs +++ b/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs @@ -13,7 +13,8 @@ public class ScimUserRequestModel : BaseScimUserModel { public ScimUserRequestModel() : base(false) - { } + { + } public OrganizationUserInvite ToOrganizationUserInvite(ScimProviderType scimProvider) { @@ -28,7 +29,7 @@ public class ScimUserRequestModel : BaseScimUserModel }; } - public OrganizationUserSingleEmailInvite ToRequest( + public InviteOrganizationUsersRequest ToRequest( ScimProviderType scimProvider, InviteOrganization inviteOrganization, DateTimeOffset performedAt) @@ -40,11 +41,18 @@ public class ScimUserRequestModel : BaseScimUserModel throw new BadRequestException(); } - return new( - email: email, - inviteOrganization: inviteOrganization, - performedAt: performedAt, - externalId: ExternalIdForInvite()); + return new InviteOrganizationUsersRequest( + invites: + [ + new Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.OrganizationUserInvite( + email: email, + externalId: ExternalIdForInvite(), + accessSecretsManager: false // TODO do something about this + ) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, // SCIM does not have a user id + performedAt: performedAt); } private string EmailForInvite(ScimProviderType scimProvider) diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/IInviteOrganizationUsersCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/IInviteOrganizationUsersCommand.cs index 332991db49..e948f99a73 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/IInviteOrganizationUsersCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/IInviteOrganizationUsersCommand.cs @@ -19,5 +19,5 @@ public interface IInviteOrganizationUsersCommand /// /// Response from InviteScimOrganiation Task> InviteScimOrganizationUserAsync( - OrganizationUserSingleEmailInvite request); + InviteOrganizationUsersRequest request); } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs index 76c19edfb6..6831baca97 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUsersCommand.cs @@ -17,6 +17,7 @@ using Bit.Core.Tools.Models.Business; using Bit.Core.Tools.Services; using Microsoft.Extensions.Logging; using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.CreateOrganizationUser; +using OrganizationUserInvite = Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.OrganizationUserInvite; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; @@ -41,21 +42,23 @@ public class InviteOrganizationUsersCommand(IEventService eventService, public const string InvalidResultType = "Invalid result type."; - public async Task> InviteScimOrganizationUserAsync(OrganizationUserSingleEmailInvite request) + public async Task> InviteScimOrganizationUserAsync(InviteOrganizationUsersRequest request) { var hasSecretsManagerStandalone = await paymentService.HasSecretsManagerStandalone(request.InviteOrganization); + // Maybe move this all back up var orgUsers = await organizationUserRepository.GetManyDetailsByOrganizationAsync(request.InviteOrganization.OrganizationId); if (orgUsers.Any(existingUser => - request.Email.Equals(existingUser.Email, StringComparison.InvariantCultureIgnoreCase) || - request.ExternalId.Equals(existingUser.ExternalId, StringComparison.InvariantCultureIgnoreCase))) + request.Invites.First().Email.Equals(existingUser.Email, StringComparison.InvariantCultureIgnoreCase) || + request.Invites.First().ExternalId.Equals(existingUser.ExternalId, StringComparison.InvariantCultureIgnoreCase))) { return new Failure( new UserAlreadyExistsError(new ScimInviteOrganizationUsersResponse(request))); } + // end of move - var result = await InviteOrganizationUsersAsync(new InviteOrganizationUsersRequest(request, hasSecretsManagerStandalone)); + var result = await InviteOrganizationUsersAsync(request); switch (result) { @@ -83,15 +86,7 @@ public class InviteOrganizationUsersCommand(IEventService eventService, private async Task>> InviteOrganizationUsersAsync(InviteOrganizationUsersRequest request) { - var existingEmails = new HashSet(await organizationUserRepository.SelectKnownEmailsAsync( - request.InviteOrganization.OrganizationId, request.Invites.SelectMany(i => i.Emails), false), - StringComparer.InvariantCultureIgnoreCase); - - var invitesToSend = request.Invites - .SelectMany(invite => invite.Emails - .Where(email => !existingEmails.Contains(email)) - .Select(email => OrganizationUserInviteDto.Create(email, invite, request.InviteOrganization.OrganizationId)) - ).ToArray(); + var invitesToSend = (await FilterExistingUsersAsync(request)).ToArray(); if (invitesToSend.Length == 0) { @@ -116,10 +111,10 @@ public class InviteOrganizationUsersCommand(IEventService eventService, var validatedRequest = validationResult as Valid; var organizationUserToInviteEntities = invitesToSend - .Select(MapToDataModel(request.PerformedAt)) + .Select(MapToDataModel(request.PerformedAt, validatedRequest!.Value.InviteOrganization)) .ToArray(); - var organization = await organizationRepository.GetByIdAsync(validatedRequest!.Value.InviteOrganization.OrganizationId); + var organization = await organizationRepository.GetByIdAsync(validatedRequest.Value.InviteOrganization.OrganizationId); try { @@ -151,6 +146,17 @@ public class InviteOrganizationUsersCommand(IEventService eventService, return new Success>(organizationUserToInviteEntities.Select(x => x.OrganizationUser)); } + private async Task> FilterExistingUsersAsync(InviteOrganizationUsersRequest request) + { + var existingEmails = new HashSet(await organizationUserRepository.SelectKnownEmailsAsync( + request.InviteOrganization.OrganizationId, request.Invites.Select(i => i.Email), false), + StringComparer.InvariantCultureIgnoreCase); + + return request.Invites + .Where(invite => !existingEmails.Contains(invite.Email)) + .ToArray(); + } + private async Task RevertPasswordManagerChangesAsync(Valid validatedResult, Organization organization) { if (validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd > 0) diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/CreateOrganizationUser.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/CreateOrganizationUser.cs index 2fc40e37c3..d48188f56d 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/CreateOrganizationUser.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/CreateOrganizationUser.cs @@ -1,4 +1,5 @@ -using Bit.Core.Entities; +using Bit.Core.AdminConsole.Models.Business; +using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Models.Data; using Bit.Core.Utilities; @@ -11,13 +12,14 @@ public class CreateOrganizationUser public CollectionAccessSelection[] Collections { get; set; } = []; public Guid[] Groups { get; set; } = []; - public static Func MapToDataModel(DateTimeOffset performedAt) => + public static Func MapToDataModel(DateTimeOffset performedAt, + InviteOrganization organization) => o => new CreateOrganizationUser { OrganizationUser = new OrganizationUser { Id = CoreHelpers.GenerateComb(), - OrganizationId = o.OrganizationId, + OrganizationId = organization.OrganizationId, Email = o.Email.ToLowerInvariant(), Type = o.Type, Status = OrganizationUserStatusType.Invited, diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersRequest.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersRequest.cs index bdca690c2e..84b350c551 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersRequest.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersRequest.cs @@ -19,11 +19,4 @@ public class InviteOrganizationUsersRequest PerformedBy = performedBy; PerformedAt = performedAt; } - - public InviteOrganizationUsersRequest(OrganizationUserSingleEmailInvite request, bool hasStandaloneSecretsManager) : - this([OrganizationUserInvite.Create(request, hasStandaloneSecretsManager)], - request.InviteOrganization, - Guid.Empty, - request.PerformedAt) - { } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs index bbfa855ac8..23d25b6c59 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteOrganizationUsersResponse.cs @@ -16,12 +16,14 @@ public class ScimInviteOrganizationUsersResponse } - public ScimInviteOrganizationUsersResponse(OrganizationUserSingleEmailInvite request) + public ScimInviteOrganizationUsersResponse(InviteOrganizationUsersRequest request) { + var userToInvite = request.Invites.First(); + InvitedUser = new OrganizationUser { - Email = request.Email, - ExternalId = request.ExternalId + Email = userToInvite.Email, + ExternalId = userToInvite.ExternalId }; } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs index f24b32d318..733dd01bf4 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/InviteUserOrganizationValidationRequest.cs @@ -20,7 +20,7 @@ public class InviteUserOrganizationValidationRequest SecretsManagerSubscriptionUpdate = smSubscriptionUpdate; } - public OrganizationUserInviteDto[] Invites { get; init; } = []; + public OrganizationUserInvite[] Invites { get; init; } = []; public InviteOrganization InviteOrganization { get; init; } public Guid PerformedBy { get; init; } public DateTimeOffset PerformedAt { get; init; } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInvite.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInvite.cs index 08e7d5c2ad..c63c4598c4 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInvite.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInvite.cs @@ -9,55 +9,57 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUse public class OrganizationUserInvite { - public string[] Emails { get; private init; } = []; - public CollectionAccessSelection[] AssignedCollections { get; private init; } = []; - public OrganizationUserType Type { get; private init; } = OrganizationUserType.User; - public Permissions Permissions { get; private init; } = new(); - public string ExternalId { get; private init; } = string.Empty; + public string Email { get; private init; } + public CollectionAccessSelection[] AssignedCollections { get; private init; } + public OrganizationUserType Type { get; private init; } + public Permissions Permissions { get; private init; } + public string ExternalId { get; private init; } public bool AccessSecretsManager { get; private init; } - public Guid[] Groups { get; private init; } = []; + public Guid[] Groups { get; private init; } - public static OrganizationUserInvite Create(string[] emails, - IEnumerable accessibleCollections, + public OrganizationUserInvite(string email, string externalId, bool accessSecretsManager) : + this( + email: email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: accessSecretsManager) + { + } + + public OrganizationUserInvite(string email, + IEnumerable assignedCollections, + IEnumerable groups, OrganizationUserType type, Permissions permissions, string externalId, bool accessSecretsManager) { - ValidateEmailAddresses(emails); + ValidateEmailAddress(email); - if (accessibleCollections?.Any(ValidateCollectionConfiguration) ?? false) + var collections = assignedCollections?.ToArray() ?? []; + + if (collections.Any(ValidateCollectionConfiguration)) { throw new BadRequestException(InvalidCollectionConfigurationErrorMessage); } - return new OrganizationUserInvite - { - Emails = emails, - AssignedCollections = accessibleCollections.ToArray(), - Type = type, - Permissions = permissions, - ExternalId = externalId, - AccessSecretsManager = accessSecretsManager - }; + Email = email; + AssignedCollections = collections; + Groups = groups.ToArray(); + Type = type; + Permissions = permissions ?? new Permissions(); + ExternalId = externalId; + AccessSecretsManager = accessSecretsManager; } - public static OrganizationUserInvite Create(OrganizationUserSingleEmailInvite invite, bool hasStandaloneSecretsManager) => - Create([invite.Email], - invite.AccessibleCollections, - invite.Type, - invite.Permissions, - invite.ExternalId, - hasStandaloneSecretsManager); - - private static void ValidateEmailAddresses(string[] emails) + private static void ValidateEmailAddress(string email) { - foreach (var email in emails) + if (!email.IsValidEmail()) { - if (!email.IsValidEmail()) - { - throw new BadRequestException($"{email} {InvalidEmailErrorMessage}"); - } + throw new BadRequestException($"{email} {InvalidEmailErrorMessage}"); } } } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInviteDto.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInviteDto.cs deleted file mode 100644 index 2f50225a66..0000000000 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserInviteDto.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Bit.Core.Enums; -using Bit.Core.Models.Data; - -namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; - -public class OrganizationUserInviteDto -{ - public string Email { get; private init; } = string.Empty; - public CollectionAccessSelection[] AssignedCollections { get; private init; } = []; - public string ExternalId { get; private init; } = string.Empty; - public Permissions Permissions { get; private init; } = new(); - public OrganizationUserType Type { get; private init; } = OrganizationUserType.User; - public bool AccessSecretsManager { get; private init; } - public Guid OrganizationId { get; private init; } = Guid.Empty; - public Guid[] Groups { get; private init; } = []; - - public static OrganizationUserInviteDto Create(string email, OrganizationUserInvite invite, Guid organizationId) - { - return new OrganizationUserInviteDto - { - Email = email, - AssignedCollections = invite.AssignedCollections, - ExternalId = invite.ExternalId, - Type = invite.Type, - Permissions = invite.Permissions, - AccessSecretsManager = invite.AccessSecretsManager, - OrganizationId = organizationId, - Groups = invite.Groups - }; - } -} diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserSingleEmailInvite.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserSingleEmailInvite.cs deleted file mode 100644 index c2ff0add59..0000000000 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Models/OrganizationUserSingleEmailInvite.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Bit.Core.AdminConsole.Models.Business; -using Bit.Core.Enums; -using Bit.Core.Exceptions; -using Bit.Core.Models.Data; -using Bit.Core.Utilities; -using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.InviteOrganizationUserErrorMessages; -using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.InviteOrganizationUserFunctions; - -namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; - -public record OrganizationUserSingleEmailInvite -{ - public string Email { get; init; } = string.Empty; - public CollectionAccessSelection[] AccessibleCollections { get; init; } = []; - public Permissions Permissions { get; init; } = new(); - public OrganizationUserType Type { get; init; } = OrganizationUserType.User; - public InviteOrganization InviteOrganization { get; private init; } - public DateTimeOffset PerformedAt { get; private init; } - public string ExternalId { get; private init; } = string.Empty; - - public OrganizationUserSingleEmailInvite(string email, - InviteOrganization inviteOrganization, - DateTimeOffset performedAt, - string externalId) : this( - email: email, - accessibleCollections: [], - type: OrganizationUserType.User, - permissions: new Permissions()) - { - InviteOrganization = inviteOrganization; - PerformedAt = performedAt; - ExternalId = externalId; - } - - public OrganizationUserSingleEmailInvite(string email, - IEnumerable accessibleCollections, - OrganizationUserType type, - Permissions permissions) - { - if (!email.IsValidEmail()) - { - throw new BadRequestException(InvalidEmailErrorMessage); - } - - if (accessibleCollections?.Any(ValidateCollectionConfiguration) ?? false) - { - throw new BadRequestException(InvalidCollectionConfigurationErrorMessage); - } - - Email = email; - AccessibleCollections = accessibleCollections.ToArray(); - Type = type; - Permissions = permissions; - } -} diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserFunctions.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserFunctions.cs index f689fe0757..2d97a25721 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserFunctions.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserFunctions.cs @@ -4,6 +4,9 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUse public static class InviteOrganizationUserFunctions { + /// + /// This + /// public static Func ValidateCollectionConfiguration => collectionAccessSelection => collectionAccessSelection.Manage && (collectionAccessSelection.ReadOnly || collectionAccessSelection.HidePasswords); } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs index 6e52321460..00568c9c31 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteOrganizationUserValidator.cs @@ -25,13 +25,6 @@ public class InviteUsersValidator( { public async Task> ValidateAsync(InviteUserOrganizationValidationRequest request) { - var organizationValidationResult = InviteUserOrganizationValidator.Validate(request.InviteOrganization); - - if (organizationValidationResult is Invalid organizationValidation) - { - return organizationValidation.Map(request); - } - var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(request); var passwordManagerValidationResult = PasswordManagerInviteUserValidator.Validate(subscriptionUpdate); @@ -45,6 +38,13 @@ public class InviteUsersValidator( return invalidEnvironment.Map(request); } + var organizationValidationResult = InviteUserOrganizationValidator.Validate(request.InviteOrganization, passwordManagerValidationResult as Valid); + + if (organizationValidationResult is Invalid organizationValidation) + { + return organizationValidation.Map(request); + } + var smSubscriptionUpdate = new SecretsManagerSubscriptionUpdate(request, subscriptionUpdate); var secretsManagerValidationResult = SecretsManagerInviteUserValidation.Validate(smSubscriptionUpdate); diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Organization/InviteUserOrganizationValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Organization/InviteUserOrganizationValidator.cs index c169c97b7b..9256a80059 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Organization/InviteUserOrganizationValidator.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/Organization/InviteUserOrganizationValidator.cs @@ -1,13 +1,15 @@ using Bit.Core.AdminConsole.Models.Business; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager; using Bit.Core.AdminConsole.Shared.Validation; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Organization; public static class InviteUserOrganizationValidator { - public static ValidationResult Validate(InviteOrganization inviteOrganization) + public static ValidationResult Validate(InviteOrganization inviteOrganization, + Valid passwordManagerValidationResult) { - if (inviteOrganization.Seats is null) + if (inviteOrganization.Seats is null || passwordManagerValidationResult.Value.SeatsRequiredToAdd is 0) { return new Valid(inviteOrganization); } diff --git a/test/Core.Test/AdminConsole/Models/InviteOrganizationUserRequestTests.cs b/test/Core.Test/AdminConsole/Models/InviteOrganizationUserRequestTests.cs deleted file mode 100644 index 32dc219fd3..0000000000 --- a/test/Core.Test/AdminConsole/Models/InviteOrganizationUserRequestTests.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; -using Bit.Core.Enums; -using Bit.Core.Exceptions; -using Bit.Core.Models.Data; -using Bit.Test.Common.AutoFixture.Attributes; -using Xunit; -using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.InviteOrganizationUserErrorMessages; - -namespace Bit.Core.Test.AdminConsole.Models; - -public class InviteOrganizationUserRequestTests -{ - [Theory] - [BitAutoData] - public void Create_WhenPassedInvalidEmail_ThrowsException(string email, OrganizationUserType type, Permissions permissions) - { - var action = () => new OrganizationUserSingleEmailInvite(email, [], type, permissions); - - var exception = Assert.Throws(action); - - Assert.Equal(InvalidEmailErrorMessage, exception.Message); - } - - [Theory] - [BitAutoData] - public void Create_WhenPassedInvalidCollectionAccessConfiguration_ThrowsException(OrganizationUserType type, Permissions permissions) - { - var validEmail = "test@email.com"; - - var invalidCollectionConfiguration = new CollectionAccessSelection { Manage = true, HidePasswords = true }; - - var action = () => new OrganizationUserSingleEmailInvite(validEmail, [invalidCollectionConfiguration], type, permissions); - - var exception = Assert.Throws(action); - - Assert.Equal(InvalidCollectionConfigurationErrorMessage, exception.Message); - } - - [Theory] - [BitAutoData] - public void Create_WhenPassedValidArguments_ReturnsInvite(OrganizationUserType type, Permissions permissions) - { - const string validEmail = "test@email.com"; - var validCollectionConfiguration = new CollectionAccessSelection { Id = Guid.NewGuid(), Manage = true }; - - var invite = new OrganizationUserSingleEmailInvite(validEmail, [validCollectionConfiguration], type, permissions); - - Assert.NotNull(invite); - Assert.Equal(validEmail, invite.Email); - Assert.Contains(validCollectionConfiguration, invite.AccessibleCollections); - } -} diff --git a/test/Core.Test/AdminConsole/Models/InviteOrganizationUsersRequestTests.cs b/test/Core.Test/AdminConsole/Models/InviteOrganizationUsersRequestTests.cs index a08ecd0f84..71b2b9766c 100644 --- a/test/Core.Test/AdminConsole/Models/InviteOrganizationUsersRequestTests.cs +++ b/test/Core.Test/AdminConsole/Models/InviteOrganizationUsersRequestTests.cs @@ -13,17 +13,16 @@ public class InviteOrganizationUsersRequestTests { [Theory] [BitAutoData] - public void Create_WhenPassedInvalidEmails_ThrowsException(string[] emails, OrganizationUserType type, Permissions permissions, string externalId) + public void Constructor_WhenPassedInvalidEmail_ThrowsException(string email, OrganizationUserType type, Permissions permissions, string externalId) { - var action = () => OrganizationUserInvite.Create(emails, [], type, permissions, externalId, false); - - var exception = Assert.Throws(action); + var exception = Assert.Throws(() => + new OrganizationUserInvite(email, [], [], type, permissions, externalId, false)); Assert.Contains(InvalidEmailErrorMessage, exception.Message); } [Fact] - public void Create_WhenPassedInvalidCollectionAccessConfiguration_ThrowsException() + public void Constructor_WhenPassedInvalidCollectionAccessConfiguration_ThrowsException() { const string validEmail = "test@email.com"; @@ -33,23 +32,36 @@ public class InviteOrganizationUsersRequestTests HidePasswords = true }; - var action = () => OrganizationUserInvite.Create([validEmail], [invalidCollectionConfiguration], default, default, default, false); - - var exception = Assert.Throws(action); + var exception = Assert.Throws(() => + new OrganizationUserInvite( + email: validEmail, + assignedCollections: [invalidCollectionConfiguration], + groups: [], + type: default, + permissions: new Permissions(), + externalId: string.Empty, + accessSecretsManager: false)); Assert.Equal(InvalidCollectionConfigurationErrorMessage, exception.Message); } [Fact] - public void Create_WhenPassedValidArguments_ReturnsInvite() + public void Constructor_WhenPassedValidArguments_ReturnsInvite() { const string validEmail = "test@email.com"; var validCollectionConfiguration = new CollectionAccessSelection { Id = Guid.NewGuid(), Manage = true }; - var invite = OrganizationUserInvite.Create([validEmail], [validCollectionConfiguration], default, default, default, false); + var invite = new OrganizationUserInvite( + email: validEmail, + assignedCollections: [validCollectionConfiguration], + groups: [], + type: default, + permissions: null, + externalId: null, + accessSecretsManager: false); Assert.NotNull(invite); - Assert.Contains(validEmail, invite.Emails); + Assert.Contains(validEmail, invite.Email); Assert.Contains(validCollectionConfiguration, invite.AssignedCollections); } } 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 b4e2a4ca96..e58e5a9026 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Helpers/InviteUserOrganizationValidationRequestHelpers.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Helpers/InviteUserOrganizationValidationRequestHelpers.cs @@ -7,15 +7,11 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.Invi public static class InviteUserOrganizationValidationRequestHelpers { - public static InviteUserOrganizationValidationRequest GetInviteValidationRequestMock(OrganizationUserSingleEmailInvite request, + public static InviteUserOrganizationValidationRequest GetInviteValidationRequestMock(InviteOrganizationUsersRequest request, InviteOrganization inviteOrganization) => new() { - Invites = - [ - OrganizationUserInviteDto.Create(request.Email, - OrganizationUserInvite.Create(request, inviteOrganization.UseSecretsManager), inviteOrganization.OrganizationId) - ], + Invites = request.Invites, InviteOrganization = inviteOrganization, PerformedBy = Guid.Empty, PerformedAt = request.PerformedAt, diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs index dcd1fc012f..1008370206 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/InviteOrganizationUserCommandTests.cs @@ -12,6 +12,7 @@ using Bit.Core.Billing.Models.StaticStore.Plans; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Models.Commands; +using Bit.Core.Models.Data; using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.StaticStore; using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface; @@ -42,12 +43,22 @@ public class InviteOrganizationUserCommandTests // Arrange user.Email = address.Address; - var organizationDto = new InviteOrganization(organization, new FreePlan()); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); - var request = new OrganizationUserSingleEmailInvite(user.Email, - organizationDto, - timeProvider.GetUtcNow(), - externalId); + var request = new InviteOrganizationUsersRequest( + invites: [ + new OrganizationUserInvite( + email: user.Email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: true) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, + timeProvider.GetUtcNow()); sutProvider.GetDependency() .SelectKnownEmailsAsync(organization.Id, Arg.Any>(), false) @@ -55,7 +66,7 @@ public class InviteOrganizationUserCommandTests sutProvider.GetDependency() .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, organizationDto))); + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization))); // Act var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); @@ -90,12 +101,22 @@ public class InviteOrganizationUserCommandTests // Arrange orgUser.Email = address.Address; - var organizationDto = new InviteOrganization(organization, new FreePlan()); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); - var request = new OrganizationUserSingleEmailInvite(orgUser.Email, - organizationDto, - timeProvider.GetUtcNow(), - externalId); + var request = new InviteOrganizationUsersRequest( + invites: [ + new OrganizationUserInvite( + email: orgUser.Email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: true) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, + timeProvider.GetUtcNow()); sutProvider.GetDependency() .SelectKnownEmailsAsync(organization.Id, Arg.Any>(), false) @@ -107,7 +128,7 @@ public class InviteOrganizationUserCommandTests sutProvider.GetDependency() .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, organizationDto))); + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization))); // Act var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); @@ -118,7 +139,7 @@ public class InviteOrganizationUserCommandTests await sutProvider.GetDependency() .Received(1) .CreateManyAsync(Arg.Is>(users => - users.Any(user => user.OrganizationUser.Email == request.Email))); + users.Any(user => user.OrganizationUser.Email == request.Invites.First().Email))); await sutProvider.GetDependency() .Received(1) @@ -142,12 +163,22 @@ public class InviteOrganizationUserCommandTests user.Email = address.Address; - var organizationDto = new InviteOrganization(organization, new FreePlan()); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); - var request = new OrganizationUserSingleEmailInvite(user.Email, - organizationDto, - timeProvider.GetUtcNow(), - externalId); + var request = new InviteOrganizationUsersRequest( + invites: [ + new OrganizationUserInvite( + email: user.Email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: true) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, + timeProvider.GetUtcNow()); sutProvider.GetDependency() .SelectKnownEmailsAsync(organization.Id, Arg.Any>(), false) @@ -196,20 +227,30 @@ public class InviteOrganizationUserCommandTests organization.MaxAutoscaleSeats = 2; ownerDetails.Type = OrganizationUserType.Owner; - var organizationDto = new InviteOrganization(organization, new FreePlan()); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); - var request = new OrganizationUserSingleEmailInvite(user.Email, - organizationDto, - timeProvider.GetUtcNow(), - externalId); + var request = new InviteOrganizationUsersRequest( + invites: [ + new OrganizationUserInvite( + email: user.Email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: true) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, + timeProvider.GetUtcNow()); var orgUserRepository = sutProvider.GetDependency(); orgUserRepository - .SelectKnownEmailsAsync(organizationDto.OrganizationId, Arg.Any>(), false) + .SelectKnownEmailsAsync(inviteOrganization.OrganizationId, Arg.Any>(), false) .Returns([]); orgUserRepository - .GetManyByMinimumRoleAsync(organizationDto.OrganizationId, OrganizationUserType.Owner) + .GetManyByMinimumRoleAsync(inviteOrganization.OrganizationId, OrganizationUserType.Owner) .Returns([ownerDetails]); sutProvider.GetDependency() @@ -218,8 +259,8 @@ public class InviteOrganizationUserCommandTests sutProvider.GetDependency() .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, organizationDto) - .WithPasswordManagerUpdate(new PasswordManagerSubscriptionUpdate(organizationDto, organization.Seats.Value, 1)))); + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization) + .WithPasswordManagerUpdate(new PasswordManagerSubscriptionUpdate(inviteOrganization, organization.Seats.Value, 1)))); // Act var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request); @@ -227,12 +268,12 @@ public class InviteOrganizationUserCommandTests // Assert Assert.IsType>(result); - Assert.NotNull(organizationDto.MaxAutoScaleSeats); + Assert.NotNull(inviteOrganization.MaxAutoScaleSeats); await sutProvider.GetDependency() .Received(1) .SendOrganizationMaxSeatLimitReachedEmailAsync(organization, - organizationDto.MaxAutoScaleSeats.Value, + inviteOrganization.MaxAutoScaleSeats.Value, Arg.Is>(emails => emails.Any(email => email == ownerDetails.Email))); } @@ -253,22 +294,32 @@ public class InviteOrganizationUserCommandTests organization.MaxAutoscaleSeats = 2; ownerDetails.Type = OrganizationUserType.Owner; - var organizationDto = new InviteOrganization(organization, new FreePlan()); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); - var request = new OrganizationUserSingleEmailInvite(user.Email, - organizationDto, - timeProvider.GetUtcNow(), - externalId); + var request = new InviteOrganizationUsersRequest( + invites: [ + new OrganizationUserInvite( + email: user.Email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: true) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, + timeProvider.GetUtcNow()); - var passwordManagerUpdate = new PasswordManagerSubscriptionUpdate(organizationDto, organization.Seats.Value, 1); + var passwordManagerUpdate = new PasswordManagerSubscriptionUpdate(inviteOrganization, organization.Seats.Value, 1); var orgUserRepository = sutProvider.GetDependency(); orgUserRepository - .SelectKnownEmailsAsync(organizationDto.OrganizationId, Arg.Any>(), false) + .SelectKnownEmailsAsync(inviteOrganization.OrganizationId, Arg.Any>(), false) .Returns([]); orgUserRepository - .GetManyByMinimumRoleAsync(organizationDto.OrganizationId, OrganizationUserType.Owner) + .GetManyByMinimumRoleAsync(inviteOrganization.OrganizationId, OrganizationUserType.Owner) .Returns([ownerDetails]); var orgRepository = sutProvider.GetDependency(); @@ -278,7 +329,7 @@ public class InviteOrganizationUserCommandTests sutProvider.GetDependency() .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, organizationDto) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization) .WithPasswordManagerUpdate(passwordManagerUpdate))); // Act @@ -288,7 +339,7 @@ public class InviteOrganizationUserCommandTests Assert.IsType>(result); await sutProvider.GetDependency() - .AdjustSeatsAsync(organization, organizationDto.Plan, passwordManagerUpdate.SeatsRequiredToAdd); + .AdjustSeatsAsync(organization, inviteOrganization.Plan, passwordManagerUpdate.SeatsRequiredToAdd); await orgRepository.Received(1).ReplaceAsync(Arg.Is(x => x.Seats == passwordManagerUpdate.UpdatedSeatTotal)); @@ -315,15 +366,25 @@ public class InviteOrganizationUserCommandTests organization.MaxAutoscaleSeats = 2; ownerDetails.Type = OrganizationUserType.Owner; - var organizationDto = new InviteOrganization(organization, new FreePlan()); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); - var request = new OrganizationUserSingleEmailInvite(user.Email, - organizationDto, - timeProvider.GetUtcNow(), - externalId); + var request = new InviteOrganizationUsersRequest( + invites: [ + new OrganizationUserInvite( + email: user.Email, + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: externalId, + accessSecretsManager: true) + ], + inviteOrganization: inviteOrganization, + performedBy: Guid.Empty, + timeProvider.GetUtcNow()); var secretsManagerSubscriptionUpdate = new SecretsManagerSubscriptionUpdate( - organizationDto, + inviteOrganization, organization.SmSeats.Value, 1, organization.Seats.Value); @@ -331,10 +392,10 @@ public class InviteOrganizationUserCommandTests var orgUserRepository = sutProvider.GetDependency(); orgUserRepository - .SelectKnownEmailsAsync(organizationDto.OrganizationId, Arg.Any>(), false) + .SelectKnownEmailsAsync(inviteOrganization.OrganizationId, Arg.Any>(), false) .Returns([]); orgUserRepository - .GetManyByMinimumRoleAsync(organizationDto.OrganizationId, OrganizationUserType.Owner) + .GetManyByMinimumRoleAsync(inviteOrganization.OrganizationId, OrganizationUserType.Owner) .Returns([ownerDetails]); var orgRepository = sutProvider.GetDependency(); @@ -344,7 +405,7 @@ public class InviteOrganizationUserCommandTests sutProvider.GetDependency() .ValidateAsync(Arg.Any()) - .Returns(new Valid(GetInviteValidationRequestMock(request, organizationDto) + .Returns(new Valid(GetInviteValidationRequestMock(request, inviteOrganization) .WithSecretsManagerUpdate(secretsManagerSubscriptionUpdate))); // Act diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteUserOrganizationValidationTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteUserOrganizationValidationTests.cs index 11b6e2c331..0aa6b55695 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteUserOrganizationValidationTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/InviteUserOrganizationValidationTests.cs @@ -1,6 +1,7 @@ using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Organization; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager; using Bit.Core.AdminConsole.Shared.Validation; using Bit.Core.Billing.Models.StaticStore.Plans; using Bit.Test.Common.AutoFixture.Attributes; @@ -14,7 +15,11 @@ public class InviteUserOrganizationValidationTests [BitAutoData] public void Validate_WhenOrganizationIsFreeTier_ShouldReturnValidResponse(Organization organization) { - var result = InviteUserOrganizationValidator.Validate(new InviteOrganization(organization, new FreePlan())); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); + var validSubscriptionUpdate = new Valid( + new PasswordManagerSubscriptionUpdate(inviteOrganization, 0, 0)); + + var result = InviteUserOrganizationValidator.Validate(inviteOrganization, validSubscriptionUpdate); Assert.IsType>(result); } @@ -25,8 +30,13 @@ public class InviteUserOrganizationValidationTests Organization organization) { organization.GatewayCustomerId = string.Empty; + organization.Seats = 3; - var result = InviteUserOrganizationValidator.Validate(new InviteOrganization(organization, new FreePlan())); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); + var validSubscriptionUpdate = new Valid( + new PasswordManagerSubscriptionUpdate(inviteOrganization, 3, 1)); + + var result = InviteUserOrganizationValidator.Validate(inviteOrganization, validSubscriptionUpdate); Assert.IsType>(result); Assert.Equal(OrganizationNoPaymentMethodFoundError.Code, (result as Invalid)!.ErrorMessageString); @@ -38,8 +48,14 @@ public class InviteUserOrganizationValidationTests Organization organization) { organization.GatewaySubscriptionId = string.Empty; + organization.Seats = 3; + organization.MaxAutoscaleSeats = 4; - var result = InviteUserOrganizationValidator.Validate(new InviteOrganization(organization, new FreePlan())); + var inviteOrganization = new InviteOrganization(organization, new FreePlan()); + var validSubscriptionUpdate = new Valid( + new PasswordManagerSubscriptionUpdate(inviteOrganization, 3, 1)); + + var result = InviteUserOrganizationValidator.Validate(inviteOrganization, validSubscriptionUpdate); Assert.IsType>(result); Assert.Equal(OrganizationNoSubscriptionFoundError.Code, (result as Invalid)!.ErrorMessageString); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/SecretsManagerInviteUserValidationTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/SecretsManagerInviteUserValidationTests.cs index 370b6e75f7..0240f43348 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/SecretsManagerInviteUserValidationTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/InviteUsers/Validation/SecretsManagerInviteUserValidationTests.cs @@ -28,7 +28,7 @@ public class SecretsManagerInviteUserValidationTests var request = new InviteUserOrganizationValidationRequest { - Invites = [new OrganizationUserInviteDto()], + Invites = [new OrganizationUserInvite("test@email.com", "", false)], InviteOrganization = organizationDto, PerformedBy = Guid.Empty, PerformedAt = default, @@ -53,11 +53,18 @@ public class SecretsManagerInviteUserValidationTests var organizationDto = new InviteOrganization(organization, new FreePlan()); var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(organizationDto, 0, 0); - var invite = OrganizationUserInvite.Create(["email@test.com"], [], OrganizationUserType.User, new Permissions(), string.Empty, true); + var invite = new OrganizationUserInvite( + email: "email@test.com", + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: string.Empty, + accessSecretsManager: true); var request = new InviteUserOrganizationValidationRequest { - Invites = [OrganizationUserInviteDto.Create(invite.Emails.First(), invite, organizationDto.OrganizationId)], + Invites = [invite], InviteOrganization = organizationDto, PerformedBy = Guid.Empty, PerformedAt = default, @@ -86,7 +93,14 @@ public class SecretsManagerInviteUserValidationTests var request = new InviteUserOrganizationValidationRequest { - Invites = [new OrganizationUserInviteDto()], + Invites = [new OrganizationUserInvite( + email: "email@test.com", + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: string.Empty, + accessSecretsManager: true)], InviteOrganization = organizationDto, PerformedBy = Guid.Empty, PerformedAt = default, @@ -116,7 +130,14 @@ public class SecretsManagerInviteUserValidationTests var request = new InviteUserOrganizationValidationRequest { - Invites = [OrganizationUserInviteDto.Create("email@test.com", OrganizationUserInvite.Create(["email@test.com"], [], OrganizationUserType.User, new Permissions(), string.Empty, true), organization.Id)], + Invites = [new OrganizationUserInvite( + email: "email@test.com", + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: string.Empty, + accessSecretsManager: true)], InviteOrganization = organizationDto, PerformedBy = Guid.Empty, PerformedAt = default, @@ -137,18 +158,26 @@ public class SecretsManagerInviteUserValidationTests public void Validate_GivenPasswordManagerSeatsAreTheSameAsSecretsManagerSeats_WhenAttemptingToAddASecretManagerSeatOnly_ThenShouldNotBeAllowedToAddSecretsManagerUsers( Organization organization) { + organization.Seats = 0; organization.SmSeats = 4; organization.MaxAutoscaleSmSeats = 5; organization.UseSecretsManager = true; organization.PlanType = PlanType.EnterpriseAnnually; - var organizationDto = new InviteOrganization(organization, new Enterprise2023Plan(isAnnual: true)); - var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(organizationDto, 0, 0); + var inviteOrganization = new InviteOrganization(organization, new Enterprise2023Plan(isAnnual: true)); + var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(inviteOrganization, 0, 0); var request = new InviteUserOrganizationValidationRequest { - Invites = [OrganizationUserInviteDto.Create("email@test.com", OrganizationUserInvite.Create(["email@test.com"], [], OrganizationUserType.User, new Permissions(), string.Empty, true), organization.Id)], - InviteOrganization = organizationDto, + Invites = [new OrganizationUserInvite( + email: "email@test.com", + assignedCollections: [], + groups: [], + type: OrganizationUserType.User, + permissions: new Permissions(), + externalId: string.Empty, + accessSecretsManager: true)], + InviteOrganization = inviteOrganization, PerformedBy = Guid.Empty, PerformedAt = default, OccupiedPmSeats = 0,