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

Added plan validation to PasswordManagerInviteUserValidation. Cleaned up a few things.

This commit is contained in:
jrmccannon 2025-02-13 10:33:20 -06:00
parent 930419a502
commit bf8d6fb3ba
No known key found for this signature in database
GPG Key ID: CF03F3DB01CE96A6
4 changed files with 50 additions and 10 deletions

View File

@ -3,13 +3,17 @@
public static class InviteUserValidationErrorMessages
{
public const string CannotAutoScaleOnSelfHostedError = "Cannot autoscale on self-hosted instance.";
public const string SeatLimitHasBeenReachedError = "Seat limit has been reached.";
public const string ProviderBillableSeatLimitError = "Seat limit has been reached. Please contact your provider to add more seats.";
public const string ProviderResellerSeatLimitError = "Seat limit has been reached. Contact your provider to purchase additional seats.";
public const string CancelledSubscriptionError = "Cannot autoscale with a canceled subscription.";
public const string NoPaymentMethodFoundError = "No payment method found.";
public const string NoSubscriptionFoundError = "No subscription found.";
// Password Manger Invite Users Error Messages
public const string SeatLimitHasBeenReachedError = "Seat limit has been reached.";
public const string PlanDoesNotAllowAdditionalSeats = "Plan does not allow additional seats.";
public const string PlanOnlyAllowsMaxAdditionalSeats = "Organization plan allows a maximum of {0} additional seats.";
// Secrets Manager Invite Users Error Messages
public const string OrganizationNoSecretsManager = "Organization has no access to Secrets Manager";
public const string SecretsManagerSeatLimitReached = "Secrets Manager seat limit has been reached.";

View File

@ -1,5 +1,6 @@
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;
@ -8,13 +9,13 @@ public class PasswordManagerSubscriptionUpdate
/// <summary>
/// Seats the organization has
/// </summary>
public int? Seats { get; private init; }
public int? Seats { get; }
public int? MaxAutoScaleSeats { get; private init; }
public int? MaxAutoScaleSeats { get; }
public int OccupiedSeats { get; private init; }
public int OccupiedSeats { get; }
public int AdditionalSeats { get; private init; }
public int AdditionalSeats { get; }
public int? AvailableSeats => Seats - OccupiedSeats;
@ -22,22 +23,25 @@ public class PasswordManagerSubscriptionUpdate
public int? UpdatedSeatTotal => Seats + SeatsRequiredToAdd;
private PasswordManagerSubscriptionUpdate(int? organizationSeats, int? organizationAutoScaleSeatLimit, int currentSeats, int seatsToAdd)
public Plan Plan { get; }
private PasswordManagerSubscriptionUpdate(int? organizationSeats, int? organizationAutoScaleSeatLimit, int currentSeats, int seatsToAdd, Plan plan)
{
Seats = organizationSeats;
MaxAutoScaleSeats = organizationAutoScaleSeatLimit;
OccupiedSeats = currentSeats;
AdditionalSeats = seatsToAdd;
Plan = plan;
}
public static PasswordManagerSubscriptionUpdate Create(OrganizationDto organizationDto, int occupiedSeats, int seatsToAdd)
{
return new PasswordManagerSubscriptionUpdate(organizationDto.Seats, organizationDto.MaxAutoScaleSeats, occupiedSeats, seatsToAdd);
return new PasswordManagerSubscriptionUpdate(organizationDto.Seats, organizationDto.MaxAutoScaleSeats, occupiedSeats, seatsToAdd, organizationDto.Plan);
}
public static PasswordManagerSubscriptionUpdate Create(InviteUserOrganizationValidationRequest refined)
{
return new PasswordManagerSubscriptionUpdate(refined.Organization.Seats, refined.Organization.MaxAutoScaleSeats,
refined.OccupiedPmSeats, refined.Invites.Length);
refined.OccupiedPmSeats, refined.Invites.Length, refined.Organization.Plan);
}
}

View File

@ -5,8 +5,7 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUse
public static class PasswordManagerInviteUserValidation
{
// TODO need to add plan validation from AdjustSeatsAsync
// NOTE This is only for validating adding users to an organization, not removing
public static ValidationResult<PasswordManagerSubscriptionUpdate> Validate(PasswordManagerSubscriptionUpdate subscriptionUpdate)
{
@ -26,6 +25,18 @@ public static class PasswordManagerInviteUserValidation
return new Invalid<PasswordManagerSubscriptionUpdate>(SeatLimitHasBeenReachedError);
}
if (subscriptionUpdate.Plan.PasswordManager.HasAdditionalSeatsOption is false)
{
return new Invalid<PasswordManagerSubscriptionUpdate>(PlanDoesNotAllowAdditionalSeats);
}
// Apparently MaxAdditionalSeats is never set. Can probably be removed.
if (subscriptionUpdate.AdditionalSeats > subscriptionUpdate.Plan.PasswordManager.MaxAdditionalSeats)
{
return new Invalid<PasswordManagerSubscriptionUpdate>(string.Format(PlanOnlyAllowsMaxAdditionalSeats,
subscriptionUpdate.Plan.PasswordManager.MaxAdditionalSeats));
}
return new Valid<PasswordManagerSubscriptionUpdate>(subscriptionUpdate);
}
}

View File

@ -2,6 +2,7 @@
using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
using Bit.Core.Billing.Enums;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
@ -30,6 +31,7 @@ public class PasswordManagerInviteUserValidationTests
public void Validate_NumberOfSeatsToAddMatchesSeatsAvailable_ShouldReturnValidResult(Organization organization)
{
organization.Seats = 8;
organization.PlanType = PlanType.EnterpriseAnnually;
var seatsOccupiedByUsers = 4;
var additionalSeats = 4;
@ -61,4 +63,23 @@ public class PasswordManagerInviteUserValidationTests
Assert.Equal(InviteUserValidationErrorMessages.SeatLimitHasBeenReachedError, result.ErrorMessageString);
}
[Theory]
[BitAutoData]
public void Validate_GivenThePlanDoesNotAllowAdditionalSeats_ShouldBeInvalidMessageOfPlanNotAllowingSeats(Organization organization)
{
organization.Seats = 8;
var seatsOccupiedByUsers = 4;
var additionalSeats = 4;
organization.PlanType = PlanType.Free;
var organizationDto = OrganizationDto.FromOrganization(organization);
var subscriptionUpdate = PasswordManagerSubscriptionUpdate.Create(organizationDto, seatsOccupiedByUsers, additionalSeats);
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
Assert.Equal(InviteUserValidationErrorMessages.PlanDoesNotAllowAdditionalSeats, result.ErrorMessageString);
}
}