mirror of
https://github.com/bitwarden/server.git
synced 2025-04-04 20:50:21 -05:00
Corrected logic and added more tests.
This commit is contained in:
parent
e80bbe1caa
commit
4e205b9d78
@ -18,11 +18,13 @@ public class InviteOrganizationUsersValidator(
|
||||
IUpdateSecretsManagerSubscriptionCommand secretsManagerSubscriptionCommand,
|
||||
IPaymentService paymentService) : IInviteUsersValidator
|
||||
{
|
||||
public async Task<ValidationResult<InviteOrganizationUsersValidationRequest>> ValidateAsync(InviteOrganizationUsersValidationRequest request)
|
||||
public async Task<ValidationResult<InviteOrganizationUsersValidationRequest>> ValidateAsync(
|
||||
InviteOrganizationUsersValidationRequest request)
|
||||
{
|
||||
var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(request);
|
||||
|
||||
var passwordManagerValidationResult = await inviteUsersPasswordManagerValidator.ValidateAsync(subscriptionUpdate);
|
||||
var passwordManagerValidationResult =
|
||||
await inviteUsersPasswordManagerValidator.ValidateAsync(subscriptionUpdate);
|
||||
|
||||
if (passwordManagerValidationResult is Invalid<PasswordManagerSubscriptionUpdate> invalidSubscriptionUpdate)
|
||||
{
|
||||
@ -53,18 +55,25 @@ public class InviteOrganizationUsersValidator(
|
||||
}
|
||||
|
||||
private async Task<ValidationResult<InviteOrganizationUsersValidationRequest>> ValidateSecretsManagerSubscriptionUpdateAsync(
|
||||
InviteOrganizationUsersValidationRequest request,
|
||||
PasswordManagerSubscriptionUpdate subscriptionUpdate)
|
||||
InviteOrganizationUsersValidationRequest request,
|
||||
PasswordManagerSubscriptionUpdate subscriptionUpdate)
|
||||
{
|
||||
try
|
||||
{
|
||||
var smSubscriptionUpdate = new SecretsManagerSubscriptionUpdate(
|
||||
organization: await organizationRepository.GetByIdAsync(request.InviteOrganization.OrganizationId),
|
||||
plan: request.InviteOrganization.Plan,
|
||||
autoscaling: true)
|
||||
.AdjustSeats(GetSecretManagerSeatAdjustment(request));
|
||||
|
||||
await secretsManagerSubscriptionCommand.ValidateUpdateAsync(smSubscriptionUpdate);
|
||||
var smSubscriptionUpdate = new SecretsManagerSubscriptionUpdate(
|
||||
organization: await organizationRepository.GetByIdAsync(request.InviteOrganization.OrganizationId),
|
||||
plan: request.InviteOrganization.Plan,
|
||||
autoscaling: true);
|
||||
|
||||
var seatsToAdd = GetSecretManagerSeatAdjustment(request);
|
||||
|
||||
if (seatsToAdd > 0)
|
||||
{
|
||||
smSubscriptionUpdate.AdjustSeats(seatsToAdd);
|
||||
|
||||
await secretsManagerSubscriptionCommand.ValidateUpdateAsync(smSubscriptionUpdate);
|
||||
}
|
||||
|
||||
return new Valid<InviteOrganizationUsersValidationRequest>(new InviteOrganizationUsersValidationRequest(
|
||||
request,
|
||||
@ -73,13 +82,27 @@ public class InviteOrganizationUsersValidator(
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Invalid<InviteOrganizationUsersValidationRequest>(new Error<InviteOrganizationUsersValidationRequest>(ex.Message, request));
|
||||
return new Invalid<InviteOrganizationUsersValidationRequest>(
|
||||
new Error<InviteOrganizationUsersValidationRequest>(ex.Message, request));
|
||||
}
|
||||
|
||||
int GetSecretManagerSeatAdjustment(InviteOrganizationUsersValidationRequest request) =>
|
||||
Math.Abs(
|
||||
request.InviteOrganization.SmSeats -
|
||||
request.OccupiedSmSeats -
|
||||
request.Invites.Count(x => x.AccessSecretsManager) ?? 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This calculates the number of SM seats to add to the organization seat total.
|
||||
///
|
||||
/// If they have a current seat limit (it can be null), we want to figure out how many are available (seats -
|
||||
/// occupied seats). Then, we'll subtract the available seats from the number of users we're trying to invite.
|
||||
///
|
||||
/// If it's negative, we have available seats and do not need to increase, so we go with 0.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
private static int GetSecretManagerSeatAdjustment(InviteOrganizationUsersValidationRequest request) =>
|
||||
request.InviteOrganization.SmSeats.HasValue
|
||||
? Math.Max(
|
||||
request.Invites.Count(x => x.AccessSecretsManager) -
|
||||
(request.InviteOrganization.SmSeats.Value -
|
||||
request.OccupiedSmSeats),
|
||||
0)
|
||||
: 0;
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
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.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Billing.Models.StaticStore.Plans;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
|
||||
using Bit.Core.Repositories;
|
||||
@ -10,6 +12,7 @@ using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ExceptionExtensions;
|
||||
using Xunit;
|
||||
using OrganizationUserInvite = Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models.OrganizationUserInvite;
|
||||
|
||||
@ -20,7 +23,7 @@ public class InviteOrganizationUsersValidatorTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WhenOrganizationHasSecretsManagerInvites_ThenShouldCorrectlyCalculateSeatsToAdd(
|
||||
public async Task ValidateAsync_WhenOrganizationHasSecretsManagerInvitesAndDoesNotHaveEnoughSeatsAvailable_ThenShouldCorrectlyCalculateSeatsToAdd(
|
||||
Organization organization,
|
||||
SutProvider<InviteOrganizationUsersValidator> sutProvider
|
||||
)
|
||||
@ -63,4 +66,96 @@ public class InviteOrganizationUsersValidatorTests
|
||||
.ValidateUpdateAsync(Arg.Is<SecretsManagerSubscriptionUpdate>(x =>
|
||||
x.SmSeatsChanged == true && x.SmSeats == 12));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WhenOrganizationHasSecretsManagerInvitesAndHasSeatsAvailable_ThenShouldReturnValid(
|
||||
Organization organization,
|
||||
SutProvider<InviteOrganizationUsersValidator> sutProvider
|
||||
)
|
||||
{
|
||||
organization.Seats = null;
|
||||
organization.SmSeats = 12;
|
||||
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<IPaymentService>()
|
||||
.HasSecretsManagerStandalone(request.InviteOrganization)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
Assert.IsType<Valid<InviteOrganizationUsersValidationRequest>>(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WhenOrganizationHasSecretsManagerInvitesAndSmSeatUpdateFailsValidation_ThenShouldReturnInvalid(
|
||||
Organization organization,
|
||||
SutProvider<InviteOrganizationUsersValidator> sutProvider
|
||||
)
|
||||
{
|
||||
organization.Seats = null;
|
||||
organization.SmSeats = 5;
|
||||
organization.MaxAutoscaleSmSeats = 5;
|
||||
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 = 4
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPaymentService>()
|
||||
.HasSecretsManagerStandalone(request.InviteOrganization)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<IUpdateSecretsManagerSubscriptionCommand>()
|
||||
.ValidateUpdateAsync(Arg.Any<SecretsManagerSubscriptionUpdate>())
|
||||
.Throws(new BadRequestException("Some Secrets Manager Failure"));
|
||||
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
Assert.IsType<Invalid<InviteOrganizationUsersValidationRequest>>(result);
|
||||
Assert.Equal("Some Secrets Manager Failure", (result as Invalid<InviteOrganizationUsersValidationRequest>)!.ErrorMessageString);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user