mirror of
https://github.com/bitwarden/server
synced 2025-12-06 00:03:34 +00:00
[PM-24278] Create Remove Individual Vault validator (#6139)
This commit is contained in:
@@ -278,6 +278,6 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
return;
|
||||
}
|
||||
|
||||
await _collectionRepository.CreateDefaultCollectionsAsync(organizationId, eligibleOrganizationUserIds, defaultUserCollectionName);
|
||||
await _collectionRepository.UpsertDefaultCollectionsAsync(organizationId, eligibleOrganizationUserIds, defaultUserCollectionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
|
||||
@@ -24,19 +25,19 @@ public enum OrganizationDataOwnershipState
|
||||
/// </summary>
|
||||
public class OrganizationDataOwnershipPolicyRequirement : IPolicyRequirement
|
||||
{
|
||||
private readonly IEnumerable<Guid> _organizationIdsWithPolicyEnabled;
|
||||
private readonly IEnumerable<PolicyDetails> _policyDetails;
|
||||
|
||||
/// <param name="organizationDataOwnershipState">
|
||||
/// The organization data ownership state for the user.
|
||||
/// </param>
|
||||
/// <param name="organizationIdsWithPolicyEnabled">
|
||||
/// The collection of Organization IDs that have the Organization Data Ownership policy enabled.
|
||||
/// <param name="policyDetails">
|
||||
/// An enumerable collection of PolicyDetails for the organizations.
|
||||
/// </param>
|
||||
public OrganizationDataOwnershipPolicyRequirement(
|
||||
OrganizationDataOwnershipState organizationDataOwnershipState,
|
||||
IEnumerable<Guid> organizationIdsWithPolicyEnabled)
|
||||
IEnumerable<PolicyDetails> policyDetails)
|
||||
{
|
||||
_organizationIdsWithPolicyEnabled = organizationIdsWithPolicyEnabled ?? [];
|
||||
_policyDetails = policyDetails;
|
||||
State = organizationDataOwnershipState;
|
||||
}
|
||||
|
||||
@@ -46,14 +47,34 @@ public class OrganizationDataOwnershipPolicyRequirement : IPolicyRequirement
|
||||
public OrganizationDataOwnershipState State { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the Organization Data Ownership policy is enforced in that organization.
|
||||
/// Gets a default collection request for enforcing the Organization Data Ownership policy.
|
||||
/// Only confirmed users are applicable.
|
||||
/// This indicates whether the user should have a default collection created for them when the policy is enabled,
|
||||
/// and if so, the relevant OrganizationUserId to create the collection for.
|
||||
/// </summary>
|
||||
public bool RequiresDefaultCollection(Guid organizationId)
|
||||
/// <param name="organizationId">The organization ID to create the request for.</param>
|
||||
/// <returns>A DefaultCollectionRequest containing the OrganizationUserId and a flag indicating whether to create a default collection.</returns>
|
||||
public DefaultCollectionRequest GetDefaultCollectionRequestOnPolicyEnable(Guid organizationId)
|
||||
{
|
||||
return _organizationIdsWithPolicyEnabled.Contains(organizationId);
|
||||
var policyDetail = _policyDetails
|
||||
.FirstOrDefault(p => p.OrganizationId == organizationId);
|
||||
|
||||
if (policyDetail != null && policyDetail.HasStatus([OrganizationUserStatusType.Confirmed]))
|
||||
{
|
||||
return new DefaultCollectionRequest(policyDetail.OrganizationUserId, true);
|
||||
}
|
||||
|
||||
var noCollectionNeeded = new DefaultCollectionRequest(Guid.Empty, false);
|
||||
return noCollectionNeeded;
|
||||
}
|
||||
}
|
||||
|
||||
public record DefaultCollectionRequest(Guid OrganizationUserId, bool ShouldCreateDefaultCollection)
|
||||
{
|
||||
public readonly bool ShouldCreateDefaultCollection = ShouldCreateDefaultCollection;
|
||||
public readonly Guid OrganizationUserId = OrganizationUserId;
|
||||
}
|
||||
|
||||
public class OrganizationDataOwnershipPolicyRequirementFactory : BasePolicyRequirementFactory<OrganizationDataOwnershipPolicyRequirement>
|
||||
{
|
||||
public override PolicyType PolicyType => PolicyType.OrganizationDataOwnership;
|
||||
@@ -63,10 +84,9 @@ public class OrganizationDataOwnershipPolicyRequirementFactory : BasePolicyRequi
|
||||
var organizationDataOwnershipState = policyDetails.Any()
|
||||
? OrganizationDataOwnershipState.Enabled
|
||||
: OrganizationDataOwnershipState.Disabled;
|
||||
var organizationIdsWithPolicyEnabled = policyDetails.Select(p => p.OrganizationId).ToHashSet();
|
||||
|
||||
return new OrganizationDataOwnershipPolicyRequirement(
|
||||
organizationDataOwnershipState,
|
||||
organizationIdsWithPolicyEnabled);
|
||||
policyDetails);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ public static class PolicyServiceCollectionExtensions
|
||||
services.AddScoped<IPolicyValidator, ResetPasswordPolicyValidator>();
|
||||
services.AddScoped<IPolicyValidator, MaximumVaultTimeoutPolicyValidator>();
|
||||
services.AddScoped<IPolicyValidator, FreeFamiliesForEnterprisePolicyValidator>();
|
||||
// This validator will be hooked up in https://bitwarden.atlassian.net/browse/PM-24279.
|
||||
// services.AddScoped<IPolicyValidator, OrganizationDataOwnershipPolicyValidator>();
|
||||
}
|
||||
|
||||
private static void AddPolicyRequirements(this IServiceCollection services)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
|
||||
public class OrganizationDataOwnershipPolicyValidator(
|
||||
IPolicyRepository policyRepository,
|
||||
ICollectionRepository collectionRepository,
|
||||
IEnumerable<IPolicyRequirementFactory<IPolicyRequirement>> factories,
|
||||
IFeatureService featureService,
|
||||
ILogger<OrganizationDataOwnershipPolicyValidator> logger)
|
||||
: OrganizationPolicyValidator(policyRepository, factories)
|
||||
{
|
||||
public override PolicyType Type => PolicyType.OrganizationDataOwnership;
|
||||
|
||||
public override IEnumerable<PolicyType> RequiredPolicies => [];
|
||||
|
||||
public override Task<string> ValidateAsync(PolicyUpdate policyUpdate, Policy? currentPolicy) => Task.FromResult("");
|
||||
|
||||
public override async Task OnSaveSideEffectsAsync(PolicyUpdate policyUpdate, Policy? currentPolicy)
|
||||
{
|
||||
if (!featureService.IsEnabled(FeatureFlagKeys.CreateDefaultLocation))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPolicy?.Enabled != true && policyUpdate.Enabled)
|
||||
{
|
||||
await UpsertDefaultCollectionsForUsersAsync(policyUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpsertDefaultCollectionsForUsersAsync(PolicyUpdate policyUpdate)
|
||||
{
|
||||
var requirements = await GetUserPolicyRequirementsByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(policyUpdate.OrganizationId, policyUpdate.Type);
|
||||
|
||||
var userOrgIds = requirements
|
||||
.Select(requirement => requirement.GetDefaultCollectionRequestOnPolicyEnable(policyUpdate.OrganizationId))
|
||||
.Where(request => request.ShouldCreateDefaultCollection)
|
||||
.Select(request => request.OrganizationUserId);
|
||||
|
||||
if (!userOrgIds.Any())
|
||||
{
|
||||
logger.LogError("No UserOrganizationIds found for {OrganizationId}", policyUpdate.OrganizationId);
|
||||
return;
|
||||
}
|
||||
|
||||
await collectionRepository.UpsertDefaultCollectionsAsync(
|
||||
policyUpdate.OrganizationId,
|
||||
userOrgIds,
|
||||
GetDefaultUserCollectionName());
|
||||
}
|
||||
|
||||
private static string GetDefaultUserCollectionName()
|
||||
{
|
||||
// TODO: https://bitwarden.atlassian.net/browse/PM-24279
|
||||
const string temporaryPlaceHolderValue = "Default";
|
||||
return temporaryPlaceHolderValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
|
||||
public abstract class OrganizationPolicyValidator(IPolicyRepository policyRepository, IEnumerable<IPolicyRequirementFactory<IPolicyRequirement>> factories) : IPolicyValidator
|
||||
{
|
||||
public abstract PolicyType Type { get; }
|
||||
|
||||
public abstract IEnumerable<PolicyType> RequiredPolicies { get; }
|
||||
|
||||
protected async Task<IEnumerable<T>> GetUserPolicyRequirementsByOrganizationIdAsync<T>(Guid organizationId, PolicyType policyType) where T : IPolicyRequirement
|
||||
{
|
||||
var factory = factories.OfType<IPolicyRequirementFactory<T>>().SingleOrDefault();
|
||||
if (factory is null)
|
||||
{
|
||||
throw new NotImplementedException("No Requirement Factory found for " + typeof(T));
|
||||
}
|
||||
|
||||
var policyDetails = await policyRepository.GetPolicyDetailsByOrganizationIdAsync(organizationId, policyType);
|
||||
var policyDetailGroups = policyDetails.GroupBy(policyDetail => policyDetail.UserId);
|
||||
var requirements = new List<T>();
|
||||
|
||||
foreach (var policyDetailGroup in policyDetailGroups)
|
||||
{
|
||||
var filteredPolicies = policyDetailGroup
|
||||
.Where(factory.Enforce)
|
||||
// Prevent deferred execution from causing inconsistent tests.
|
||||
.ToList();
|
||||
|
||||
requirements.Add(factory.Create(filteredPolicies));
|
||||
}
|
||||
|
||||
return requirements;
|
||||
}
|
||||
|
||||
public abstract Task OnSaveSideEffectsAsync(
|
||||
PolicyUpdate policyUpdate,
|
||||
Policy? currentPolicy
|
||||
);
|
||||
|
||||
public abstract Task<string> ValidateAsync(
|
||||
PolicyUpdate policyUpdate,
|
||||
Policy? currentPolicy
|
||||
);
|
||||
}
|
||||
@@ -63,5 +63,5 @@ public interface ICollectionRepository : IRepository<Collection, Guid>
|
||||
Task CreateOrUpdateAccessForManyAsync(Guid organizationId, IEnumerable<Guid> collectionIds,
|
||||
IEnumerable<CollectionAccessSelection> users, IEnumerable<CollectionAccessSelection> groups);
|
||||
|
||||
Task CreateDefaultCollectionsAsync(Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName);
|
||||
Task UpsertDefaultCollectionsAsync(Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName);
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ public class CollectionRepository : Repository<Collection, Guid>, ICollectionRep
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateDefaultCollectionsAsync(Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName)
|
||||
public async Task UpsertDefaultCollectionsAsync(Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName)
|
||||
{
|
||||
if (!affectedOrgUserIds.Any())
|
||||
{
|
||||
|
||||
@@ -793,7 +793,7 @@ public class CollectionRepository : Repository<Core.Entities.Collection, Collect
|
||||
// SaveChangesAsync is expected to be called outside this method
|
||||
}
|
||||
|
||||
public async Task CreateDefaultCollectionsAsync(Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName)
|
||||
public async Task UpsertDefaultCollectionsAsync(Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName)
|
||||
{
|
||||
if (!affectedOrgUserIds.Any())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using AutoFixture;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
|
||||
internal class OrganizationPolicyDetailsCustomization(
|
||||
PolicyType policyType,
|
||||
OrganizationUserType userType,
|
||||
bool isProvider,
|
||||
OrganizationUserStatusType userStatus) : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<OrganizationPolicyDetails>(composer => composer
|
||||
.With(o => o.PolicyType, policyType)
|
||||
.With(o => o.OrganizationUserType, userType)
|
||||
.With(o => o.IsProvider, isProvider)
|
||||
.With(o => o.OrganizationUserStatus, userStatus)
|
||||
.Without(o => o.PolicyData)); // avoid autogenerating invalid json data
|
||||
}
|
||||
}
|
||||
|
||||
public class OrganizationPolicyDetailsAttribute(
|
||||
PolicyType policyType,
|
||||
OrganizationUserType userType = OrganizationUserType.User,
|
||||
bool isProvider = false,
|
||||
OrganizationUserStatusType userStatus = OrganizationUserStatusType.Confirmed) : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
=> new OrganizationPolicyDetailsCustomization(policyType, userType, isProvider, userStatus);
|
||||
}
|
||||
@@ -33,3 +33,5 @@ public class PolicyDetailsAttribute(
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
=> new PolicyDetailsCustomization(policyType, userType, isProvider, userStatus);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@ public class ConfirmOrganizationUserCommandTests
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.Received(1)
|
||||
.CreateDefaultCollectionsAsync(
|
||||
.UpsertDefaultCollectionsAsync(
|
||||
organization.Id,
|
||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(orgUser.Id)),
|
||||
collectionName);
|
||||
@@ -505,7 +505,7 @@ public class ConfirmOrganizationUserCommandTests
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
.UpsertDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -531,6 +531,6 @@ public class ConfirmOrganizationUserCommandTests
|
||||
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
.UpsertDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@@ -30,24 +31,85 @@ public class OrganizationDataOwnershipPolicyRequirementFactoryTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void RequiresDefaultCollection_WithNoPolicies_ReturnsFalse(
|
||||
Guid organizationId,
|
||||
SutProvider<OrganizationDataOwnershipPolicyRequirementFactory> sutProvider)
|
||||
public void PolicyType_ReturnsOrganizationDataOwnership(SutProvider<OrganizationDataOwnershipPolicyRequirementFactory> sutProvider)
|
||||
{
|
||||
var actual = sutProvider.Sut.Create([]);
|
||||
|
||||
Assert.False(actual.RequiresDefaultCollection(organizationId));
|
||||
Assert.Equal(PolicyType.OrganizationDataOwnership, sutProvider.Sut.PolicyType);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void RequiresDefaultCollection_WithOrganizationDataOwnershipPolicies_ReturnsCorrectResult(
|
||||
[PolicyDetails(PolicyType.OrganizationDataOwnership)] PolicyDetails[] policies,
|
||||
Guid nonPolicyOrganizationId,
|
||||
public void GetDefaultCollectionRequestOnPolicyEnable_WithConfirmedUser_ReturnsTrue(
|
||||
[PolicyDetails(PolicyType.OrganizationDataOwnership, userStatus: OrganizationUserStatusType.Confirmed)] PolicyDetails[] policies,
|
||||
SutProvider<OrganizationDataOwnershipPolicyRequirementFactory> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var requirement = sutProvider.Sut.Create(policies);
|
||||
var expectedOrganizationUserId = policies[0].OrganizationUserId;
|
||||
var organizationId = policies[0].OrganizationId;
|
||||
|
||||
// Act
|
||||
var result = requirement.GetDefaultCollectionRequestOnPolicyEnable(organizationId);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedOrganizationUserId, result.OrganizationUserId);
|
||||
Assert.True(result.ShouldCreateDefaultCollection);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void GetDefaultCollectionRequestOnPolicyEnable_WithAcceptedUser_ReturnsFalse(
|
||||
[PolicyDetails(PolicyType.OrganizationDataOwnership, userStatus: OrganizationUserStatusType.Accepted)] PolicyDetails[] policies,
|
||||
SutProvider<OrganizationDataOwnershipPolicyRequirementFactory> sutProvider)
|
||||
{
|
||||
var actual = sutProvider.Sut.Create(policies);
|
||||
// Arrange
|
||||
var requirement = sutProvider.Sut.Create(policies);
|
||||
var organizationId = policies[0].OrganizationId;
|
||||
|
||||
Assert.True(actual.RequiresDefaultCollection(policies[0].OrganizationId));
|
||||
Assert.False(actual.RequiresDefaultCollection(nonPolicyOrganizationId));
|
||||
// Act
|
||||
var result = requirement.GetDefaultCollectionRequestOnPolicyEnable(organizationId);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(Guid.Empty, result.OrganizationUserId);
|
||||
Assert.False(result.ShouldCreateDefaultCollection);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void GetDefaultCollectionRequestOnPolicyEnable_WithNoPolicies_ReturnsFalse(
|
||||
SutProvider<OrganizationDataOwnershipPolicyRequirementFactory> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var requirement = sutProvider.Sut.Create([]);
|
||||
var organizationId = Guid.NewGuid();
|
||||
|
||||
// Act
|
||||
var result = requirement.GetDefaultCollectionRequestOnPolicyEnable(organizationId);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(Guid.Empty, result.OrganizationUserId);
|
||||
Assert.False(result.ShouldCreateDefaultCollection);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public void GetDefaultCollectionRequestOnPolicyEnable_WithMixedStatuses(
|
||||
[PolicyDetails(PolicyType.OrganizationDataOwnership)] PolicyDetails[] policies,
|
||||
SutProvider<OrganizationDataOwnershipPolicyRequirementFactory> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var requirement = sutProvider.Sut.Create(policies);
|
||||
|
||||
var confirmedPolicy = policies[0];
|
||||
var acceptedPolicy = policies[1];
|
||||
|
||||
confirmedPolicy.OrganizationUserStatus = OrganizationUserStatusType.Confirmed;
|
||||
acceptedPolicy.OrganizationUserStatus = OrganizationUserStatusType.Accepted;
|
||||
|
||||
// Act
|
||||
var confirmedResult = requirement.GetDefaultCollectionRequestOnPolicyEnable(confirmedPolicy.OrganizationId);
|
||||
var acceptedResult = requirement.GetDefaultCollectionRequestOnPolicyEnable(acceptedPolicy.OrganizationId);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(Guid.Empty, acceptedResult.OrganizationUserId);
|
||||
Assert.False(acceptedResult.ShouldCreateDefaultCollection);
|
||||
|
||||
Assert.Equal(confirmedPolicy.OrganizationUserId, confirmedResult.OrganizationUserId);
|
||||
Assert.True(confirmedResult.ShouldCreateDefaultCollection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationDataOwnershipPolicyValidatorTests
|
||||
{
|
||||
private const string _defaultUserCollectionName = "Default";
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task OnSaveSideEffectsAsync_FeatureFlagDisabled_DoesNothing(
|
||||
[PolicyUpdate(PolicyType.OrganizationDataOwnership)] PolicyUpdate policyUpdate,
|
||||
[Policy(PolicyType.OrganizationDataOwnership, false)] Policy currentPolicy,
|
||||
SutProvider<OrganizationDataOwnershipPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||
.Returns(false);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, currentPolicy);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.UpsertDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<List<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task OnSaveSideEffectsAsync_PolicyAlreadyEnabled_DoesNothing(
|
||||
[PolicyUpdate(PolicyType.OrganizationDataOwnership)] PolicyUpdate policyUpdate,
|
||||
[Policy(PolicyType.OrganizationDataOwnership, true)] Policy currentPolicy,
|
||||
SutProvider<OrganizationDataOwnershipPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
||||
policyUpdate.Enabled = true;
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||
.Returns(true);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, currentPolicy);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.UpsertDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<List<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task OnSaveSideEffectsAsync_PolicyBeingDisabled_DoesNothing(
|
||||
[PolicyUpdate(PolicyType.OrganizationDataOwnership, false)] PolicyUpdate policyUpdate,
|
||||
[Policy(PolicyType.OrganizationDataOwnership, true)] Policy currentPolicy,
|
||||
SutProvider<OrganizationDataOwnershipPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||
.Returns(true);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, currentPolicy);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.UpsertDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<List<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task OnSaveSideEffectsAsync_WhenNoUsersExist_ShouldLogError(
|
||||
[PolicyUpdate(PolicyType.OrganizationDataOwnership)] PolicyUpdate policyUpdate,
|
||||
[Policy(PolicyType.OrganizationDataOwnership, false)] Policy currentPolicy,
|
||||
OrganizationDataOwnershipPolicyRequirementFactory factory)
|
||||
{
|
||||
// Arrange
|
||||
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
||||
policyUpdate.Enabled = true;
|
||||
|
||||
var policyRepository = ArrangePolicyRepositoryWithOutUsers();
|
||||
var collectionRepository = Substitute.For<ICollectionRepository>();
|
||||
var logger = Substitute.For<ILogger<OrganizationDataOwnershipPolicyValidator>>();
|
||||
|
||||
var sut = ArrangeSut(factory, policyRepository, collectionRepository, logger);
|
||||
|
||||
// Act
|
||||
await sut.OnSaveSideEffectsAsync(policyUpdate, currentPolicy);
|
||||
|
||||
// Assert
|
||||
await collectionRepository
|
||||
.DidNotReceive()
|
||||
.UpsertDefaultCollectionsAsync(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<List<Guid>>(),
|
||||
Arg.Any<string>());
|
||||
|
||||
const string expectedErrorMessage = "No UserOrganizationIds found for";
|
||||
|
||||
logger.Received(1).Log(
|
||||
LogLevel.Error,
|
||||
Arg.Any<EventId>(),
|
||||
Arg.Is<object>(o => (o.ToString() ?? "").Contains(expectedErrorMessage)),
|
||||
Arg.Any<Exception>(),
|
||||
Arg.Any<Func<object, Exception?, string>>());
|
||||
}
|
||||
|
||||
public static IEnumerable<object?[]> ShouldUpsertDefaultCollectionsTestCases()
|
||||
{
|
||||
yield return WithExistingPolicy();
|
||||
|
||||
yield return WithNoExistingPolicy();
|
||||
yield break;
|
||||
|
||||
object?[] WithExistingPolicy()
|
||||
{
|
||||
var organizationId = Guid.NewGuid();
|
||||
var policyUpdate = new PolicyUpdate
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Type = PolicyType.OrganizationDataOwnership,
|
||||
Enabled = true
|
||||
};
|
||||
var currentPolicy = new Policy
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
OrganizationId = organizationId,
|
||||
Type = PolicyType.OrganizationDataOwnership,
|
||||
Enabled = false
|
||||
};
|
||||
|
||||
return new object?[]
|
||||
{
|
||||
policyUpdate,
|
||||
currentPolicy
|
||||
};
|
||||
}
|
||||
|
||||
object?[] WithNoExistingPolicy()
|
||||
{
|
||||
var policyUpdate = new PolicyUpdate
|
||||
{
|
||||
OrganizationId = new Guid(),
|
||||
Type = PolicyType.OrganizationDataOwnership,
|
||||
Enabled = true
|
||||
};
|
||||
|
||||
const Policy currentPolicy = null;
|
||||
|
||||
return new object?[]
|
||||
{
|
||||
policyUpdate,
|
||||
currentPolicy
|
||||
};
|
||||
}
|
||||
}
|
||||
[Theory, BitAutoData]
|
||||
[BitMemberAutoData(nameof(ShouldUpsertDefaultCollectionsTestCases))]
|
||||
public async Task OnSaveSideEffectsAsync_WithRequirements_ShouldUpsertDefaultCollections(
|
||||
[PolicyUpdate(PolicyType.OrganizationDataOwnership)] PolicyUpdate policyUpdate,
|
||||
[Policy(PolicyType.OrganizationDataOwnership, false)] Policy? currentPolicy,
|
||||
[OrganizationPolicyDetails(PolicyType.OrganizationDataOwnership)] IEnumerable<OrganizationPolicyDetails> orgPolicyDetails,
|
||||
OrganizationDataOwnershipPolicyRequirementFactory factory)
|
||||
{
|
||||
// Arrange
|
||||
foreach (var policyDetail in orgPolicyDetails)
|
||||
{
|
||||
policyDetail.OrganizationId = policyUpdate.OrganizationId;
|
||||
}
|
||||
|
||||
var policyRepository = ArrangePolicyRepository(orgPolicyDetails);
|
||||
var collectionRepository = Substitute.For<ICollectionRepository>();
|
||||
var logger = Substitute.For<ILogger<OrganizationDataOwnershipPolicyValidator>>();
|
||||
|
||||
var sut = ArrangeSut(factory, policyRepository, collectionRepository, logger);
|
||||
|
||||
// Act
|
||||
await sut.OnSaveSideEffectsAsync(policyUpdate, currentPolicy);
|
||||
|
||||
// Assert
|
||||
await collectionRepository
|
||||
.Received(1)
|
||||
.UpsertDefaultCollectionsAsync(
|
||||
policyUpdate.OrganizationId,
|
||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Count() == 3),
|
||||
_defaultUserCollectionName);
|
||||
}
|
||||
|
||||
private static IPolicyRepository ArrangePolicyRepositoryWithOutUsers()
|
||||
{
|
||||
return ArrangePolicyRepository([]);
|
||||
}
|
||||
|
||||
private static IPolicyRepository ArrangePolicyRepository(IEnumerable<OrganizationPolicyDetails> policyDetails)
|
||||
{
|
||||
var policyRepository = Substitute.For<IPolicyRepository>();
|
||||
|
||||
policyRepository
|
||||
.GetPolicyDetailsByOrganizationIdAsync(Arg.Any<Guid>(), PolicyType.OrganizationDataOwnership)
|
||||
.Returns(policyDetails);
|
||||
return policyRepository;
|
||||
}
|
||||
|
||||
private static OrganizationDataOwnershipPolicyValidator ArrangeSut(
|
||||
OrganizationDataOwnershipPolicyRequirementFactory factory,
|
||||
IPolicyRepository policyRepository,
|
||||
ICollectionRepository collectionRepository,
|
||||
ILogger<OrganizationDataOwnershipPolicyValidator> logger = null!)
|
||||
{
|
||||
logger ??= Substitute.For<ILogger<OrganizationDataOwnershipPolicyValidator>>();
|
||||
|
||||
var featureService = Substitute.For<IFeatureService>();
|
||||
featureService
|
||||
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
|
||||
.Returns(true);
|
||||
|
||||
var sut = new OrganizationDataOwnershipPolicyValidator(policyRepository, collectionRepository, [factory], featureService, logger);
|
||||
return sut;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationPolicyValidatorTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetUserPolicyRequirementsByOrganizationIdAsync_WithNoFactory_ThrowsNotImplementedException(
|
||||
Guid organizationId,
|
||||
SutProvider<TestOrganizationPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var sut = new TestOrganizationPolicyValidator(sutProvider.GetDependency<IPolicyRepository>(), []);
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<NotImplementedException>(() =>
|
||||
sut.TestGetUserPolicyRequirementsByOrganizationIdAsync<TestPolicyRequirement>(
|
||||
organizationId, PolicyType.TwoFactorAuthentication));
|
||||
|
||||
Assert.Contains("No Requirement Factory found for", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetUserPolicyRequirementsByOrganizationIdAsync_WithMultipleUsers_GroupsByUserId(
|
||||
Guid organizationId,
|
||||
Guid userId1,
|
||||
Guid userId2,
|
||||
SutProvider<TestOrganizationPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var policyDetails = new List<OrganizationPolicyDetails>
|
||||
{
|
||||
new() { UserId = userId1, OrganizationId = organizationId },
|
||||
new() { UserId = userId1, OrganizationId = Guid.NewGuid() },
|
||||
new() { UserId = userId2, OrganizationId = organizationId }
|
||||
};
|
||||
|
||||
var factory = Substitute.For<IPolicyRequirementFactory<TestPolicyRequirement>>();
|
||||
factory.Create(Arg.Any<IEnumerable<PolicyDetails>>()).Returns(new TestPolicyRequirement());
|
||||
factory.Enforce(Arg.Any<PolicyDetails>()).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.TwoFactorAuthentication)
|
||||
.Returns(policyDetails);
|
||||
|
||||
var factories = new List<IPolicyRequirementFactory<IPolicyRequirement>> { factory };
|
||||
var sut = new TestOrganizationPolicyValidator(sutProvider.GetDependency<IPolicyRepository>(), factories);
|
||||
|
||||
// Act
|
||||
var result = await sut.TestGetUserPolicyRequirementsByOrganizationIdAsync<TestPolicyRequirement>(
|
||||
organizationId, PolicyType.TwoFactorAuthentication);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count());
|
||||
|
||||
factory.Received(2).Create(Arg.Any<IEnumerable<OrganizationPolicyDetails>>());
|
||||
factory.Received(1).Create(Arg.Is<IEnumerable<OrganizationPolicyDetails>>(
|
||||
results => results.Count() == 1 && results.First().UserId == userId2));
|
||||
factory.Received(1).Create(Arg.Is<IEnumerable<OrganizationPolicyDetails>>(
|
||||
results => results.Count() == 2 && results.First().UserId == userId1));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetUserPolicyRequirementsByOrganizationIdAsync_ShouldEnforceFilters(
|
||||
Guid organizationId,
|
||||
Guid userId,
|
||||
SutProvider<TestOrganizationPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var adminUser = new OrganizationPolicyDetails()
|
||||
{
|
||||
UserId = userId,
|
||||
OrganizationId = organizationId,
|
||||
OrganizationUserType = OrganizationUserType.Admin
|
||||
};
|
||||
|
||||
var user = new OrganizationPolicyDetails()
|
||||
{
|
||||
UserId = userId,
|
||||
OrganizationId = organizationId,
|
||||
OrganizationUserType = OrganizationUserType.User
|
||||
};
|
||||
|
||||
var policyDetails = new List<OrganizationPolicyDetails>
|
||||
{
|
||||
adminUser,
|
||||
user
|
||||
};
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.TwoFactorAuthentication)
|
||||
.Returns(policyDetails);
|
||||
|
||||
var factory = Substitute.For<IPolicyRequirementFactory<TestPolicyRequirement>>();
|
||||
factory.Create(Arg.Any<IEnumerable<PolicyDetails>>()).Returns(new TestPolicyRequirement());
|
||||
factory.Enforce(Arg.Is<PolicyDetails>(p => p.OrganizationUserType == OrganizationUserType.Admin))
|
||||
.Returns(true);
|
||||
factory.Enforce(Arg.Is<PolicyDetails>(p => p.OrganizationUserType == OrganizationUserType.User))
|
||||
.Returns(false);
|
||||
|
||||
var factories = new List<IPolicyRequirementFactory<IPolicyRequirement>> { factory };
|
||||
var sut = new TestOrganizationPolicyValidator(sutProvider.GetDependency<IPolicyRepository>(), factories);
|
||||
|
||||
// Act
|
||||
var result = await sut.TestGetUserPolicyRequirementsByOrganizationIdAsync<TestPolicyRequirement>(
|
||||
organizationId, PolicyType.TwoFactorAuthentication);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result);
|
||||
|
||||
factory.Received(1).Create(Arg.Is<IEnumerable<PolicyDetails>>(policies =>
|
||||
policies.Count() == 1 && policies.First().OrganizationUserType == OrganizationUserType.Admin));
|
||||
|
||||
factory.Received(1).Enforce(Arg.Is<PolicyDetails>(p => ReferenceEquals(p, adminUser)));
|
||||
factory.Received(1).Enforce(Arg.Is<PolicyDetails>(p => ReferenceEquals(p, user)));
|
||||
factory.Received(2).Enforce(Arg.Any<OrganizationPolicyDetails>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetUserPolicyRequirementsByOrganizationIdAsync_WithEmptyPolicyDetails_ReturnsEmptyCollection(
|
||||
Guid organizationId,
|
||||
SutProvider<TestOrganizationPolicyValidator> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var factory = Substitute.For<IPolicyRequirementFactory<TestPolicyRequirement>>();
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.TwoFactorAuthentication)
|
||||
.Returns(new List<OrganizationPolicyDetails>());
|
||||
|
||||
var factories = new List<IPolicyRequirementFactory<IPolicyRequirement>> { factory };
|
||||
var sut = new TestOrganizationPolicyValidator(sutProvider.GetDependency<IPolicyRepository>(), factories);
|
||||
|
||||
// Act
|
||||
var result = await sut.TestGetUserPolicyRequirementsByOrganizationIdAsync<TestPolicyRequirement>(
|
||||
organizationId, PolicyType.TwoFactorAuthentication);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result);
|
||||
factory.DidNotReceive().Create(Arg.Any<IEnumerable<PolicyDetails>>());
|
||||
}
|
||||
}
|
||||
|
||||
public class TestOrganizationPolicyValidator : OrganizationPolicyValidator
|
||||
{
|
||||
public TestOrganizationPolicyValidator(
|
||||
IPolicyRepository policyRepository,
|
||||
IEnumerable<IPolicyRequirementFactory<IPolicyRequirement>>? factories = null)
|
||||
: base(policyRepository, factories ?? [])
|
||||
{
|
||||
}
|
||||
|
||||
public override PolicyType Type => PolicyType.TwoFactorAuthentication;
|
||||
|
||||
public override IEnumerable<PolicyType> RequiredPolicies => [];
|
||||
|
||||
public override Task<string> ValidateAsync(PolicyUpdate policyUpdate, Policy? currentPolicy)
|
||||
{
|
||||
return Task.FromResult("");
|
||||
}
|
||||
|
||||
public override Task OnSaveSideEffectsAsync(PolicyUpdate policyUpdate, Policy? currentPolicy)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<T>> TestGetUserPolicyRequirementsByOrganizationIdAsync<T>(Guid organizationId, PolicyType policyType)
|
||||
where T : IPolicyRequirement
|
||||
{
|
||||
return await GetUserPolicyRequirementsByOrganizationIdAsync<T>(organizationId, policyType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TestPolicyRequirement : IPolicyRequirement
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
@@ -120,7 +121,7 @@ public class ImportCiphersAsyncCommandTests
|
||||
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(userId)
|
||||
.Returns(new OrganizationDataOwnershipPolicyRequirement(
|
||||
OrganizationDataOwnershipState.Enabled,
|
||||
[Guid.NewGuid()]));
|
||||
[new PolicyDetails()]));
|
||||
|
||||
var folderRelationships = new List<KeyValuePair<int, int>>();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
@@ -173,7 +174,7 @@ public class CipherServiceTests
|
||||
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(savingUserId)
|
||||
.Returns(new OrganizationDataOwnershipPolicyRequirement(
|
||||
OrganizationDataOwnershipState.Enabled,
|
||||
[Guid.NewGuid()]));
|
||||
[new PolicyDetails()]));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveDetailsAsync(cipher, savingUserId, null));
|
||||
|
||||
@@ -6,10 +6,10 @@ using Xunit;
|
||||
|
||||
namespace Bit.Infrastructure.IntegrationTest.AdminConsole.Repositories.CollectionRepository;
|
||||
|
||||
public class CreateDefaultCollectionsTests
|
||||
public class UpsertDefaultCollectionsTests
|
||||
{
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task CreateDefaultCollectionsAsync_ShouldCreateDefaultCollection_WhenUsersDoNotHaveDefaultCollection(
|
||||
[Theory, DatabaseData]
|
||||
public async Task UpsertDefaultCollectionsAsync_ShouldCreateDefaultCollection_WhenUsersDoNotHaveDefaultCollection(
|
||||
IOrganizationRepository organizationRepository,
|
||||
IUserRepository userRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
@@ -28,7 +28,7 @@ public class CreateDefaultCollectionsTests
|
||||
var defaultCollectionName = $"default-name-{organization.Id}";
|
||||
|
||||
// Act
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
|
||||
await collectionRepository.UpsertDefaultCollectionsAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organization.Id);
|
||||
@@ -36,8 +36,8 @@ public class CreateDefaultCollectionsTests
|
||||
await CleanupAsync(organizationRepository, userRepository, organization, resultOrganizationUsers);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task CreateDefaultCollectionsAsync_ShouldUpsertCreateDefaultCollection_ForUsersWithAndWithoutDefaultCollectionsExist(
|
||||
[Theory, DatabaseData]
|
||||
public async Task UpsertDefaultCollectionsAsync_ShouldUpsertCreateDefaultCollection_ForUsersWithAndWithoutDefaultCollectionsExist(
|
||||
IOrganizationRepository organizationRepository,
|
||||
IUserRepository userRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
@@ -66,7 +66,7 @@ public class CreateDefaultCollectionsTests
|
||||
var affectedOrgUserIds = affectedOrgUsers.Select(organizationUser => organizationUser.Id);
|
||||
|
||||
// Act
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
|
||||
await collectionRepository.UpsertDefaultCollectionsAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, arrangedOrganizationUsers, organization.Id);
|
||||
@@ -74,8 +74,8 @@ public class CreateDefaultCollectionsTests
|
||||
await CleanupAsync(organizationRepository, userRepository, organization, affectedOrgUsers);
|
||||
}
|
||||
|
||||
[DatabaseTheory, DatabaseData]
|
||||
public async Task CreateDefaultCollectionsAsync_ShouldNotCreateDefaultCollection_WhenUsersAlreadyHaveOne(
|
||||
[Theory, DatabaseData]
|
||||
public async Task UpsertDefaultCollectionsAsync_ShouldNotCreateDefaultCollection_WhenUsersAlreadyHaveOne(
|
||||
IOrganizationRepository organizationRepository,
|
||||
IUserRepository userRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
@@ -96,7 +96,7 @@ public class CreateDefaultCollectionsTests
|
||||
await CreateUsersWithExistingDefaultCollectionsAsync(collectionRepository, organization.Id, affectedOrgUserIds, defaultCollectionName, resultOrganizationUsers);
|
||||
|
||||
// Act
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
|
||||
await collectionRepository.UpsertDefaultCollectionsAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organization.Id);
|
||||
@@ -108,7 +108,7 @@ public class CreateDefaultCollectionsTests
|
||||
Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName,
|
||||
OrganizationUser[] resultOrganizationUsers)
|
||||
{
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organizationId, affectedOrgUserIds, defaultCollectionName);
|
||||
await collectionRepository.UpsertDefaultCollectionsAsync(organizationId, affectedOrgUserIds, defaultCollectionName);
|
||||
|
||||
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organizationId);
|
||||
}
|
||||
Reference in New Issue
Block a user