mirror of
https://github.com/bitwarden/server
synced 2026-01-05 18:13:31 +00:00
[PM-26636] - Auto Confirm Org User Command (#6488)
* Adding auto confirm endpoint and initial command work. * Adding validator * Finished command implementation. * Enabled the feature renomved used method. Enabled the policy in the tests. * Added extension functions to allow for railroad programming. * Removed guid from route template. Added xml docs * Added validation for command. * Added default collection creation to command. * formatting. * Added additional error types and mapped to appropriate results. * Added tests for auto confirm validator * Adding tests * fixing file name * Cleaned up OrgUserController. Added integration tests. * Consolidated CommandResult and validation result stuff into a v2 directory. * changing result to match handle method. * Moves validation thenasync method. * Added brackets. * Updated XML comment * Adding idempotency comment. * Fixed up merge problems. Fixed return types for handle. * Renamed to ValidationRequest * I added some methods for CommandResult to cover some future use cases. Added ApplyAsync method to execute multiple functions against CommandResult without an error stopping the workflow for side-effects. * Fixed up logic around should create default colleciton. Added more methods for chaining ValidationResult together. Added logic for user type. * Clearing nullable enable. * Fixed up validator tests. * Tests for auto confirm command * Fixed up command result and AutoConfirmCommand. * Removed some unused methods. * Moved autoconfirm tests to their own class. * Moved some stuff around. Need to clean up creation of accepted org user yet. * Moved some more code around. Folded Key into accepted constructor. removed unneeded tests since key and accepted are now a part of AcceptedOrgUser Creation. * Clean up clean up everybody everywhere. Clean up clean up everybody do your share. * Another quick one * Removed aggregate Errors.cs * Cleaned up validator and fixed up tests. * Fixed auto confirm repo * Cleaned up command tests. * Unused method. * Restoring Bulk command back to what it was. deleted handle method for bulk. * Remove unused method. * removed unnecssary lines and comments * fixed layout. * Fixed test. * fixed spelling mistake. removed unused import. * Update test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUsers/AutomaticallyConfirmUsersCommandTests.cs Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com> * Ensuring collection is created before full sync. Cleaning up tests and added a few more. Added check that the policy is enabled. * Added org cleanup * Lowering to 5 to see if that helps the runner. * 🤷 * Trying this * Maybe this time will be different. * seeing if awaiting and checking independently will work in ci * I figured it out. Locally, it would be fast enough to all return NoContent, however in CI, its slow enough for it to return 400 due to the user already being confirmed via validation. * Updated tests and validator * Fixed name --------- Co-authored-by: Rui Tomé <108268980+r-tome@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,696 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
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.AutoConfirmUsers;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class AutomaticallyConfirmOrganizationUsersValidatorTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithNullOrganizationUser_ReturnsUserNotFoundError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = null,
|
||||
OrganizationUserId = Guid.NewGuid(),
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<UserNotFoundError>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithNullUserId_ReturnsUserNotFoundError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = null;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<UserNotFoundError>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithNullOrganization_ReturnsOrganizationNotFoundError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = null,
|
||||
OrganizationId = organizationUser.OrganizationId,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<OrganizationNotFound>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithValidAcceptedUser_ReturnsValidResult(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true, planType: PlanType.EnterpriseAnnually)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
Assert.Equal(request, result.Request);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithMismatchedOrganizationId_ReturnsOrganizationUserIdIsInvalidError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = Guid.NewGuid(); // Different from organization.Id
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<OrganizationUserIdIsInvalid>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationUserStatusType.Invited)]
|
||||
[BitAutoData(OrganizationUserStatusType.Revoked)]
|
||||
[BitAutoData(OrganizationUserStatusType.Confirmed)]
|
||||
public async Task ValidateAsync_WithNotAcceptedStatus_ReturnsUserIsNotAcceptedError(
|
||||
OrganizationUserStatusType statusType,
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
organizationUser.Status = statusType;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<UserIsNotAccepted>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(OrganizationUserType.Owner)]
|
||||
[BitAutoData(OrganizationUserType.Custom)]
|
||||
[BitAutoData(OrganizationUserType.Admin)]
|
||||
public async Task ValidateAsync_WithNonUserType_ReturnsUserIsNotUserTypeError(
|
||||
OrganizationUserType userType,
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
organizationUser.Type = userType;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<UserIsNotUserType>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserWithout2FA_And2FARequired_ReturnsError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
var twoFactorPolicyDetails = new PolicyDetails
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
PolicyType = PolicyType.TwoFactorAuthentication
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, false)]);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<RequireTwoFactorPolicyRequirement>(userId)
|
||||
.Returns(new RequireTwoFactorPolicyRequirement([twoFactorPolicyDetails]));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<UserDoesNotHaveTwoFactorEnabled>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserWith2FA_ReturnsValidResult(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserWithout2FA_And2FANotRequired_ReturnsValidResult(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, false)]);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<RequireTwoFactorPolicyRequirement>(userId)
|
||||
.Returns(new RequireTwoFactorPolicyRequirement([])); // No 2FA policy
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserInMultipleOrgs_WithSingleOrgPolicyOnThisOrg_ReturnsError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
OrganizationUser otherOrgUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
var singleOrgPolicyDetails = new PolicyDetails
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
PolicyType = PolicyType.SingleOrg
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser, otherOrgUser]);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<SingleOrganizationPolicyRequirement>(userId)
|
||||
.Returns(new SingleOrganizationPolicyRequirement([singleOrgPolicyDetails]));
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<OrganizationEnforcesSingleOrgPolicy>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserInMultipleOrgs_WithSingleOrgPolicyOnOtherOrg_ReturnsError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
OrganizationUser otherOrgUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
var otherOrgId = Guid.NewGuid(); // Different org
|
||||
var singleOrgPolicyDetails = new PolicyDetails
|
||||
{
|
||||
OrganizationId = otherOrgId,
|
||||
PolicyType = PolicyType.SingleOrg,
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser, otherOrgUser]);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<SingleOrganizationPolicyRequirement>(userId)
|
||||
.Returns(new SingleOrganizationPolicyRequirement([singleOrgPolicyDetails]));
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<OtherOrganizationEnforcesSingleOrgPolicy>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserInSingleOrg_ReturnsValidResult(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]); // Single org
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_UserInMultipleOrgs_WithNoSingleOrgPolicy_ReturnsValidResult(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
OrganizationUser otherOrgUser,
|
||||
Guid userId,
|
||||
Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
autoConfirmPolicy.Type = PolicyType.AutomaticUserConfirmation;
|
||||
autoConfirmPolicy.Enabled = true;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser, otherOrgUser]);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<SingleOrganizationPolicyRequirement>(userId)
|
||||
.Returns(new SingleOrganizationPolicyRequirement([]));
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithAutoConfirmPolicyDisabled_ReturnsAutoConfirmPolicyNotEnabledError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns((Policy)null);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<AutomaticallyConfirmUsersPolicyIsNotEnabled>(result.AsError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task ValidateAsync_WithOrganizationUseAutomaticUserConfirmationDisabled_ReturnsAutoConfirmPolicyNotEnabledError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
|
||||
[Organization(useAutomaticUserConfirmation: false)] Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
Guid userId,
|
||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = userId;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = Substitute.For<IActingUser>(),
|
||||
DefaultUserCollectionName = "test-collection",
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
Organization = organization,
|
||||
OrganizationId = organization.Id,
|
||||
Key = "test-key"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
|
||||
.Returns(autoConfirmPolicy);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns([(userId, true)]);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByUserAsync(userId)
|
||||
.Returns([organizationUser]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.ValidateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<AutomaticallyConfirmUsersPolicyIsNotEnabled>(result.AsError);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,730 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.Models.Data.OrganizationUsers;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Utilities.v2;
|
||||
using Bit.Core.AdminConsole.Utilities.v2.Validation;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Platform.Push;
|
||||
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 Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ExceptionExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUsers;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class AutomaticallyConfirmUsersCommandTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WithValidRequest_ConfirmsUserSuccessfully(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.Received(1)
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key));
|
||||
|
||||
await AssertSuccessfulOperationsAsync(sutProvider, organizationUser, organization, user, key);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WithInvalidUserOrgId_ReturnsOrganizationUserIdIsInvalidError(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = Guid.NewGuid(); // User belongs to another organization
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, false, new OrganizationUserIdIsInvalid());
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsError);
|
||||
Assert.IsType<OrganizationUserIdIsInvalid>(result.AsError);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.DidNotReceive()
|
||||
.ConfirmOrganizationUserAsync(Arg.Any<AcceptedOrganizationUserToConfirm>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenAlreadyConfirmed_ReturnsNoneSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
// Return false to indicate the user is already confirmed
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(x =>
|
||||
x.OrganizationUserId == organizationUser.Id && x.Key == request.Key))
|
||||
.Returns(false);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.Received(1)
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(x =>
|
||||
x.OrganizationUserId == organizationUser.Id && x.Key == request.Key));
|
||||
|
||||
// Verify no side effects occurred
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.DidNotReceive()
|
||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
|
||||
|
||||
await sutProvider.GetDependency<IPushNotificationService>()
|
||||
.DidNotReceive()
|
||||
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WithDefaultCollectionEnabled_CreatesDefaultCollection(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName, // Non-empty to trigger creation
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
SetupPolicyRequirementMock(sutProvider, user.Id, organization.Id, true); // Policy requires collection
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().ConfirmOrganizationUserAsync(
|
||||
Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.Received(1)
|
||||
.CreateAsync(
|
||||
Arg.Is<Collection>(c =>
|
||||
c.OrganizationId == organization.Id &&
|
||||
c.Name == defaultCollectionName &&
|
||||
c.Type == CollectionType.DefaultUserCollection),
|
||||
Arg.Is<IEnumerable<CollectionAccessSelection>>(groups => groups == null),
|
||||
Arg.Is<IEnumerable<CollectionAccessSelection>>(access =>
|
||||
access.FirstOrDefault(x => x.Id == organizationUser.Id && x.Manage) != null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WithDefaultCollectionDisabled_DoesNotCreateCollection(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = string.Empty, // Empty, so the collection won't be created
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
SetupPolicyRequirementMock(sutProvider, user.Id, organization.Id, false); // Policy doesn't require
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateAsync(Arg.Any<Collection>(),
|
||||
Arg.Any<IEnumerable<CollectionAccessSelection>>(),
|
||||
Arg.Any<IEnumerable<CollectionAccessSelection>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenCreateDefaultCollectionFails_LogsErrorButReturnsSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName, // Non-empty to trigger creation
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
SetupPolicyRequirementMock(sutProvider, user.Id, organization.Id, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key)).Returns(true);
|
||||
|
||||
var collectionException = new Exception("Collection creation failed");
|
||||
sutProvider.GetDependency<ICollectionRepository>()
|
||||
.CreateAsync(Arg.Any<Collection>(),
|
||||
Arg.Any<IEnumerable<CollectionAccessSelection>>(),
|
||||
Arg.Any<IEnumerable<CollectionAccessSelection>>())
|
||||
.ThrowsAsync(collectionException);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert - side effects are fire-and-forget, so command returns success even if collection creation fails
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
sutProvider.GetDependency<ILogger<AutomaticallyConfirmOrganizationUserCommand>>()
|
||||
.Received(1)
|
||||
.Log(
|
||||
LogLevel.Error,
|
||||
Arg.Any<EventId>(),
|
||||
Arg.Is<object>(o => o.ToString()!.Contains("Failed to create default collection for user")),
|
||||
collectionException,
|
||||
Arg.Any<Func<object, Exception?, string>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenEventLogFails_LogsErrorButReturnsSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
var eventException = new Exception("Event logging failed");
|
||||
sutProvider.GetDependency<IEventService>()
|
||||
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(),
|
||||
EventType.OrganizationUser_AutomaticallyConfirmed,
|
||||
Arg.Any<DateTime?>())
|
||||
.ThrowsAsync(eventException);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert - side effects are fire-and-forget, so command returns success even if event log fails
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
sutProvider.GetDependency<ILogger<AutomaticallyConfirmOrganizationUserCommand>>()
|
||||
.Received(1)
|
||||
.Log(
|
||||
LogLevel.Error,
|
||||
Arg.Any<EventId>(),
|
||||
Arg.Is<object>(o => o.ToString()!.Contains("Failed to log OrganizationUser_AutomaticallyConfirmed event")),
|
||||
eventException,
|
||||
Arg.Any<Func<object, Exception?, string>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenSendEmailFails_LogsErrorButReturnsSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
var emailException = new Exception("Email sending failed");
|
||||
sutProvider.GetDependency<IMailService>()
|
||||
.SendOrganizationConfirmedEmailAsync(organization.Name, user.Email, organizationUser.AccessSecretsManager)
|
||||
.ThrowsAsync(emailException);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert - side effects are fire-and-forget, so command returns success even if email fails
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
sutProvider.GetDependency<ILogger<AutomaticallyConfirmOrganizationUserCommand>>()
|
||||
.Received(1)
|
||||
.Log(
|
||||
LogLevel.Error,
|
||||
Arg.Any<EventId>(),
|
||||
Arg.Is<object>(o => o.ToString()!.Contains("Failed to send OrganizationUserConfirmed")),
|
||||
emailException,
|
||||
Arg.Any<Func<object, Exception?, string>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenUserNotFoundForEmail_LogsErrorButReturnsSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
// Return null when retrieving user for email
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
.GetByIdAsync(user.Id)
|
||||
.Returns((User)null!);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert - side effects are fire-and-forget, so command returns success even if user not found for email
|
||||
Assert.True(result.IsSuccess);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenDeleteDeviceRegistrationFails_LogsErrorButReturnsSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName,
|
||||
Device device)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
device.UserId = user.Id;
|
||||
device.PushToken = "test-push-token";
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<Device> { device });
|
||||
|
||||
var deviceException = new Exception("Device registration deletion failed");
|
||||
sutProvider.GetDependency<IPushRegistrationService>()
|
||||
.DeleteUserRegistrationOrganizationAsync(Arg.Any<IEnumerable<string>>(), organization.Id.ToString())
|
||||
.ThrowsAsync(deviceException);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert - side effects are fire-and-forget, so command returns success even if device registration deletion fails
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
sutProvider.GetDependency<ILogger<AutomaticallyConfirmOrganizationUserCommand>>()
|
||||
.Received(1)
|
||||
.Log(
|
||||
LogLevel.Error,
|
||||
Arg.Any<EventId>(),
|
||||
Arg.Is<object>(o => o.ToString()!.Contains("Failed to delete device registration")),
|
||||
deviceException,
|
||||
Arg.Any<Func<object, Exception?, string>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WhenPushSyncOrgKeysFails_LogsErrorButReturnsSuccess(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
var pushException = new Exception("Push sync failed");
|
||||
sutProvider.GetDependency<IPushNotificationService>()
|
||||
.PushSyncOrgKeysAsync(user.Id)
|
||||
.ThrowsAsync(pushException);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert - side effects are fire-and-forget, so command returns success even if push sync fails
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
sutProvider.GetDependency<ILogger<AutomaticallyConfirmOrganizationUserCommand>>()
|
||||
.Received(1)
|
||||
.Log(
|
||||
LogLevel.Error,
|
||||
Arg.Any<EventId>(),
|
||||
Arg.Is<object>(o => o.ToString()!.Contains("Failed to push organization keys")),
|
||||
pushException,
|
||||
Arg.Any<Func<object, Exception?, string>>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task AutomaticallyConfirmOrganizationUserAsync_WithDevicesWithoutPushToken_FiltersCorrectly(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
|
||||
User user,
|
||||
Guid performingUserId,
|
||||
string key,
|
||||
string defaultCollectionName,
|
||||
Device deviceWithToken,
|
||||
Device deviceWithoutToken)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.UserId = user.Id;
|
||||
organizationUser.OrganizationId = organization.Id;
|
||||
deviceWithToken.UserId = user.Id;
|
||||
deviceWithToken.PushToken = "test-token";
|
||||
deviceWithoutToken.UserId = user.Id;
|
||||
deviceWithoutToken.PushToken = null;
|
||||
var request = new AutomaticallyConfirmOrganizationUserRequest
|
||||
{
|
||||
OrganizationUserId = organizationUser.Id,
|
||||
OrganizationId = organization.Id,
|
||||
Key = key,
|
||||
DefaultUserCollectionName = defaultCollectionName,
|
||||
PerformedBy = new StandardUser(performingUserId, true)
|
||||
};
|
||||
|
||||
SetupRepositoryMocks(sutProvider, organizationUser, organization, user);
|
||||
SetupValidatorMock(sutProvider, request, organizationUser, organization, true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.ConfirmOrganizationUserAsync(Arg.Is<AcceptedOrganizationUserToConfirm>(o =>
|
||||
o.OrganizationUserId == organizationUser.Id && o.Key == request.Key))
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<Device> { deviceWithToken, deviceWithoutToken });
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AutomaticallyConfirmOrganizationUserAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuccess);
|
||||
|
||||
await sutProvider.GetDependency<IPushRegistrationService>()
|
||||
.Received(1)
|
||||
.DeleteUserRegistrationOrganizationAsync(
|
||||
Arg.Is<IEnumerable<string>>(devices =>
|
||||
devices.Count(d => deviceWithToken.Id.ToString() == d) == 1),
|
||||
organization.Id.ToString());
|
||||
}
|
||||
|
||||
private static void SetupRepositoryMocks(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
OrganizationUser organizationUser,
|
||||
Organization organization,
|
||||
User user)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByIdAsync(organizationUser.Id)
|
||||
.Returns(organizationUser);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
.GetByIdAsync(user.Id)
|
||||
.Returns(user);
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<Device>());
|
||||
}
|
||||
|
||||
private static void SetupValidatorMock(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
AutomaticallyConfirmOrganizationUserRequest originalRequest,
|
||||
OrganizationUser organizationUser,
|
||||
Organization organization,
|
||||
bool isValid,
|
||||
Error? error = null)
|
||||
{
|
||||
var validationRequest = new AutomaticallyConfirmOrganizationUserValidationRequest
|
||||
{
|
||||
PerformedBy = originalRequest.PerformedBy,
|
||||
DefaultUserCollectionName = originalRequest.DefaultUserCollectionName,
|
||||
OrganizationUserId = originalRequest.OrganizationUserId,
|
||||
OrganizationUser = organizationUser,
|
||||
OrganizationId = originalRequest.OrganizationId,
|
||||
Organization = organization,
|
||||
Key = originalRequest.Key
|
||||
};
|
||||
|
||||
var validationResult = isValid
|
||||
? ValidationResultHelpers.Valid(validationRequest)
|
||||
: ValidationResultHelpers.Invalid(validationRequest, error ?? new UserIsNotAccepted());
|
||||
|
||||
sutProvider.GetDependency<IAutomaticallyConfirmOrganizationUsersValidator>()
|
||||
.ValidateAsync(Arg.Any<AutomaticallyConfirmOrganizationUserValidationRequest>())
|
||||
.Returns(validationResult);
|
||||
}
|
||||
|
||||
private static void SetupPolicyRequirementMock(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
Guid userId,
|
||||
Guid organizationId,
|
||||
bool requiresDefaultCollection)
|
||||
{
|
||||
var policyDetails = requiresDefaultCollection
|
||||
? new List<PolicyDetails> { new() { OrganizationId = organizationId } }
|
||||
: new List<PolicyDetails>();
|
||||
|
||||
var policyRequirement = new OrganizationDataOwnershipPolicyRequirement(
|
||||
requiresDefaultCollection ? OrganizationDataOwnershipState.Enabled : OrganizationDataOwnershipState.Disabled,
|
||||
policyDetails);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(userId)
|
||||
.Returns(policyRequirement);
|
||||
}
|
||||
|
||||
private static async Task AssertSuccessfulOperationsAsync(
|
||||
SutProvider<AutomaticallyConfirmOrganizationUserCommand> sutProvider,
|
||||
OrganizationUser organizationUser,
|
||||
Organization organization,
|
||||
User user,
|
||||
string key)
|
||||
{
|
||||
await sutProvider.GetDependency<IEventService>()
|
||||
.Received(1)
|
||||
.LogOrganizationUserEventAsync(
|
||||
Arg.Is<OrganizationUser>(x => x.Id == organizationUser.Id),
|
||||
EventType.OrganizationUser_AutomaticallyConfirmed,
|
||||
Arg.Any<DateTime?>());
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendOrganizationConfirmedEmailAsync(
|
||||
organization.Name,
|
||||
user.Email,
|
||||
organizationUser.AccessSecretsManager);
|
||||
|
||||
await sutProvider.GetDependency<IPushNotificationService>()
|
||||
.Received(1)
|
||||
.PushSyncOrgKeysAsync(user.Id);
|
||||
|
||||
await sutProvider.GetDependency<IPushRegistrationService>()
|
||||
.Received(1)
|
||||
.DeleteUserRegistrationOrganizationAsync(
|
||||
Arg.Any<IEnumerable<string>>(),
|
||||
organization.Id.ToString());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.Utilities.v2;
|
||||
using Bit.Core.AdminConsole.Utilities.v2.Validation;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
|
||||
Reference in New Issue
Block a user