mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 21:18:13 -05:00
Refactor validation parameter to improve clarity and consistency. Added XML doc
This commit is contained in:
parent
e1eb458036
commit
87c181b662
@ -3,7 +3,21 @@ using Bit.Core.Models.Commands;
|
|||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the contract for inviting organization users via SCIM (System for Cross-domain Identity Management).
|
||||||
|
/// Provides functionality for handling single email invitation requests within an organization context.
|
||||||
|
/// </summary>
|
||||||
public interface IInviteOrganizationUsersCommand
|
public interface IInviteOrganizationUsersCommand
|
||||||
{
|
{
|
||||||
Task<CommandResult<ScimInviteOrganizationUsersResponse>> InviteScimOrganizationUserAsync(OrganizationUserSingleEmailInvite request);
|
/// <summary>
|
||||||
|
/// Sends an invitation to add an organization user via SCIM (System for Cross-domain Identity Management) system.
|
||||||
|
/// This can be a Success or a Failure. Failure will contain the Error along with a representation of the errored value.
|
||||||
|
/// Success will be the successful return object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">
|
||||||
|
/// Contains the details for inviting a single organization user via email.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Response from InviteScimOrganiation<see cref="ScimInviteOrganizationUsersResponse"/></returns>
|
||||||
|
Task<CommandResult<ScimInviteOrganizationUsersResponse>> InviteScimOrganizationUserAsync(
|
||||||
|
OrganizationUserSingleEmailInvite request);
|
||||||
}
|
}
|
||||||
|
@ -139,42 +139,42 @@ public class InviteOrganizationUsersCommand(IEventService eventService,
|
|||||||
return new Success<IEnumerable<OrganizationUser>>(organizationUserCollection.Select(x => x.OrganizationUser));
|
return new Success<IEnumerable<OrganizationUser>>(organizationUserCollection.Select(x => x.OrganizationUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RevertPasswordManagerChangesAsync(Valid<InviteUserOrganizationValidationRequest> valid, Organization organization)
|
private async Task RevertPasswordManagerChangesAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult, Organization organization)
|
||||||
{
|
{
|
||||||
if (valid.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd > 0)
|
if (validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd > 0)
|
||||||
{
|
{
|
||||||
// When reverting seats, we have to tell payments service that the seats are going back down by what we attempted to add.
|
// When reverting seats, we have to tell payments service that the seats are going back down by what we attempted to add.
|
||||||
// However, this might lead to a problem if we don't actually update stripe but throw any ways.
|
// However, this might lead to a problem if we don't actually update stripe but throw any ways.
|
||||||
// stripe could not be updated, and then we would decrement the number of seats in stripe accidentally.
|
// stripe could not be updated, and then we would decrement the number of seats in stripe accidentally.
|
||||||
var seatsToRemove = -valid.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd;
|
var seatsToRemove = -validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd;
|
||||||
await paymentService.AdjustSeatsAsync(organization, valid.Value.InviteOrganization.Plan, -seatsToRemove);
|
await paymentService.AdjustSeatsAsync(organization, validatedResult.Value.InviteOrganization.Plan, -seatsToRemove);
|
||||||
|
|
||||||
organization.Seats = (short?)valid.Value.PasswordManagerSubscriptionUpdate.Seats;
|
organization.Seats = (short?)validatedResult.Value.PasswordManagerSubscriptionUpdate.Seats;
|
||||||
|
|
||||||
await organizationRepository.ReplaceAsync(organization);
|
await organizationRepository.ReplaceAsync(organization);
|
||||||
await applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
await applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RevertSecretsManagerChangesAsync(Valid<InviteUserOrganizationValidationRequest> valid, Organization organization)
|
private async Task RevertSecretsManagerChangesAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult, Organization organization)
|
||||||
{
|
{
|
||||||
if (valid.Value.SecretsManagerSubscriptionUpdate.SeatsRequiredToAdd < 0)
|
if (validatedResult.Value.SecretsManagerSubscriptionUpdate.SeatsRequiredToAdd < 0)
|
||||||
{
|
{
|
||||||
var updateRevert = new SecretsManagerSubscriptionUpdate(organization, valid.Value.InviteOrganization.Plan, false)
|
var updateRevert = new SecretsManagerSubscriptionUpdate(organization, validatedResult.Value.InviteOrganization.Plan, false)
|
||||||
{
|
{
|
||||||
SmSeats = valid.Value.SecretsManagerSubscriptionUpdate.Seats
|
SmSeats = validatedResult.Value.SecretsManagerSubscriptionUpdate.Seats
|
||||||
};
|
};
|
||||||
|
|
||||||
await updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(updateRevert);
|
await updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(updateRevert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PublishReferenceEventAsync(Valid<InviteUserOrganizationValidationRequest> valid,
|
private async Task PublishReferenceEventAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult,
|
||||||
Organization organization) =>
|
Organization organization) =>
|
||||||
await referenceEventService.RaiseEventAsync(
|
await referenceEventService.RaiseEventAsync(
|
||||||
new ReferenceEvent(ReferenceEventType.InvitedUsers, organization, currentContext)
|
new ReferenceEvent(ReferenceEventType.InvitedUsers, organization, currentContext)
|
||||||
{
|
{
|
||||||
Users = valid.Value.Invites.Length
|
Users = validatedResult.Value.Invites.Length
|
||||||
});
|
});
|
||||||
|
|
||||||
private async Task SendInvitesAsync(IEnumerable<CreateOrganizationUser> users, Organization organization) =>
|
private async Task SendInvitesAsync(IEnumerable<CreateOrganizationUser> users, Organization organization) =>
|
||||||
@ -183,14 +183,14 @@ public class InviteOrganizationUsersCommand(IEventService eventService,
|
|||||||
users.Select(x => x.OrganizationUser),
|
users.Select(x => x.OrganizationUser),
|
||||||
organization));
|
organization));
|
||||||
|
|
||||||
private async Task SendAdditionalEmailsAsync(Valid<InviteUserOrganizationValidationRequest> valid, Organization organization)
|
private async Task SendAdditionalEmailsAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult, Organization organization)
|
||||||
{
|
{
|
||||||
await SendPasswordManagerMaxSeatLimitEmailsAsync(valid, organization);
|
await SendPasswordManagerMaxSeatLimitEmailsAsync(validatedResult, organization);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendPasswordManagerMaxSeatLimitEmailsAsync(Valid<InviteUserOrganizationValidationRequest> valid, Organization organization)
|
private async Task SendPasswordManagerMaxSeatLimitEmailsAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult, Organization organization)
|
||||||
{
|
{
|
||||||
if (!valid.Value.PasswordManagerSubscriptionUpdate.MaxSeatsReached)
|
if (!validatedResult.Value.PasswordManagerSubscriptionUpdate.MaxSeatsReached)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -198,12 +198,12 @@ public class InviteOrganizationUsersCommand(IEventService eventService,
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ownerEmails = (await organizationUserRepository
|
var ownerEmails = (await organizationUserRepository
|
||||||
.GetManyByMinimumRoleAsync(valid.Value.InviteOrganization.OrganizationId, OrganizationUserType.Owner))
|
.GetManyByMinimumRoleAsync(validatedResult.Value.InviteOrganization.OrganizationId, OrganizationUserType.Owner))
|
||||||
.Select(x => x.Email)
|
.Select(x => x.Email)
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
await mailService.SendOrganizationMaxSeatLimitReachedEmailAsync(organization,
|
await mailService.SendOrganizationMaxSeatLimitReachedEmailAsync(organization,
|
||||||
valid.Value.PasswordManagerSubscriptionUpdate.MaxAutoScaleSeats!.Value, ownerEmails);
|
validatedResult.Value.PasswordManagerSubscriptionUpdate.MaxAutoScaleSeats!.Value, ownerEmails);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -211,29 +211,29 @@ public class InviteOrganizationUsersCommand(IEventService eventService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AdjustSecretsManagerSeatsAsync(Valid<InviteUserOrganizationValidationRequest> valid, Organization organization)
|
private async Task AdjustSecretsManagerSeatsAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult, Organization organization)
|
||||||
{
|
{
|
||||||
if (valid.Value.SecretsManagerSubscriptionUpdate.SeatsRequiredToAdd <= 0)
|
if (validatedResult.Value.SecretsManagerSubscriptionUpdate.SeatsRequiredToAdd <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subscriptionUpdate = new SecretsManagerSubscriptionUpdate(organization, valid.Value.InviteOrganization.Plan, true)
|
var subscriptionUpdate = new SecretsManagerSubscriptionUpdate(organization, validatedResult.Value.InviteOrganization.Plan, true)
|
||||||
.AdjustSeats(valid.Value.SecretsManagerSubscriptionUpdate.SeatsRequiredToAdd);
|
.AdjustSeats(validatedResult.Value.SecretsManagerSubscriptionUpdate.SeatsRequiredToAdd);
|
||||||
|
|
||||||
await updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(subscriptionUpdate);
|
await updateSecretsManagerSubscriptionCommand.UpdateSubscriptionAsync(subscriptionUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AdjustPasswordManagerSeatsAsync(Valid<InviteUserOrganizationValidationRequest> valid, Organization organization)
|
private async Task AdjustPasswordManagerSeatsAsync(Valid<InviteUserOrganizationValidationRequest> validatedResult, Organization organization)
|
||||||
{
|
{
|
||||||
if (valid.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd <= 0)
|
if (validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await paymentService.AdjustSeatsAsync(organization, valid.Value.InviteOrganization.Plan, valid.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd);
|
await paymentService.AdjustSeatsAsync(organization, validatedResult.Value.InviteOrganization.Plan, validatedResult.Value.PasswordManagerSubscriptionUpdate.SeatsRequiredToAdd);
|
||||||
|
|
||||||
organization.Seats = (short?)valid.Value.PasswordManagerSubscriptionUpdate.UpdatedSeatTotal;
|
organization.Seats = (short?)validatedResult.Value.PasswordManagerSubscriptionUpdate.UpdatedSeatTotal;
|
||||||
|
|
||||||
await organizationRepository.ReplaceAsync(organization); // could optimize this with only a property update
|
await organizationRepository.ReplaceAsync(organization); // could optimize this with only a property update
|
||||||
await applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
await applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||||
@ -241,10 +241,10 @@ public class InviteOrganizationUsersCommand(IEventService eventService,
|
|||||||
await referenceEventService.RaiseEventAsync(
|
await referenceEventService.RaiseEventAsync(
|
||||||
new ReferenceEvent(ReferenceEventType.AdjustSeats, organization, currentContext)
|
new ReferenceEvent(ReferenceEventType.AdjustSeats, organization, currentContext)
|
||||||
{
|
{
|
||||||
PlanName = valid.Value.InviteOrganization.Plan.Name,
|
PlanName = validatedResult.Value.InviteOrganization.Plan.Name,
|
||||||
PlanType = valid.Value.InviteOrganization.Plan.Type,
|
PlanType = validatedResult.Value.InviteOrganization.Plan.Type,
|
||||||
Seats = valid.Value.PasswordManagerSubscriptionUpdate.UpdatedSeatTotal,
|
Seats = validatedResult.Value.PasswordManagerSubscriptionUpdate.UpdatedSeatTotal,
|
||||||
PreviousSeats = valid.Value.PasswordManagerSubscriptionUpdate.Seats
|
PreviousSeats = validatedResult.Value.PasswordManagerSubscriptionUpdate.Seats
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ public class PasswordManagerInviteUserValidationTests
|
|||||||
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
|
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
|
||||||
|
|
||||||
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
|
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
|
||||||
Assert.Equal(PasswordManagerSeatLimitHasBeenReachedError.Code, (result as Invalid<PasswordManagerSubscriptionUpdate>).ErrorMessageString);
|
Assert.Equal(PasswordManagerSeatLimitHasBeenReachedError.Code, (result as Invalid<PasswordManagerSubscriptionUpdate>)!.ErrorMessageString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@ -80,6 +80,6 @@ public class PasswordManagerInviteUserValidationTests
|
|||||||
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
|
var result = PasswordManagerInviteUserValidation.Validate(subscriptionUpdate);
|
||||||
|
|
||||||
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
|
Assert.IsType<Invalid<PasswordManagerSubscriptionUpdate>>(result);
|
||||||
Assert.Equal(PasswordManagerPlanDoesNotAllowAdditionalSeatsError.Code, (result as Invalid<PasswordManagerSubscriptionUpdate>).ErrorMessageString);
|
Assert.Equal(PasswordManagerPlanDoesNotAllowAdditionalSeatsError.Code, (result as Invalid<PasswordManagerSubscriptionUpdate>)!.ErrorMessageString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user