18 changed files with 83 additions and 927 deletions
@ -1,7 +1,7 @@ |
|||||||
using OneOf; |
using OneOf; |
||||||
using OneOf.Types; |
using OneOf.Types; |
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext; |
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; |
||||||
|
|
||||||
/// <summary> |
/// <summary> |
||||||
/// Represents the result of a command. |
/// Represents the result of a command. |
||||||
@ -1,6 +1,6 @@ |
|||||||
using Bit.Core.Entities; |
using Bit.Core.Entities; |
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext; |
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; |
||||||
|
|
||||||
public class DeleteUserValidationRequest |
public class DeleteUserValidationRequest |
||||||
{ |
{ |
||||||
@ -1,4 +1,4 @@ |
|||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext; |
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; |
||||||
|
|
||||||
/// <summary> |
/// <summary> |
||||||
/// A strongly typed error containing a reason that an action failed. |
/// A strongly typed error containing a reason that an action failed. |
||||||
@ -1,6 +1,6 @@ |
|||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext; |
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; |
||||||
|
|
||||||
public interface IDeleteClaimedOrganizationUserAccountCommandvNext |
public interface IDeleteClaimedOrganizationUserAccountCommand |
||||||
{ |
{ |
||||||
/// <summary> |
/// <summary> |
||||||
/// Removes a user from an organization and deletes all of their associated user data. |
/// Removes a user from an organization and deletes all of their associated user data. |
||||||
@ -1,6 +1,6 @@ |
|||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext; |
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; |
||||||
|
|
||||||
public interface IDeleteClaimedOrganizationUserAccountValidatorvNext |
public interface IDeleteClaimedOrganizationUserAccountValidator |
||||||
{ |
{ |
||||||
Task<IEnumerable<ValidationResult<DeleteUserValidationRequest>>> ValidateAsync(IEnumerable<DeleteUserValidationRequest> requests); |
Task<IEnumerable<ValidationResult<DeleteUserValidationRequest>>> ValidateAsync(IEnumerable<DeleteUserValidationRequest> requests); |
||||||
} |
} |
||||||
@ -1,7 +1,7 @@ |
|||||||
using OneOf; |
using OneOf; |
||||||
using OneOf.Types; |
using OneOf.Types; |
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext; |
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; |
||||||
|
|
||||||
/// <summary> |
/// <summary> |
||||||
/// Represents the result of validating a request. |
/// Represents the result of validating a request. |
||||||
@ -1,239 +0,0 @@ |
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; |
|
||||||
using Bit.Core.AdminConsole.Repositories; |
|
||||||
using Bit.Core.Context; |
|
||||||
using Bit.Core.Entities; |
|
||||||
using Bit.Core.Enums; |
|
||||||
using Bit.Core.Exceptions; |
|
||||||
using Bit.Core.Platform.Push; |
|
||||||
using Bit.Core.Repositories; |
|
||||||
using Bit.Core.Services; |
|
||||||
|
|
||||||
#nullable enable |
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; |
|
||||||
|
|
||||||
public class DeleteClaimedOrganizationUserAccountCommand : IDeleteClaimedOrganizationUserAccountCommand |
|
||||||
{ |
|
||||||
private readonly IUserService _userService; |
|
||||||
private readonly IEventService _eventService; |
|
||||||
private readonly IGetOrganizationUsersClaimedStatusQuery _getOrganizationUsersClaimedStatusQuery; |
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository; |
|
||||||
private readonly IUserRepository _userRepository; |
|
||||||
private readonly ICurrentContext _currentContext; |
|
||||||
private readonly IHasConfirmedOwnersExceptQuery _hasConfirmedOwnersExceptQuery; |
|
||||||
private readonly IPushNotificationService _pushService; |
|
||||||
private readonly IOrganizationRepository _organizationRepository; |
|
||||||
private readonly IProviderUserRepository _providerUserRepository; |
|
||||||
public DeleteClaimedOrganizationUserAccountCommand( |
|
||||||
IUserService userService, |
|
||||||
IEventService eventService, |
|
||||||
IGetOrganizationUsersClaimedStatusQuery getOrganizationUsersClaimedStatusQuery, |
|
||||||
IOrganizationUserRepository organizationUserRepository, |
|
||||||
IUserRepository userRepository, |
|
||||||
ICurrentContext currentContext, |
|
||||||
IHasConfirmedOwnersExceptQuery hasConfirmedOwnersExceptQuery, |
|
||||||
IPushNotificationService pushService, |
|
||||||
IOrganizationRepository organizationRepository, |
|
||||||
IProviderUserRepository providerUserRepository) |
|
||||||
{ |
|
||||||
_userService = userService; |
|
||||||
_eventService = eventService; |
|
||||||
_getOrganizationUsersClaimedStatusQuery = getOrganizationUsersClaimedStatusQuery; |
|
||||||
_organizationUserRepository = organizationUserRepository; |
|
||||||
_userRepository = userRepository; |
|
||||||
_currentContext = currentContext; |
|
||||||
_hasConfirmedOwnersExceptQuery = hasConfirmedOwnersExceptQuery; |
|
||||||
_pushService = pushService; |
|
||||||
_organizationRepository = organizationRepository; |
|
||||||
_providerUserRepository = providerUserRepository; |
|
||||||
} |
|
||||||
|
|
||||||
public async Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid? deletingUserId) |
|
||||||
{ |
|
||||||
var organizationUser = await _organizationUserRepository.GetByIdAsync(organizationUserId); |
|
||||||
if (organizationUser == null || organizationUser.OrganizationId != organizationId) |
|
||||||
{ |
|
||||||
throw new NotFoundException("Member not found."); |
|
||||||
} |
|
||||||
|
|
||||||
var claimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(organizationId, new[] { organizationUserId }); |
|
||||||
var hasOtherConfirmedOwners = await _hasConfirmedOwnersExceptQuery.HasConfirmedOwnersExceptAsync(organizationId, new[] { organizationUserId }, includeProvider: true); |
|
||||||
|
|
||||||
await ValidateDeleteUserAsync(organizationId, organizationUser, deletingUserId, claimedStatus, hasOtherConfirmedOwners); |
|
||||||
|
|
||||||
var user = await _userRepository.GetByIdAsync(organizationUser.UserId!.Value); |
|
||||||
if (user == null) |
|
||||||
{ |
|
||||||
throw new NotFoundException("Member not found."); |
|
||||||
} |
|
||||||
|
|
||||||
await _userService.DeleteAsync(user); |
|
||||||
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deleted); |
|
||||||
} |
|
||||||
|
|
||||||
public async Task<IEnumerable<(Guid OrganizationUserId, string? ErrorMessage)>> DeleteManyUsersAsync(Guid organizationId, IEnumerable<Guid> orgUserIds, Guid? deletingUserId) |
|
||||||
{ |
|
||||||
var orgUsers = await _organizationUserRepository.GetManyAsync(orgUserIds); |
|
||||||
var userIds = orgUsers.Where(ou => ou.UserId.HasValue).Select(ou => ou.UserId!.Value).ToList(); |
|
||||||
var users = await _userRepository.GetManyAsync(userIds); |
|
||||||
|
|
||||||
var claimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(organizationId, orgUserIds); |
|
||||||
var hasOtherConfirmedOwners = await _hasConfirmedOwnersExceptQuery.HasConfirmedOwnersExceptAsync(organizationId, orgUserIds, includeProvider: true); |
|
||||||
|
|
||||||
var results = new List<(Guid OrganizationUserId, string? ErrorMessage)>(); |
|
||||||
foreach (var orgUserId in orgUserIds) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
var orgUser = orgUsers.FirstOrDefault(ou => ou.Id == orgUserId); |
|
||||||
if (orgUser == null || orgUser.OrganizationId != organizationId) |
|
||||||
{ |
|
||||||
throw new NotFoundException("Member not found."); |
|
||||||
} |
|
||||||
|
|
||||||
await ValidateDeleteUserAsync(organizationId, orgUser, deletingUserId, claimedStatus, hasOtherConfirmedOwners); |
|
||||||
|
|
||||||
var user = users.FirstOrDefault(u => u.Id == orgUser.UserId); |
|
||||||
if (user == null) |
|
||||||
{ |
|
||||||
throw new NotFoundException("Member not found."); |
|
||||||
} |
|
||||||
|
|
||||||
await ValidateUserMembershipAndPremiumAsync(user); |
|
||||||
|
|
||||||
results.Add((orgUserId, string.Empty)); |
|
||||||
} |
|
||||||
catch (Exception ex) |
|
||||||
{ |
|
||||||
results.Add((orgUserId, ex.Message)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var orgUserResultsToDelete = results.Where(result => string.IsNullOrEmpty(result.ErrorMessage)); |
|
||||||
var orgUsersToDelete = orgUsers.Where(orgUser => orgUserResultsToDelete.Any(result => orgUser.Id == result.OrganizationUserId)); |
|
||||||
var usersToDelete = users.Where(user => orgUsersToDelete.Any(orgUser => orgUser.UserId == user.Id)); |
|
||||||
|
|
||||||
if (usersToDelete.Any()) |
|
||||||
{ |
|
||||||
await DeleteManyAsync(usersToDelete); |
|
||||||
} |
|
||||||
|
|
||||||
await LogDeletedOrganizationUsersAsync(orgUsers, results); |
|
||||||
|
|
||||||
return results; |
|
||||||
} |
|
||||||
|
|
||||||
private async Task ValidateDeleteUserAsync(Guid organizationId, OrganizationUser orgUser, Guid? deletingUserId, IDictionary<Guid, bool> claimedStatus, bool hasOtherConfirmedOwners) |
|
||||||
{ |
|
||||||
if (!orgUser.UserId.HasValue || orgUser.Status == OrganizationUserStatusType.Invited) |
|
||||||
{ |
|
||||||
throw new BadRequestException("You cannot delete a member with Invited status."); |
|
||||||
} |
|
||||||
|
|
||||||
if (deletingUserId.HasValue && orgUser.UserId.Value == deletingUserId.Value) |
|
||||||
{ |
|
||||||
throw new BadRequestException("You cannot delete yourself."); |
|
||||||
} |
|
||||||
|
|
||||||
if (orgUser.Type == OrganizationUserType.Owner) |
|
||||||
{ |
|
||||||
if (deletingUserId.HasValue && !await _currentContext.OrganizationOwner(organizationId)) |
|
||||||
{ |
|
||||||
throw new BadRequestException("Only owners can delete other owners."); |
|
||||||
} |
|
||||||
|
|
||||||
if (!hasOtherConfirmedOwners) |
|
||||||
{ |
|
||||||
throw new BadRequestException("Organization must have at least one confirmed owner."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (orgUser.Type == OrganizationUserType.Admin && await _currentContext.OrganizationCustom(organizationId)) |
|
||||||
{ |
|
||||||
throw new BadRequestException("Custom users can not delete admins."); |
|
||||||
} |
|
||||||
|
|
||||||
if (!claimedStatus.TryGetValue(orgUser.Id, out var isClaimed) || !isClaimed) |
|
||||||
{ |
|
||||||
throw new BadRequestException("Member is not claimed by the organization."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private async Task LogDeletedOrganizationUsersAsync( |
|
||||||
IEnumerable<OrganizationUser> orgUsers, |
|
||||||
IEnumerable<(Guid OrgUserId, string? ErrorMessage)> results) |
|
||||||
{ |
|
||||||
var eventDate = DateTime.UtcNow; |
|
||||||
var events = new List<(OrganizationUser OrgUser, EventType Event, DateTime? EventDate)>(); |
|
||||||
|
|
||||||
foreach (var (orgUserId, errorMessage) in results) |
|
||||||
{ |
|
||||||
var orgUser = orgUsers.FirstOrDefault(ou => ou.Id == orgUserId); |
|
||||||
// If the user was not found or there was an error, we skip logging the event |
|
||||||
if (orgUser == null || !string.IsNullOrEmpty(errorMessage)) |
|
||||||
{ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
events.Add((orgUser, EventType.OrganizationUser_Deleted, eventDate)); |
|
||||||
} |
|
||||||
|
|
||||||
if (events.Any()) |
|
||||||
{ |
|
||||||
await _eventService.LogOrganizationUserEventsAsync(events); |
|
||||||
} |
|
||||||
} |
|
||||||
private async Task DeleteManyAsync(IEnumerable<User> users) |
|
||||||
{ |
|
||||||
|
|
||||||
await _userRepository.DeleteManyAsync(users); |
|
||||||
foreach (var user in users) |
|
||||||
{ |
|
||||||
await _pushService.PushLogOutAsync(user.Id); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private async Task ValidateUserMembershipAndPremiumAsync(User user) |
|
||||||
{ |
|
||||||
// Check if user is the only owner of any organizations. |
|
||||||
var onlyOwnerCount = await _organizationUserRepository.GetCountByOnlyOwnerAsync(user.Id); |
|
||||||
if (onlyOwnerCount > 0) |
|
||||||
{ |
|
||||||
throw new BadRequestException("Cannot delete this user because it is the sole owner of at least one organization. Please delete these organizations or upgrade another user."); |
|
||||||
} |
|
||||||
|
|
||||||
var orgs = await _organizationUserRepository.GetManyDetailsByUserAsync(user.Id, OrganizationUserStatusType.Confirmed); |
|
||||||
if (orgs.Count == 1) |
|
||||||
{ |
|
||||||
var org = await _organizationRepository.GetByIdAsync(orgs.First().OrganizationId); |
|
||||||
if (org != null && (!org.Enabled || string.IsNullOrWhiteSpace(org.GatewaySubscriptionId))) |
|
||||||
{ |
|
||||||
var orgCount = await _organizationUserRepository.GetCountByOrganizationIdAsync(org.Id); |
|
||||||
if (orgCount <= 1) |
|
||||||
{ |
|
||||||
await _organizationRepository.DeleteAsync(org); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
throw new BadRequestException("Cannot delete this user because it is the sole owner of at least one organization. Please delete these organizations or upgrade another user."); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var onlyOwnerProviderCount = await _providerUserRepository.GetCountByOnlyOwnerAsync(user.Id); |
|
||||||
if (onlyOwnerProviderCount > 0) |
|
||||||
{ |
|
||||||
throw new BadRequestException("Cannot delete this user because it is the sole owner of at least one provider. Please delete these providers or upgrade another user."); |
|
||||||
} |
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(user.GatewaySubscriptionId)) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
await _userService.CancelPremiumAsync(user); |
|
||||||
} |
|
||||||
catch (GatewayException) { } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,19 +0,0 @@ |
|||||||
#nullable enable |
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; |
|
||||||
|
|
||||||
public interface IDeleteClaimedOrganizationUserAccountCommand |
|
||||||
{ |
|
||||||
/// <summary> |
|
||||||
/// Removes a user from an organization and deletes all of their associated user data. |
|
||||||
/// </summary> |
|
||||||
Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid? deletingUserId); |
|
||||||
|
|
||||||
/// <summary> |
|
||||||
/// Removes multiple users from an organization and deletes all of their associated user data. |
|
||||||
/// </summary> |
|
||||||
/// <returns> |
|
||||||
/// An error message for each user that could not be removed, otherwise null. |
|
||||||
/// </returns> |
|
||||||
Task<IEnumerable<(Guid OrganizationUserId, string? ErrorMessage)>> DeleteManyUsersAsync(Guid organizationId, IEnumerable<Guid> orgUserIds, Guid? deletingUserId); |
|
||||||
} |
|
||||||
34
test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedAccountvNext/DeleteClaimedOrganizationUserAccountValidatorvNextTests.cs → test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedAccountvNext/DeleteClaimedOrganizationUserAccountValidatorTests.cs
34
test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedAccountvNext/DeleteClaimedOrganizationUserAccountValidatorvNextTests.cs → test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/DeleteClaimedAccountvNext/DeleteClaimedOrganizationUserAccountValidatorTests.cs
@ -1,526 +0,0 @@ |
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; |
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; |
|
||||||
using Bit.Core.Context; |
|
||||||
using Bit.Core.Entities; |
|
||||||
using Bit.Core.Enums; |
|
||||||
using Bit.Core.Exceptions; |
|
||||||
using Bit.Core.Repositories; |
|
||||||
using Bit.Core.Services; |
|
||||||
using Bit.Core.Test.AutoFixture.OrganizationUserFixtures; |
|
||||||
using Bit.Test.Common.AutoFixture; |
|
||||||
using Bit.Test.Common.AutoFixture.Attributes; |
|
||||||
using NSubstitute; |
|
||||||
using Xunit; |
|
||||||
|
|
||||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers; |
|
||||||
|
|
||||||
[SutProviderCustomize] |
|
||||||
public class DeleteClaimedOrganizationUserAccountCommandTests |
|
||||||
{ |
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_WithValidUser_DeletesUserAndLogsEvent( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, Guid deletingUserId, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetByIdAsync(user.Id) |
|
||||||
.Returns(user); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>() |
|
||||||
.GetUsersOrganizationClaimedStatusAsync( |
|
||||||
organizationUser.OrganizationId, |
|
||||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id))) |
|
||||||
.Returns(new Dictionary<Guid, bool> { { organizationUser.Id, true } }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>() |
|
||||||
.HasConfirmedOwnersExceptAsync( |
|
||||||
organizationUser.OrganizationId, |
|
||||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id)), |
|
||||||
includeProvider: Arg.Any<bool>()) |
|
||||||
.Returns(true); |
|
||||||
|
|
||||||
// Act |
|
||||||
await sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId); |
|
||||||
|
|
||||||
// Assert |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(1).DeleteAsync(user); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(1) |
|
||||||
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deleted); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_WithUserNotFound_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, |
|
||||||
Guid organizationId, Guid organizationUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUserId) |
|
||||||
.Returns((OrganizationUser?)null); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<NotFoundException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationId, organizationUserId, null)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("Member not found.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_DeletingYourself_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, |
|
||||||
User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser, |
|
||||||
Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = user.Id = deletingUserId; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id) |
|
||||||
.Returns(user); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("You cannot delete yourself.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_WhenUserIsInvited_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser organizationUser) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = null; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, null)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("You cannot delete a member with Invited status.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_WhenCustomUserDeletesAdmin_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Admin)] OrganizationUser organizationUser, |
|
||||||
Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id) |
|
||||||
.Returns(user); |
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>() |
|
||||||
.OrganizationCustom(organizationUser.OrganizationId) |
|
||||||
.Returns(true); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("Custom users can not delete admins.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_DeletingOwnerWhenNotOwner_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser organizationUser, |
|
||||||
Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id) |
|
||||||
.Returns(user); |
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>() |
|
||||||
.OrganizationOwner(organizationUser.OrganizationId) |
|
||||||
.Returns(false); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("Only owners can delete other owners.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_DeletingLastConfirmedOwner_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser organizationUser, |
|
||||||
Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id) |
|
||||||
.Returns(user); |
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>() |
|
||||||
.OrganizationOwner(organizationUser.OrganizationId) |
|
||||||
.Returns(true); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>() |
|
||||||
.HasConfirmedOwnersExceptAsync( |
|
||||||
organizationUser.OrganizationId, |
|
||||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id)), |
|
||||||
includeProvider: Arg.Any<bool>()) |
|
||||||
.Returns(false); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("Organization must have at least one confirmed owner.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteUserAsync_WithUserNotManaged_ThrowsException( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
organizationUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetByIdAsync(organizationUser.Id) |
|
||||||
.Returns(organizationUser); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id) |
|
||||||
.Returns(user); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>() |
|
||||||
.GetUsersOrganizationClaimedStatusAsync(organizationUser.OrganizationId, Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new Dictionary<Guid, bool> { { organizationUser.Id, false } }); |
|
||||||
|
|
||||||
// Act |
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
||||||
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, null)); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal("Member is not claimed by the organization.", exception.Message); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WithValidUsers_DeletesUsersAndLogsEvents( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user1, User user2, Guid organizationId, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser1, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser2) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser1.OrganizationId = orgUser2.OrganizationId = organizationId; |
|
||||||
orgUser1.UserId = user1.Id; |
|
||||||
orgUser2.UserId = user2.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser1, orgUser2 }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user1.Id) && ids.Contains(user2.Id))) |
|
||||||
.Returns(new[] { user1, user2 }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>() |
|
||||||
.GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new Dictionary<Guid, bool> { { orgUser1.Id, true }, { orgUser2.Id, true } }); |
|
||||||
|
|
||||||
// Act |
|
||||||
var userIds = new[] { orgUser1.Id, orgUser2.Id }; |
|
||||||
var results = await sutProvider.Sut.DeleteManyUsersAsync(organizationId, userIds, null); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal(2, results.Count()); |
|
||||||
Assert.All(results, r => Assert.Empty(r.Item2)); |
|
||||||
|
|
||||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).GetManyAsync(userIds); |
|
||||||
await sutProvider.GetDependency<IUserRepository>().Received(1).DeleteManyAsync(Arg.Is<IEnumerable<User>>(users => users.Any(u => u.Id == user1.Id) && users.Any(u => u.Id == user2.Id))); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationUserEventsAsync( |
|
||||||
Arg.Is<IEnumerable<(OrganizationUser, EventType, DateTime?)>>(events => |
|
||||||
events.Count(e => e.Item1.Id == orgUser1.Id && e.Item2 == EventType.OrganizationUser_Deleted) == 1 |
|
||||||
&& events.Count(e => e.Item1.Id == orgUser2.Id && e.Item2 == EventType.OrganizationUser_Deleted) == 1)); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WhenUserNotFound_ReturnsErrorMessage( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, |
|
||||||
Guid organizationId, |
|
||||||
Guid orgUserId) |
|
||||||
{ |
|
||||||
// Act |
|
||||||
var result = await sutProvider.Sut.DeleteManyUsersAsync(organizationId, new[] { orgUserId }, null); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Single(result); |
|
||||||
Assert.Equal(orgUserId, result.First().Item1); |
|
||||||
Assert.Contains("Member not found.", result.First().Item2); |
|
||||||
await sutProvider.GetDependency<IUserRepository>() |
|
||||||
.DidNotReceiveWithAnyArgs() |
|
||||||
.DeleteManyAsync(default); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WhenDeletingYourself_ReturnsErrorMessage( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, |
|
||||||
User user, [OrganizationUser] OrganizationUser orgUser, Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser.UserId = user.Id = deletingUserId; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user.Id))) |
|
||||||
.Returns(new[] { user }); |
|
||||||
|
|
||||||
// Act |
|
||||||
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, deletingUserId); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Single(result); |
|
||||||
Assert.Equal(orgUser.Id, result.First().Item1); |
|
||||||
Assert.Contains("You cannot delete yourself.", result.First().Item2); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WhenUserIsInvited_ReturnsErrorMessage( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser orgUser) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser.UserId = null; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser }); |
|
||||||
|
|
||||||
// Act |
|
||||||
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, null); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Single(result); |
|
||||||
Assert.Equal(orgUser.Id, result.First().Item1); |
|
||||||
Assert.Contains("You cannot delete a member with Invited status.", result.First().Item2); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WhenDeletingOwnerAsNonOwner_ReturnsErrorMessage( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser orgUser, |
|
||||||
Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(user.Id))) |
|
||||||
.Returns(new[] { user }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>() |
|
||||||
.OrganizationOwner(orgUser.OrganizationId) |
|
||||||
.Returns(false); |
|
||||||
|
|
||||||
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, deletingUserId); |
|
||||||
|
|
||||||
Assert.Single(result); |
|
||||||
Assert.Equal(orgUser.Id, result.First().Item1); |
|
||||||
Assert.Contains("Only owners can delete other owners.", result.First().Item2); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WhenDeletingLastOwner_ReturnsErrorMessage( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser orgUser, |
|
||||||
Guid deletingUserId) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(user.Id))) |
|
||||||
.Returns(new[] { user }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>() |
|
||||||
.OrganizationOwner(orgUser.OrganizationId) |
|
||||||
.Returns(true); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>() |
|
||||||
.HasConfirmedOwnersExceptAsync(orgUser.OrganizationId, Arg.Any<IEnumerable<Guid>>(), Arg.Any<bool>()) |
|
||||||
.Returns(false); |
|
||||||
|
|
||||||
// Act |
|
||||||
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, deletingUserId); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Single(result); |
|
||||||
Assert.Equal(orgUser.Id, result.First().Item1); |
|
||||||
Assert.Contains("Organization must have at least one confirmed owner.", result.First().Item2); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_WhenUserNotManaged_ReturnsErrorMessage( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser.UserId = user.Id; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(orgUser.UserId.Value))) |
|
||||||
.Returns(new[] { user }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>() |
|
||||||
.GetUsersOrganizationClaimedStatusAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new Dictionary<Guid, bool> { { orgUser.Id, false } }); |
|
||||||
|
|
||||||
// Act |
|
||||||
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, null); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Single(result); |
|
||||||
Assert.Equal(orgUser.Id, result.First().Item1); |
|
||||||
Assert.Contains("Member is not claimed by the organization.", result.First().Item2); |
|
||||||
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>()); |
|
||||||
await sutProvider.GetDependency<IEventService>().Received(0) |
|
||||||
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>()); |
|
||||||
} |
|
||||||
|
|
||||||
[Theory] |
|
||||||
[BitAutoData] |
|
||||||
public async Task DeleteManyUsersAsync_MixedValidAndInvalidUsers_ReturnsAppropriateResults( |
|
||||||
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user1, User user3, |
|
||||||
Guid organizationId, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser1, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser orgUser2, |
|
||||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser3) |
|
||||||
{ |
|
||||||
// Arrange |
|
||||||
orgUser1.UserId = user1.Id; |
|
||||||
orgUser2.UserId = null; |
|
||||||
orgUser3.UserId = user3.Id; |
|
||||||
orgUser1.OrganizationId = orgUser2.OrganizationId = orgUser3.OrganizationId = organizationId; |
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>() |
|
||||||
.GetManyAsync(Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new List<OrganizationUser> { orgUser1, orgUser2, orgUser3 }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IUserRepository>() |
|
||||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user1.Id) && ids.Contains(user3.Id))) |
|
||||||
.Returns(new[] { user1, user3 }); |
|
||||||
|
|
||||||
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>() |
|
||||||
.GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any<IEnumerable<Guid>>()) |
|
||||||
.Returns(new Dictionary<Guid, bool> { { orgUser1.Id, true }, { orgUser3.Id, false } }); |
|
||||||
|
|
||||||
// Act |
|
||||||
var results = await sutProvider.Sut.DeleteManyUsersAsync(organizationId, new[] { orgUser1.Id, orgUser2.Id, orgUser3.Id }, null); |
|
||||||
|
|
||||||
// Assert |
|
||||||
Assert.Equal(3, results.Count()); |
|
||||||
Assert.Empty(results.First(r => r.Item1 == orgUser1.Id).Item2); |
|
||||||
Assert.Equal("You cannot delete a member with Invited status.", results.First(r => r.Item1 == orgUser2.Id).Item2); |
|
||||||
Assert.Equal("Member is not claimed by the organization.", results.First(r => r.Item1 == orgUser3.Id).Item2); |
|
||||||
|
|
||||||
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationUserEventsAsync( |
|
||||||
Arg.Is<IEnumerable<(OrganizationUser, EventType, DateTime?)>>(events => |
|
||||||
events.Count(e => e.Item1.Id == orgUser1.Id && e.Item2 == EventType.OrganizationUser_Deleted) == 1)); |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue