1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

Cleaned up DTO models. Moved some validation steps around. A few quick fixes to address CR concerns. Still need to move a few things yet.

This commit is contained in:
jrmccannon
2025-03-26 10:56:33 -05:00
parent f3f2f41cfb
commit ad3131f66e
19 changed files with 288 additions and 294 deletions

View File

@ -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<BadRequestException>(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<BadRequestException>(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);
}
}

View File

@ -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<BadRequestException>(action);
var exception = Assert.Throws<BadRequestException>(() =>
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<BadRequestException>(action);
var exception = Assert.Throws<BadRequestException>(() =>
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);
}
}

View File

@ -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,

View File

@ -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<IOrganizationUserRepository>()
.SelectKnownEmailsAsync(organization.Id, Arg.Any<IEnumerable<string>>(), false)
@ -55,7 +66,7 @@ public class InviteOrganizationUserCommandTests
sutProvider.GetDependency<IInviteUsersValidator>()
.ValidateAsync(Arg.Any<InviteUserOrganizationValidationRequest>())
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, organizationDto)));
.Returns(new Valid<InviteUserOrganizationValidationRequest>(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<IOrganizationUserRepository>()
.SelectKnownEmailsAsync(organization.Id, Arg.Any<IEnumerable<string>>(), false)
@ -107,7 +128,7 @@ public class InviteOrganizationUserCommandTests
sutProvider.GetDependency<IInviteUsersValidator>()
.ValidateAsync(Arg.Any<InviteUserOrganizationValidationRequest>())
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, organizationDto)));
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, inviteOrganization)));
// Act
var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request);
@ -118,7 +139,7 @@ public class InviteOrganizationUserCommandTests
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.CreateManyAsync(Arg.Is<IEnumerable<CreateOrganizationUser>>(users =>
users.Any(user => user.OrganizationUser.Email == request.Email)));
users.Any(user => user.OrganizationUser.Email == request.Invites.First().Email)));
await sutProvider.GetDependency<ISendOrganizationInvitesCommand>()
.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<IOrganizationUserRepository>()
.SelectKnownEmailsAsync(organization.Id, Arg.Any<IEnumerable<string>>(), 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<IOrganizationUserRepository>();
orgUserRepository
.SelectKnownEmailsAsync(organizationDto.OrganizationId, Arg.Any<IEnumerable<string>>(), false)
.SelectKnownEmailsAsync(inviteOrganization.OrganizationId, Arg.Any<IEnumerable<string>>(), false)
.Returns([]);
orgUserRepository
.GetManyByMinimumRoleAsync(organizationDto.OrganizationId, OrganizationUserType.Owner)
.GetManyByMinimumRoleAsync(inviteOrganization.OrganizationId, OrganizationUserType.Owner)
.Returns([ownerDetails]);
sutProvider.GetDependency<IOrganizationRepository>()
@ -218,8 +259,8 @@ public class InviteOrganizationUserCommandTests
sutProvider.GetDependency<IInviteUsersValidator>()
.ValidateAsync(Arg.Any<InviteUserOrganizationValidationRequest>())
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, organizationDto)
.WithPasswordManagerUpdate(new PasswordManagerSubscriptionUpdate(organizationDto, organization.Seats.Value, 1))));
.Returns(new Valid<InviteUserOrganizationValidationRequest>(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<Success<ScimInviteOrganizationUsersResponse>>(result);
Assert.NotNull(organizationDto.MaxAutoScaleSeats);
Assert.NotNull(inviteOrganization.MaxAutoScaleSeats);
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendOrganizationMaxSeatLimitReachedEmailAsync(organization,
organizationDto.MaxAutoScaleSeats.Value,
inviteOrganization.MaxAutoScaleSeats.Value,
Arg.Is<IEnumerable<string>>(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<IOrganizationUserRepository>();
orgUserRepository
.SelectKnownEmailsAsync(organizationDto.OrganizationId, Arg.Any<IEnumerable<string>>(), false)
.SelectKnownEmailsAsync(inviteOrganization.OrganizationId, Arg.Any<IEnumerable<string>>(), false)
.Returns([]);
orgUserRepository
.GetManyByMinimumRoleAsync(organizationDto.OrganizationId, OrganizationUserType.Owner)
.GetManyByMinimumRoleAsync(inviteOrganization.OrganizationId, OrganizationUserType.Owner)
.Returns([ownerDetails]);
var orgRepository = sutProvider.GetDependency<IOrganizationRepository>();
@ -278,7 +329,7 @@ public class InviteOrganizationUserCommandTests
sutProvider.GetDependency<IInviteUsersValidator>()
.ValidateAsync(Arg.Any<InviteUserOrganizationValidationRequest>())
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, organizationDto)
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, inviteOrganization)
.WithPasswordManagerUpdate(passwordManagerUpdate)));
// Act
@ -288,7 +339,7 @@ public class InviteOrganizationUserCommandTests
Assert.IsType<Success<ScimInviteOrganizationUsersResponse>>(result);
await sutProvider.GetDependency<IPaymentService>()
.AdjustSeatsAsync(organization, organizationDto.Plan, passwordManagerUpdate.SeatsRequiredToAdd);
.AdjustSeatsAsync(organization, inviteOrganization.Plan, passwordManagerUpdate.SeatsRequiredToAdd);
await orgRepository.Received(1).ReplaceAsync(Arg.Is<Organization>(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<IOrganizationUserRepository>();
orgUserRepository
.SelectKnownEmailsAsync(organizationDto.OrganizationId, Arg.Any<IEnumerable<string>>(), false)
.SelectKnownEmailsAsync(inviteOrganization.OrganizationId, Arg.Any<IEnumerable<string>>(), false)
.Returns([]);
orgUserRepository
.GetManyByMinimumRoleAsync(organizationDto.OrganizationId, OrganizationUserType.Owner)
.GetManyByMinimumRoleAsync(inviteOrganization.OrganizationId, OrganizationUserType.Owner)
.Returns([ownerDetails]);
var orgRepository = sutProvider.GetDependency<IOrganizationRepository>();
@ -344,7 +405,7 @@ public class InviteOrganizationUserCommandTests
sutProvider.GetDependency<IInviteUsersValidator>()
.ValidateAsync(Arg.Any<InviteUserOrganizationValidationRequest>())
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, organizationDto)
.Returns(new Valid<InviteUserOrganizationValidationRequest>(GetInviteValidationRequestMock(request, inviteOrganization)
.WithSecretsManagerUpdate(secretsManagerSubscriptionUpdate)));
// Act

View File

@ -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<PasswordManagerSubscriptionUpdate>(
new PasswordManagerSubscriptionUpdate(inviteOrganization, 0, 0));
var result = InviteUserOrganizationValidator.Validate(inviteOrganization, validSubscriptionUpdate);
Assert.IsType<Valid<InviteOrganization>>(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<PasswordManagerSubscriptionUpdate>(
new PasswordManagerSubscriptionUpdate(inviteOrganization, 3, 1));
var result = InviteUserOrganizationValidator.Validate(inviteOrganization, validSubscriptionUpdate);
Assert.IsType<Invalid<InviteOrganization>>(result);
Assert.Equal(OrganizationNoPaymentMethodFoundError.Code, (result as Invalid<InviteOrganization>)!.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<PasswordManagerSubscriptionUpdate>(
new PasswordManagerSubscriptionUpdate(inviteOrganization, 3, 1));
var result = InviteUserOrganizationValidator.Validate(inviteOrganization, validSubscriptionUpdate);
Assert.IsType<Invalid<InviteOrganization>>(result);
Assert.Equal(OrganizationNoSubscriptionFoundError.Code, (result as Invalid<InviteOrganization>)!.ErrorMessageString);

View File

@ -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,