mirror of
https://github.com/bitwarden/server.git
synced 2025-04-04 20:50:21 -05:00
Refactored to use new ValidationResult pattern. added mapping method.
This commit is contained in:
parent
1620fecc70
commit
59b579f071
@ -1,3 +1,8 @@
|
||||
namespace Bit.Core.AdminConsole.Errors;
|
||||
|
||||
public record Error<T>(string Message, T ErroredValue);
|
||||
|
||||
public static class ErrorMappers
|
||||
{
|
||||
public static Error<B> ToError<A, B>(this Error<A> errorA, B erroredValue) => new(errorA.Message, erroredValue);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Bit.Core.AdminConsole.Interfaces;
|
||||
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.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.GlobalSettings;
|
||||
|
||||
public record CannotAutoScaleOnSelfHostError(IGlobalSettings InvalidSettings) : Error<IGlobalSettings>(Code, InvalidSettings)
|
||||
{
|
||||
public const string Code = "CannotAutoScaleOnSelfHost";
|
||||
}
|
@ -1,20 +1,21 @@
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.GlobalSettings;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Organization;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.InviteUserValidationErrorMessages;
|
||||
using SecretsManagerSubscriptionUpdate = Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models.SecretsManagerSubscriptionUpdate;
|
||||
using SecretsManagerSubscriptionUpdate = Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager.SecretsManagerSubscriptionUpdate;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
|
||||
// TODO move into own file ... and change name to validator
|
||||
public interface IInviteUsersValidation
|
||||
{
|
||||
Task<ValidationResult<InviteUserOrganizationValidationRequest>> ValidateAsync(InviteUserOrganizationValidationRequest request);
|
||||
}
|
||||
public interface IInviteUsersValidation : IValidator<InviteUserOrganizationValidationRequest>;
|
||||
|
||||
public class InviteUsersValidation(
|
||||
IGlobalSettings globalSettings,
|
||||
@ -26,14 +27,14 @@ public class InviteUsersValidation(
|
||||
{
|
||||
if (ValidateEnvironment(globalSettings) is Invalid<IGlobalSettings> invalidEnvironment)
|
||||
{
|
||||
return new Invalid<InviteUserOrganizationValidationRequest>(invalidEnvironment.ErrorMessageString);
|
||||
return invalidEnvironment.Map(request);
|
||||
}
|
||||
|
||||
var organizationValidationResult = InvitingUserOrganizationValidation.Validate(request.InviteOrganization);
|
||||
|
||||
if (organizationValidationResult is Invalid<InviteOrganization> organizationValidation)
|
||||
{
|
||||
return new Invalid<InviteUserOrganizationValidationRequest>(organizationValidation.ErrorMessageString);
|
||||
return organizationValidation.Map(request);
|
||||
}
|
||||
|
||||
var subscriptionUpdate = new PasswordManagerSubscriptionUpdate(request);
|
||||
@ -41,7 +42,7 @@ public class InviteUsersValidation(
|
||||
|
||||
if (passwordManagerValidationResult is Invalid<PasswordManagerSubscriptionUpdate> invalidSubscriptionUpdate)
|
||||
{
|
||||
return new Invalid<InviteUserOrganizationValidationRequest>(invalidSubscriptionUpdate.ErrorMessageString);
|
||||
return invalidSubscriptionUpdate.Map(request);
|
||||
}
|
||||
|
||||
var smSubscriptionUpdate = new SecretsManagerSubscriptionUpdate(request, subscriptionUpdate);
|
||||
@ -49,7 +50,7 @@ public class InviteUsersValidation(
|
||||
|
||||
if (secretsManagerValidationResult is Invalid<SecretsManagerSubscriptionUpdate> invalidSmSubscriptionUpdate)
|
||||
{
|
||||
return new Invalid<InviteUserOrganizationValidationRequest>(invalidSmSubscriptionUpdate.ErrorMessageString);
|
||||
return invalidSmSubscriptionUpdate.Map(request);
|
||||
}
|
||||
|
||||
var provider = await providerRepository.GetByOrganizationIdAsync(request.InviteOrganization.OrganizationId);
|
||||
@ -59,16 +60,19 @@ public class InviteUsersValidation(
|
||||
|
||||
if (providerValidationResult is Invalid<ProviderDto> invalidProviderValidation)
|
||||
{
|
||||
return new Invalid<InviteUserOrganizationValidationRequest>(invalidProviderValidation.ErrorMessageString);
|
||||
return invalidProviderValidation.Map(request);
|
||||
}
|
||||
}
|
||||
|
||||
var paymentSubscription = await paymentService.GetSubscriptionAsync(await organizationRepository.GetByIdAsync(request.InviteOrganization.OrganizationId));
|
||||
var paymentValidationResult = InviteUserPaymentValidation.Validate(new PaymentsSubscription(paymentSubscription, request.InviteOrganization));
|
||||
var paymentSubscription = await paymentService.GetSubscriptionAsync(
|
||||
await organizationRepository.GetByIdAsync(request.InviteOrganization.OrganizationId));
|
||||
|
||||
var paymentValidationResult = InviteUserPaymentValidation.Validate(
|
||||
new PaymentsSubscription(paymentSubscription, request.InviteOrganization));
|
||||
|
||||
if (paymentValidationResult is Invalid<PaymentsSubscription> invalidPaymentValidation)
|
||||
{
|
||||
return new Invalid<InviteUserOrganizationValidationRequest>(invalidPaymentValidation.ErrorMessageString);
|
||||
return invalidPaymentValidation.Map(request);
|
||||
}
|
||||
|
||||
return new Valid<InviteUserOrganizationValidationRequest>(new InviteUserOrganizationValidationRequest(
|
||||
@ -79,6 +83,6 @@ public class InviteUsersValidation(
|
||||
|
||||
public static ValidationResult<IGlobalSettings> ValidateEnvironment(IGlobalSettings globalSettings) =>
|
||||
globalSettings.SelfHosted
|
||||
? new Invalid<IGlobalSettings>(CannotAutoScaleOnSelfHostedError)
|
||||
? new Invalid<IGlobalSettings>(new CannotAutoScaleOnSelfHostError(globalSettings))
|
||||
: new Valid<IGlobalSettings>(globalSettings);
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
|
||||
public static class InviteUserValidationErrorMessages
|
||||
{
|
||||
public const string CannotAutoScaleOnSelfHostedError = "Cannot autoscale on self-hosted instance.";
|
||||
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.";
|
||||
public const string SecretsManagerCannotExceedPasswordManager = "You cannot have more Secrets Manager seats than Password Manager seats.";
|
||||
public const string SecretsManagerAdditionalSeatLimitReached = "You have reached the maximum number of Secrets Manager seats ({0}) for this plan.";
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Organization;
|
||||
|
||||
public record OrganizationNoPaymentMethodFoundError(InviteOrganization InvalidRequest)
|
||||
: Error<InviteOrganization>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "No payment method found.";
|
||||
}
|
||||
|
||||
public record OrganizationNoSubscriptionFoundError(InviteOrganization InvalidRequest)
|
||||
: Error<InviteOrganization>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "No subscription found.";
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.InviteUserValidationErrorMessages;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Organization;
|
||||
|
||||
public static class InvitingUserOrganizationValidation
|
||||
{
|
||||
@ -14,12 +14,12 @@ public static class InvitingUserOrganizationValidation
|
||||
|
||||
if (string.IsNullOrWhiteSpace(inviteOrganization.GatewayCustomerId))
|
||||
{
|
||||
return new Invalid<InviteOrganization>(NoPaymentMethodFoundError);
|
||||
return new Invalid<InviteOrganization>(new OrganizationNoPaymentMethodFoundError(inviteOrganization));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(inviteOrganization.GatewaySubscriptionId))
|
||||
{
|
||||
return new Invalid<InviteOrganization>(NoSubscriptionFoundError);
|
||||
return new Invalid<InviteOrganization>(new OrganizationNoSubscriptionFoundError(inviteOrganization));
|
||||
}
|
||||
|
||||
return new Valid<InviteOrganization>(inviteOrganization);
|
@ -0,0 +1,24 @@
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
|
||||
public record PasswordManagerSeatLimitHasBeenReachedError(PasswordManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<PasswordManagerSubscriptionUpdate>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Seat limit has been reached.";
|
||||
}
|
||||
|
||||
public record PasswordManagerPlanDoesNotAllowAdditionalSeatsError(PasswordManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<PasswordManagerSubscriptionUpdate>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Plan does not allow additional seats.";
|
||||
}
|
||||
|
||||
public record PasswordManagerPlanOnlyAllowsMaxAdditionalSeatsError(PasswordManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<PasswordManagerSubscriptionUpdate>(GetErrorMessage(InvalidRequest), InvalidRequest)
|
||||
{
|
||||
private static string GetErrorMessage(PasswordManagerSubscriptionUpdate invalidRequest) =>
|
||||
string.Format(Code, invalidRequest.PasswordManagerPlan.MaxAdditionalSeats);
|
||||
|
||||
public const string Code = "Organization plan allows a maximum of {0} additional seats.";
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.InviteUserValidationErrorMessages;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
|
||||
public static class PasswordManagerInviteUserValidation
|
||||
{
|
||||
// NOTE This is only for validating adding users to an organization, not removing
|
||||
|
||||
public static ValidationResult<PasswordManagerSubscriptionUpdate> Validate(PasswordManagerSubscriptionUpdate subscriptionUpdate)
|
||||
{
|
||||
if (subscriptionUpdate.Seats is null)
|
||||
@ -22,19 +20,21 @@ public static class PasswordManagerInviteUserValidation
|
||||
if (subscriptionUpdate.UpdatedSeatTotal is not null && subscriptionUpdate.MaxAutoScaleSeats is not null &&
|
||||
subscriptionUpdate.UpdatedSeatTotal > subscriptionUpdate.MaxAutoScaleSeats)
|
||||
{
|
||||
return new Invalid<PasswordManagerSubscriptionUpdate>(SeatLimitHasBeenReachedError);
|
||||
return new Invalid<PasswordManagerSubscriptionUpdate>(
|
||||
new PasswordManagerSeatLimitHasBeenReachedError(subscriptionUpdate));
|
||||
}
|
||||
|
||||
if (subscriptionUpdate.PasswordManagerPlan.HasAdditionalSeatsOption is false)
|
||||
{
|
||||
return new Invalid<PasswordManagerSubscriptionUpdate>(PlanDoesNotAllowAdditionalSeats);
|
||||
return new Invalid<PasswordManagerSubscriptionUpdate>(
|
||||
new PasswordManagerPlanDoesNotAllowAdditionalSeatsError(subscriptionUpdate));
|
||||
}
|
||||
|
||||
// Apparently MaxAdditionalSeats is never set. Can probably be removed.
|
||||
if (subscriptionUpdate.AdditionalSeats > subscriptionUpdate.PasswordManagerPlan.MaxAdditionalSeats)
|
||||
{
|
||||
return new Invalid<PasswordManagerSubscriptionUpdate>(string.Format(PlanOnlyAllowsMaxAdditionalSeats,
|
||||
subscriptionUpdate.PasswordManagerPlan.MaxAdditionalSeats));
|
||||
return new Invalid<PasswordManagerSubscriptionUpdate>(
|
||||
new PasswordManagerPlanOnlyAllowsMaxAdditionalSeatsError(subscriptionUpdate));
|
||||
}
|
||||
|
||||
return new Valid<PasswordManagerSubscriptionUpdate>(subscriptionUpdate);
|
@ -2,7 +2,7 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
|
||||
public class PasswordManagerSubscriptionUpdate
|
||||
{
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Payments;
|
||||
|
||||
public record PaymentCancelledSubscriptionError(PaymentsSubscription InvalidRequest)
|
||||
: Error<PaymentsSubscription>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Cannot autoscale with a canceled subscription.";
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Payments;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Enums;
|
||||
|
||||
@ -15,7 +17,7 @@ public static class InviteUserPaymentValidation
|
||||
|
||||
if (subscription.SubscriptionStatus == StripeConstants.SubscriptionStatus.Canceled)
|
||||
{
|
||||
return new Invalid<PaymentsSubscription>(InviteUserValidationErrorMessages.CancelledSubscriptionError);
|
||||
return new Invalid<PaymentsSubscription>(new PaymentCancelledSubscriptionError(subscription));
|
||||
}
|
||||
|
||||
return new Valid<PaymentsSubscription>(subscription);
|
@ -0,0 +1,13 @@
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider;
|
||||
|
||||
public record ProviderBillableSeatLimitError(ProviderDto InvalidRequest) : Error<ProviderDto>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Seat limit has been reached. Please contact your provider to add more seats.";
|
||||
}
|
||||
|
||||
public record ProviderResellerSeatLimitError(ProviderDto InvalidRequest) : Error<ProviderDto>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Seat limit has been reached. Contact your provider to purchase additional seats.";
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider;
|
||||
|
||||
public static class InvitingUserOrganizationProviderValidation
|
||||
{
|
||||
@ -12,12 +12,12 @@ public static class InvitingUserOrganizationProviderValidation
|
||||
{
|
||||
if (provider.IsBillable())
|
||||
{
|
||||
return new Invalid<ProviderDto>(InviteUserValidationErrorMessages.ProviderBillableSeatLimitError);
|
||||
return new Invalid<ProviderDto>(new ProviderBillableSeatLimitError(provider));
|
||||
}
|
||||
|
||||
if (provider.Type == ProviderType.Reseller)
|
||||
{
|
||||
return new Invalid<ProviderDto>(InviteUserValidationErrorMessages.ProviderResellerSeatLimitError);
|
||||
return new Invalid<ProviderDto>(new ProviderResellerSeatLimitError(provider));
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider;
|
||||
|
||||
public class ProviderDto
|
||||
{
|
||||
@ -10,7 +9,7 @@ public class ProviderDto
|
||||
public ProviderStatusType Status { get; init; }
|
||||
public bool Enabled { get; init; }
|
||||
|
||||
public static ProviderDto FromProviderEntity(Provider provider)
|
||||
public static ProviderDto FromProviderEntity(Entities.Provider.Provider provider)
|
||||
{
|
||||
return new ProviderDto { ProviderId = provider.Id, Type = provider.Type, Status = provider.Status, Enabled = provider.Enabled };
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
|
||||
public record OrganizationNoSecretsManagerError(SecretsManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<SecretsManagerSubscriptionUpdate>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Organization has no access to Secrets Manager";
|
||||
}
|
||||
|
||||
public record SecretsManagerAdditionalSeatLimitReachedError(SecretsManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<SecretsManagerSubscriptionUpdate>(GetErrorMessage(InvalidRequest), InvalidRequest)
|
||||
{
|
||||
public const string Code = "You have reached the maximum number of Secrets Manager seats ({0}) for this plan.";
|
||||
|
||||
public static string GetErrorMessage(SecretsManagerSubscriptionUpdate invalidRequest) =>
|
||||
string.Format(Code,
|
||||
invalidRequest.SecretsManagerPlan.BaseSeats +
|
||||
invalidRequest.SecretsManagerPlan.MaxAdditionalSeats.GetValueOrDefault());
|
||||
}
|
||||
|
||||
public record SecretsManagerSeatLimitReachedError(SecretsManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<SecretsManagerSubscriptionUpdate>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "Secrets Manager seat limit has been reached.";
|
||||
}
|
||||
|
||||
public record SecretsManagerCannotExceedPasswordManagerError(SecretsManagerSubscriptionUpdate InvalidRequest)
|
||||
: Error<SecretsManagerSubscriptionUpdate>(Code, InvalidRequest)
|
||||
{
|
||||
public const string Code = "You cannot have more Secrets Manager seats than Password Manager seats.";
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using static Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.InviteUserValidationErrorMessages;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
|
||||
public static class SecretsManagerInviteUserValidation
|
||||
{
|
||||
@ -10,33 +9,34 @@ public static class SecretsManagerInviteUserValidation
|
||||
subscriptionUpdate switch
|
||||
{
|
||||
{ UseSecretsManger: false, AdditionalSeats: > 0 } =>
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(OrganizationNoSecretsManager),
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(
|
||||
new OrganizationNoSecretsManagerError(subscriptionUpdate)),
|
||||
|
||||
{ UseSecretsManger: false, AdditionalSeats: 0 } or { UseSecretsManger: true, Seats: null } =>
|
||||
new Valid<SecretsManagerSubscriptionUpdate>(subscriptionUpdate),
|
||||
|
||||
{ UseSecretsManger: true, SecretsManagerPlan.HasAdditionalSeatsOption: false } =>
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(
|
||||
string.Format(SecretsManagerAdditionalSeatLimitReached,
|
||||
subscriptionUpdate.SecretsManagerPlan.BaseSeats +
|
||||
subscriptionUpdate.SecretsManagerPlan.MaxAdditionalSeats.GetValueOrDefault())),
|
||||
new SecretsManagerAdditionalSeatLimitReachedError(subscriptionUpdate)),
|
||||
|
||||
{ UseSecretsManger: true, SecretsManagerPlan.MaxAdditionalSeats: var planMaxSeats }
|
||||
when planMaxSeats < subscriptionUpdate.AdditionalSeats =>
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(
|
||||
string.Format(SecretsManagerAdditionalSeatLimitReached,
|
||||
subscriptionUpdate.SecretsManagerPlan.BaseSeats +
|
||||
subscriptionUpdate.SecretsManagerPlan.MaxAdditionalSeats.GetValueOrDefault())),
|
||||
new SecretsManagerAdditionalSeatLimitReachedError(subscriptionUpdate)),
|
||||
|
||||
{ UseSecretsManger: true, UpdatedSeatTotal: var updateSeatTotal, MaxAutoScaleSeats: var maxAutoScaleSeats }
|
||||
when updateSeatTotal > maxAutoScaleSeats =>
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(SecretsManagerSeatLimitReached),
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(
|
||||
new SecretsManagerSeatLimitReachedError(subscriptionUpdate)),
|
||||
|
||||
{
|
||||
UseSecretsManger: true,
|
||||
PasswordManagerUpdatedSeatTotal: var passwordManagerUpdatedSeatTotal,
|
||||
UpdatedSeatTotal: var secretsManagerUpdatedSeatTotal
|
||||
} when passwordManagerUpdatedSeatTotal < secretsManagerUpdatedSeatTotal =>
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(SecretsManagerCannotExceedPasswordManager),
|
||||
}
|
||||
when passwordManagerUpdatedSeatTotal < secretsManagerUpdatedSeatTotal =>
|
||||
new Invalid<SecretsManagerSubscriptionUpdate>(
|
||||
new SecretsManagerCannotExceedPasswordManagerError(subscriptionUpdate)),
|
||||
|
||||
_ => new Valid<SecretsManagerSubscriptionUpdate>(subscriptionUpdate)
|
||||
};
|
@ -1,8 +1,9 @@
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
|
||||
public class SecretsManagerSubscriptionUpdate
|
||||
{
|
@ -1,15 +0,0 @@
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
|
||||
public abstract record ValidationResult<T>(T Value, IEnumerable<string> Errors)
|
||||
{
|
||||
public bool IsValid => !Errors.Any();
|
||||
|
||||
public string ErrorMessageString => string.Join(" ", Errors);
|
||||
}
|
||||
|
||||
public record Valid<T>(T Value) : ValidationResult<T>(Value, []);
|
||||
|
||||
public record Invalid<T>(IEnumerable<string> Errors) : ValidationResult<T>(default, Errors)
|
||||
{
|
||||
public Invalid(string error) : this([error]) { }
|
||||
}
|
@ -6,10 +6,39 @@ public abstract record ValidationResult<T>;
|
||||
|
||||
public record Valid<T> : ValidationResult<T>
|
||||
{
|
||||
public Valid() { }
|
||||
|
||||
public Valid(T Value)
|
||||
{
|
||||
this.Value = Value;
|
||||
}
|
||||
|
||||
public T Value { get; init; }
|
||||
}
|
||||
|
||||
public record Invalid<T> : ValidationResult<T>
|
||||
{
|
||||
public IEnumerable<Error<T>> Errors { get; init; }
|
||||
public IEnumerable<Error<T>> Errors { get; init; } = [];
|
||||
|
||||
public string ErrorMessageString => string.Join(" ", Errors.Select(e => e.Message));
|
||||
|
||||
public Invalid() { }
|
||||
|
||||
public Invalid(Error<T> error) : this([error]) { }
|
||||
|
||||
public Invalid(IEnumerable<Error<T>> errors)
|
||||
{
|
||||
Errors = errors;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ValidationResultMappers
|
||||
{
|
||||
public static ValidationResult<B> Map<A, B>(this ValidationResult<A> validationResult, B invalidValue) =>
|
||||
validationResult switch
|
||||
{
|
||||
Valid<A> => new Valid<B>(invalidValue),
|
||||
Invalid<A> invalid => new Invalid<B>(invalid.Errors.Select(x => x.ToError(invalidValue))),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(validationResult), "Unhandled validation result type")
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Provider;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Helpers;
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
using System.Net.Mail;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Errors;
|
||||
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.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Commands;
|
||||
@ -158,7 +161,7 @@ public class InviteOrganizationUserCommandTests
|
||||
|
||||
sutProvider.GetDependency<IInviteUsersValidation>()
|
||||
.ValidateAsync(Arg.Any<InviteUserOrganizationValidationRequest>())
|
||||
.Returns(new Invalid<InviteUserOrganizationValidationRequest>(errorMessage));
|
||||
.Returns(new Invalid<InviteUserOrganizationValidationRequest>(new Error<InviteUserOrganizationValidationRequest>(errorMessage, new InviteUserOrganizationValidationRequest())));
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.InviteScimOrganizationUserAsync(request);
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Organization;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
@ -27,7 +28,8 @@ public class InviteUserOrganizationValidationTests
|
||||
var result = InvitingUserOrganizationValidation.Validate(new InviteOrganization(organization));
|
||||
|
||||
Assert.IsType<Invalid<InviteOrganization>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.NoPaymentMethodFoundError, result.ErrorMessageString);
|
||||
|
||||
Assert.Equal(OrganizationNoPaymentMethodFoundError.Code, (result as Invalid<InviteOrganization>).ErrorMessageString);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -40,6 +42,6 @@ public class InviteUserOrganizationValidationTests
|
||||
var result = InvitingUserOrganizationValidation.Validate(new InviteOrganization(organization));
|
||||
|
||||
Assert.IsType<Invalid<InviteOrganization>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.NoSubscriptionFoundError, result.ErrorMessageString);
|
||||
Assert.Equal(OrganizationNoSubscriptionFoundError.Code, (result as Invalid<InviteOrganization>).ErrorMessageString);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
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.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Payments;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@ -36,7 +38,7 @@ public class InviteUserPaymentValidationTests
|
||||
});
|
||||
|
||||
Assert.IsType<Invalid<PaymentsSubscription>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.CancelledSubscriptionError, result.ErrorMessageString);
|
||||
Assert.Equal(PaymentCancelledSubscriptionError.Code, (result as Invalid<PaymentsSubscription>).ErrorMessageString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -1,7 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
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.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
@ -61,7 +61,7 @@ public class PasswordManagerInviteUserValidationTests
|
||||
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
|
||||
|
||||
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.SeatLimitHasBeenReachedError, result.ErrorMessageString);
|
||||
Assert.Equal(PasswordManagerSeatLimitHasBeenReachedError.Code, (result as Invalid<PasswordManagerSubscriptionUpdate>).ErrorMessageString);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -80,6 +80,6 @@ public class PasswordManagerInviteUserValidationTests
|
||||
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
|
||||
|
||||
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.PlanDoesNotAllowAdditionalSeats, result.ErrorMessageString);
|
||||
Assert.Equal(PasswordManagerPlanDoesNotAllowAdditionalSeatsError.Code, (result as Invalid<PasswordManagerSubscriptionUpdate>).ErrorMessageString);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
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.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.PasswordManager;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Validation.SecretsManager;
|
||||
using Bit.Core.AdminConsole.Shared.Validation;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
@ -68,7 +69,7 @@ public class SecretsManagerInviteUserValidationTests
|
||||
var result = SecretsManagerInviteUserValidation.Validate(update);
|
||||
|
||||
Assert.IsType<Invalid<SecretsManagerSubscriptionUpdate>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.OrganizationNoSecretsManager, result.ErrorMessageString);
|
||||
Assert.Equal(OrganizationNoSecretsManagerError.Code, (result as Invalid<SecretsManagerSubscriptionUpdate>).ErrorMessageString);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -127,7 +128,7 @@ public class SecretsManagerInviteUserValidationTests
|
||||
var result = SecretsManagerInviteUserValidation.Validate(update);
|
||||
|
||||
Assert.IsType<Invalid<SecretsManagerSubscriptionUpdate>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.SecretsManagerSeatLimitReached, result.ErrorMessageString);
|
||||
Assert.Equal(SecretsManagerSeatLimitReachedError.Code, (result as Invalid<SecretsManagerSubscriptionUpdate>).ErrorMessageString);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -158,6 +159,6 @@ public class SecretsManagerInviteUserValidationTests
|
||||
var result = SecretsManagerInviteUserValidation.Validate(update);
|
||||
|
||||
Assert.IsType<Invalid<SecretsManagerSubscriptionUpdate>>(result);
|
||||
Assert.Equal(InviteUserValidationErrorMessages.SecretsManagerCannotExceedPasswordManager, result.ErrorMessageString);
|
||||
Assert.Equal(SecretsManagerCannotExceedPasswordManagerError.Code, (result as Invalid<SecretsManagerSubscriptionUpdate>).ErrorMessageString);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user