mirror of
https://github.com/bitwarden/server.git
synced 2025-12-10 15:55:10 -06:00
[PM-28260] Optimize bulk reinvite endpoint (#6670)
* Implement optimized bulk invite resend command - Added IBulkResendOrganizationInvitesCommand interface to define the bulk resend operation. - Created BulkResendOrganizationInvitesCommand class to handle the logic for resending invites to multiple organization users. - Integrated logging and validation to ensure only valid users receive invites. - Included error handling for non-existent organizations and invalid user statuses. * Add unit tests for BulkResendOrganizationInvitesCommand - Implemented comprehensive test cases for the BulkResendOrganizationInvitesCommand class. - Validated user statuses and ensured correct handling of valid and invalid users during bulk invite resends. - Included tests for scenarios such as organization not found and empty user lists. - Utilized Xunit and NSubstitute for effective testing and mocking of dependencies. * Add IBulkResendOrganizationInvitesCommand to service collection - Registered IBulkResendOrganizationInvitesCommand in the service collection for dependency injection. * Update OrganizationUsersController to utilize IBulkResendOrganizationInvitesCommand - Added IBulkResendOrganizationInvitesCommand to the OrganizationUsersController for handling bulk invite resends based on feature flag. - Updated BulkReinvite method to conditionally use the new command or the legacy service based on the feature flag status. - Enhanced unit tests to verify correct command usage depending on feature flag state, ensuring robust testing for both scenarios.
This commit is contained in:
parent
18a8829476
commit
5469d8be0e
@ -71,6 +71,7 @@ public class OrganizationUsersController : BaseAdminConsoleController
|
|||||||
private readonly IFeatureService _featureService;
|
private readonly IFeatureService _featureService;
|
||||||
private readonly IPricingClient _pricingClient;
|
private readonly IPricingClient _pricingClient;
|
||||||
private readonly IResendOrganizationInviteCommand _resendOrganizationInviteCommand;
|
private readonly IResendOrganizationInviteCommand _resendOrganizationInviteCommand;
|
||||||
|
private readonly IBulkResendOrganizationInvitesCommand _bulkResendOrganizationInvitesCommand;
|
||||||
private readonly IAutomaticallyConfirmOrganizationUserCommand _automaticallyConfirmOrganizationUserCommand;
|
private readonly IAutomaticallyConfirmOrganizationUserCommand _automaticallyConfirmOrganizationUserCommand;
|
||||||
private readonly IConfirmOrganizationUserCommand _confirmOrganizationUserCommand;
|
private readonly IConfirmOrganizationUserCommand _confirmOrganizationUserCommand;
|
||||||
private readonly IRestoreOrganizationUserCommand _restoreOrganizationUserCommand;
|
private readonly IRestoreOrganizationUserCommand _restoreOrganizationUserCommand;
|
||||||
@ -105,6 +106,7 @@ public class OrganizationUsersController : BaseAdminConsoleController
|
|||||||
IInitPendingOrganizationCommand initPendingOrganizationCommand,
|
IInitPendingOrganizationCommand initPendingOrganizationCommand,
|
||||||
IRevokeOrganizationUserCommand revokeOrganizationUserCommand,
|
IRevokeOrganizationUserCommand revokeOrganizationUserCommand,
|
||||||
IResendOrganizationInviteCommand resendOrganizationInviteCommand,
|
IResendOrganizationInviteCommand resendOrganizationInviteCommand,
|
||||||
|
IBulkResendOrganizationInvitesCommand bulkResendOrganizationInvitesCommand,
|
||||||
IAdminRecoverAccountCommand adminRecoverAccountCommand,
|
IAdminRecoverAccountCommand adminRecoverAccountCommand,
|
||||||
IAutomaticallyConfirmOrganizationUserCommand automaticallyConfirmOrganizationUserCommand)
|
IAutomaticallyConfirmOrganizationUserCommand automaticallyConfirmOrganizationUserCommand)
|
||||||
{
|
{
|
||||||
@ -131,6 +133,7 @@ public class OrganizationUsersController : BaseAdminConsoleController
|
|||||||
_featureService = featureService;
|
_featureService = featureService;
|
||||||
_pricingClient = pricingClient;
|
_pricingClient = pricingClient;
|
||||||
_resendOrganizationInviteCommand = resendOrganizationInviteCommand;
|
_resendOrganizationInviteCommand = resendOrganizationInviteCommand;
|
||||||
|
_bulkResendOrganizationInvitesCommand = bulkResendOrganizationInvitesCommand;
|
||||||
_automaticallyConfirmOrganizationUserCommand = automaticallyConfirmOrganizationUserCommand;
|
_automaticallyConfirmOrganizationUserCommand = automaticallyConfirmOrganizationUserCommand;
|
||||||
_confirmOrganizationUserCommand = confirmOrganizationUserCommand;
|
_confirmOrganizationUserCommand = confirmOrganizationUserCommand;
|
||||||
_restoreOrganizationUserCommand = restoreOrganizationUserCommand;
|
_restoreOrganizationUserCommand = restoreOrganizationUserCommand;
|
||||||
@ -273,7 +276,17 @@ public class OrganizationUsersController : BaseAdminConsoleController
|
|||||||
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkReinvite(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
|
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkReinvite(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
|
||||||
{
|
{
|
||||||
var userId = _userService.GetProperUserId(User);
|
var userId = _userService.GetProperUserId(User);
|
||||||
var result = await _organizationService.ResendInvitesAsync(orgId, userId.Value, model.Ids);
|
|
||||||
|
IEnumerable<Tuple<Core.Entities.OrganizationUser, string>> result;
|
||||||
|
if (_featureService.IsEnabled(FeatureFlagKeys.IncreaseBulkReinviteLimitForCloud))
|
||||||
|
{
|
||||||
|
result = await _bulkResendOrganizationInvitesCommand.BulkResendInvitesAsync(orgId, userId.Value, model.Ids);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await _organizationService.ResendInvitesAsync(orgId, userId.Value, model.Ids);
|
||||||
|
}
|
||||||
|
|
||||||
return new ListResponseModel<OrganizationUserBulkResponseModel>(
|
return new ListResponseModel<OrganizationUserBulkResponseModel>(
|
||||||
result.Select(t => new OrganizationUserBulkResponseModel(t.Item1.Id, t.Item2)));
|
result.Select(t => new OrganizationUserBulkResponseModel(t.Item1.Id, t.Item2)));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||||
|
using Bit.Core.AdminConsole.Utilities.DebuggingInstruments;
|
||||||
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
|
|
||||||
|
public class BulkResendOrganizationInvitesCommand : IBulkResendOrganizationInvitesCommand
|
||||||
|
{
|
||||||
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
|
private readonly ISendOrganizationInvitesCommand _sendOrganizationInvitesCommand;
|
||||||
|
private readonly ILogger<BulkResendOrganizationInvitesCommand> _logger;
|
||||||
|
|
||||||
|
public BulkResendOrganizationInvitesCommand(
|
||||||
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
|
IOrganizationRepository organizationRepository,
|
||||||
|
ISendOrganizationInvitesCommand sendOrganizationInvitesCommand,
|
||||||
|
ILogger<BulkResendOrganizationInvitesCommand> logger)
|
||||||
|
{
|
||||||
|
_organizationUserRepository = organizationUserRepository;
|
||||||
|
_organizationRepository = organizationRepository;
|
||||||
|
_sendOrganizationInvitesCommand = sendOrganizationInvitesCommand;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Tuple<OrganizationUser, string>>> BulkResendInvitesAsync(
|
||||||
|
Guid organizationId,
|
||||||
|
Guid? invitingUserId,
|
||||||
|
IEnumerable<Guid> organizationUsersId)
|
||||||
|
{
|
||||||
|
var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUsersId);
|
||||||
|
_logger.LogUserInviteStateDiagnostics(orgUsers);
|
||||||
|
|
||||||
|
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||||
|
if (org == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var validUsers = new List<OrganizationUser>();
|
||||||
|
var result = new List<Tuple<OrganizationUser, string>>();
|
||||||
|
|
||||||
|
foreach (var orgUser in orgUsers)
|
||||||
|
{
|
||||||
|
if (orgUser.Status != OrganizationUserStatusType.Invited || orgUser.OrganizationId != organizationId)
|
||||||
|
{
|
||||||
|
result.Add(Tuple.Create(orgUser, "User invalid."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
validUsers.Add(orgUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validUsers.Any())
|
||||||
|
{
|
||||||
|
await _sendOrganizationInvitesCommand.SendInvitesAsync(
|
||||||
|
new SendInvitesRequest(validUsers, org));
|
||||||
|
|
||||||
|
result.AddRange(validUsers.Select(u => Tuple.Create(u, "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
using Bit.Core.Entities;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
|
|
||||||
|
public interface IBulkResendOrganizationInvitesCommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Resend invites to multiple organization users in bulk.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="organizationId">The ID of the organization.</param>
|
||||||
|
/// <param name="invitingUserId">The ID of the user who is resending the invites.</param>
|
||||||
|
/// <param name="organizationUsersId">The IDs of the organization users to resend invites to.</param>
|
||||||
|
/// <returns>A tuple containing the OrganizationUser and an error message (empty string if successful)</returns>
|
||||||
|
Task<IEnumerable<Tuple<OrganizationUser, string>>> BulkResendInvitesAsync(
|
||||||
|
Guid organizationId,
|
||||||
|
Guid? invitingUserId,
|
||||||
|
IEnumerable<Guid> organizationUsersId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,6 +197,7 @@ public static class OrganizationServiceCollectionExtensions
|
|||||||
services.AddScoped<IInviteOrganizationUsersCommand, InviteOrganizationUsersCommand>();
|
services.AddScoped<IInviteOrganizationUsersCommand, InviteOrganizationUsersCommand>();
|
||||||
services.AddScoped<ISendOrganizationInvitesCommand, SendOrganizationInvitesCommand>();
|
services.AddScoped<ISendOrganizationInvitesCommand, SendOrganizationInvitesCommand>();
|
||||||
services.AddScoped<IResendOrganizationInviteCommand, ResendOrganizationInviteCommand>();
|
services.AddScoped<IResendOrganizationInviteCommand, ResendOrganizationInviteCommand>();
|
||||||
|
services.AddScoped<IBulkResendOrganizationInvitesCommand, BulkResendOrganizationInvitesCommand>();
|
||||||
|
|
||||||
services.AddScoped<IInviteUsersValidator, InviteOrganizationUsersValidator>();
|
services.AddScoped<IInviteUsersValidator, InviteOrganizationUsersValidator>();
|
||||||
services.AddScoped<IInviteUsersOrganizationValidator, InviteUsersOrganizationValidator>();
|
services.AddScoped<IInviteUsersOrganizationValidator, InviteUsersOrganizationValidator>();
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.AccountRecovery;
|
using Bit.Core.AdminConsole.OrganizationFeatures.AccountRecovery;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
@ -730,4 +731,68 @@ public class OrganizationUsersControllerTests
|
|||||||
var problemResult = Assert.IsType<JsonHttpResult<ErrorResponseModel>>(result);
|
var problemResult = Assert.IsType<JsonHttpResult<ErrorResponseModel>>(result);
|
||||||
Assert.Equal(StatusCodes.Status500InternalServerError, problemResult.StatusCode);
|
Assert.Equal(StatusCodes.Status500InternalServerError, problemResult.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task BulkReinvite_WhenFeatureFlagEnabled_UsesBulkResendOrganizationInvitesCommand(
|
||||||
|
Guid organizationId,
|
||||||
|
OrganizationUserBulkRequestModel bulkRequestModel,
|
||||||
|
List<OrganizationUser> organizationUsers,
|
||||||
|
Guid userId,
|
||||||
|
SutProvider<OrganizationUsersController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ManageUsers(organizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<IUserService>().GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.IncreaseBulkReinviteLimitForCloud)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
var expectedResults = organizationUsers.Select(u => Tuple.Create(u, "")).ToList();
|
||||||
|
sutProvider.GetDependency<IBulkResendOrganizationInvitesCommand>()
|
||||||
|
.BulkResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids)
|
||||||
|
.Returns(expectedResults);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await sutProvider.Sut.BulkReinvite(organizationId, bulkRequestModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(organizationUsers.Count, response.Data.Count());
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IBulkResendOrganizationInvitesCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.BulkResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task BulkReinvite_WhenFeatureFlagDisabled_UsesLegacyOrganizationService(
|
||||||
|
Guid organizationId,
|
||||||
|
OrganizationUserBulkRequestModel bulkRequestModel,
|
||||||
|
List<OrganizationUser> organizationUsers,
|
||||||
|
Guid userId,
|
||||||
|
SutProvider<OrganizationUsersController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ManageUsers(organizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<IUserService>().GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.IncreaseBulkReinviteLimitForCloud)
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
|
var expectedResults = organizationUsers.Select(u => Tuple.Create(u, "")).ToList();
|
||||||
|
sutProvider.GetDependency<IOrganizationService>()
|
||||||
|
.ResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids)
|
||||||
|
.Returns(expectedResults);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await sutProvider.Sut.BulkReinvite(organizationId, bulkRequestModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(organizationUsers.Count, response.Data.Count());
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IOrganizationService>()
|
||||||
|
.Received(1)
|
||||||
|
.ResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,113 @@
|
|||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||||
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
using NSubstitute;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
|
|
||||||
|
[SutProviderCustomize]
|
||||||
|
public class BulkResendOrganizationInvitesCommandTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task BulkResendInvitesAsync_ValidatesUsersAndSendsBatchInvite(
|
||||||
|
Organization organization,
|
||||||
|
OrganizationUser validUser1,
|
||||||
|
OrganizationUser validUser2,
|
||||||
|
OrganizationUser acceptedUser,
|
||||||
|
OrganizationUser wrongOrgUser,
|
||||||
|
SutProvider<BulkResendOrganizationInvitesCommand> sutProvider)
|
||||||
|
{
|
||||||
|
validUser1.OrganizationId = organization.Id;
|
||||||
|
validUser1.Status = OrganizationUserStatusType.Invited;
|
||||||
|
validUser2.OrganizationId = organization.Id;
|
||||||
|
validUser2.Status = OrganizationUserStatusType.Invited;
|
||||||
|
acceptedUser.OrganizationId = organization.Id;
|
||||||
|
acceptedUser.Status = OrganizationUserStatusType.Accepted;
|
||||||
|
wrongOrgUser.OrganizationId = Guid.NewGuid();
|
||||||
|
wrongOrgUser.Status = OrganizationUserStatusType.Invited;
|
||||||
|
|
||||||
|
var users = new List<OrganizationUser> { validUser1, validUser2, acceptedUser, wrongOrgUser };
|
||||||
|
var userIds = users.Select(u => u.Id).ToList();
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyAsync(userIds).Returns(users);
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
|
var result = (await sutProvider.Sut.BulkResendInvitesAsync(organization.Id, null, userIds)).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(4, result.Count);
|
||||||
|
Assert.Equal(2, result.Count(r => string.IsNullOrEmpty(r.Item2)));
|
||||||
|
Assert.Equal(2, result.Count(r => r.Item2 == "User invalid."));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ISendOrganizationInvitesCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.SendInvitesAsync(Arg.Is<SendInvitesRequest>(req =>
|
||||||
|
req.Organization == organization &&
|
||||||
|
req.Users.Length == 2 &&
|
||||||
|
req.InitOrganization == false));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task BulkResendInvitesAsync_AllInvalidUsers_DoesNotSendInvites(
|
||||||
|
Organization organization,
|
||||||
|
List<OrganizationUser> organizationUsers,
|
||||||
|
SutProvider<BulkResendOrganizationInvitesCommand> sutProvider)
|
||||||
|
{
|
||||||
|
foreach (var user in organizationUsers)
|
||||||
|
{
|
||||||
|
user.OrganizationId = organization.Id;
|
||||||
|
user.Status = OrganizationUserStatusType.Confirmed;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userIds = organizationUsers.Select(u => u.Id).ToList();
|
||||||
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyAsync(userIds).Returns(organizationUsers);
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
|
var result = (await sutProvider.Sut.BulkResendInvitesAsync(organization.Id, null, userIds)).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(organizationUsers.Count, result.Count);
|
||||||
|
Assert.All(result, r => Assert.Equal("User invalid.", r.Item2));
|
||||||
|
await sutProvider.GetDependency<ISendOrganizationInvitesCommand>().DidNotReceive()
|
||||||
|
.SendInvitesAsync(Arg.Any<SendInvitesRequest>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task BulkResendInvitesAsync_OrganizationNotFound_ThrowsNotFoundException(
|
||||||
|
Guid organizationId,
|
||||||
|
List<Guid> userIds,
|
||||||
|
List<OrganizationUser> organizationUsers,
|
||||||
|
SutProvider<BulkResendOrganizationInvitesCommand> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyAsync(userIds).Returns(organizationUsers);
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns((Organization?)null);
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||||
|
sutProvider.Sut.BulkResendInvitesAsync(organizationId, null, userIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData]
|
||||||
|
public async Task BulkResendInvitesAsync_EmptyUserList_ReturnsEmpty(
|
||||||
|
Organization organization,
|
||||||
|
SutProvider<BulkResendOrganizationInvitesCommand> sutProvider)
|
||||||
|
{
|
||||||
|
var emptyUserIds = new List<Guid>();
|
||||||
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyAsync(emptyUserIds).Returns(new List<OrganizationUser>());
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
|
var result = await sutProvider.Sut.BulkResendInvitesAsync(organization.Id, null, emptyUserIds);
|
||||||
|
|
||||||
|
Assert.Empty(result);
|
||||||
|
await sutProvider.GetDependency<ISendOrganizationInvitesCommand>().DidNotReceive()
|
||||||
|
.SendInvitesAsync(Arg.Any<SendInvitesRequest>());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user