mirror of
https://github.com/bitwarden/server.git
synced 2026-04-12 00:31:55 -05:00
* Fix UpdateCollectionCommand to set RevisionDate using TimeProvider and update corresponding tests. Adjust tests to verify correct RevisionDate assignment during collection updates. * Enhance BulkAddCollectionAccessCommand to include revision date in access updates. Update ICollectionRepository and its implementations to accept revision date parameter. Modify stored procedure to update collection revision dates accordingly. Add tests to verify correct behavior of access creation and revision date updates. * Update GroupRepository and stored procedures to bump RevisionDate for affected collections during group creation and updates. Enhance integration tests to verify that collection revision dates are correctly updated when groups are created or modified. * Implement revision date updates for affected collections in OrganizationUserRepository and related stored procedures. Add integration tests to ensure revision dates are correctly bumped during organization user creation and updates. * Update database migration script * Update migration script summary * Refactor OrganizationUserReplaceTests to create collection first * Refactor stored procedures to use Common Table Expressions (CTEs) for updating RevisionDate of affected collections. This change improves readability and maintainability by consolidating the logic for identifying affected collections in Group_UpdateWithCollections and OrganizationUser_UpdateWithCollections procedures. * Enhance OrganizationUser_CreateManyWithCollectionsAndGroups stored procedure to accept RevisionDate parameter for updating affected collections. Update OrganizationUserRepository to utilize the provided RevisionDate when available, ensuring accurate revision date management during organization user operations. * Refactor OrganizationUser_CreateManyWithCollectionsGroups and migration script to utilize temporary table for CollectionUser data insertion. This change improves performance and maintains consistency in updating RevisionDate for affected collections. * Refactor OrganizationUserRepository to consistently use RevisionDate from created OrganizationUsers when updating affected collections. This change enhances the accuracy of revision date management across the repository. * Refactor tests to ensure consistent handling of RevisionDate across Group and Collection repositories. Update assertions to compare RevisionDate directly, improving accuracy in revision date management during tests. * Restore BOM in Group_UpdateWithCollections and OrganizationUser_UpdateWithCollections * Refactor GroupRepository and OrganizationUserRepository to improve handling of RevisionDate. Updated collection filtering logic to use HashSet for efficiency and ensured that affected collections are filtered by OrganizationId, enhancing accuracy in revision date management. * Bump migration script date * Remove internal set from RevisionDate on Group and OrganizationUser The Dapper repositories use a System.Text.Json serialize/deserialize round-trip to build *WithCollections objects. System.Text.Json silently skips properties with non-public setters, so RevisionDate was reverting to DateTime.UtcNow instead of preserving the value set in C#. * Refactor OrganizationUser_CreateManyWithCollectionsGroups and migration script to improve the logic for updating RevisionDate. The update now uses INNER JOINs to ensure accurate filtering of collections based on OrganizationId and CollectionUser data, enhancing the precision of revision date management. * Fix sprocs styling * Added early return to OrganizationUserRepository.CreateManyAsync if the supplied parameter is empty
650 lines
25 KiB
C#
650 lines
25 KiB
C#
using Bit.Core.AdminConsole.Entities;
|
|
using Bit.Core.AdminConsole.Repositories;
|
|
using Bit.Core.Billing.Enums;
|
|
using Bit.Core.Entities;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Models.Data;
|
|
using Bit.Core.Repositories;
|
|
using Xunit;
|
|
|
|
namespace Bit.Infrastructure.IntegrationTest.AdminConsole.Repositories.CollectionRepository;
|
|
|
|
public class CollectionRepositoryTests
|
|
{
|
|
/// <summary>
|
|
/// Test to ensure that access relationships are retrieved when requested
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetByIdWithPermissionsAsync_WithRelationships_Success(IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository, IGroupRepository groupRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var group = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
var collection = new Collection { Name = "Test Collection", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection, groups: new[]
|
|
{
|
|
new CollectionAccessSelection
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = true, Manage = false
|
|
}
|
|
}, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = false, Manage = true
|
|
}
|
|
});
|
|
|
|
var collectionWithPermissions = await collectionRepository.GetByIdWithPermissionsAsync(collection.Id, user.Id, true);
|
|
|
|
Assert.NotNull(collectionWithPermissions);
|
|
Assert.Equal(1, collectionWithPermissions.Users?.Count());
|
|
Assert.Equal(1, collectionWithPermissions.Groups?.Count());
|
|
Assert.True(collectionWithPermissions.Assigned);
|
|
Assert.True(collectionWithPermissions.Manage);
|
|
Assert.False(collectionWithPermissions.ReadOnly);
|
|
Assert.False(collectionWithPermissions.HidePasswords);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test to ensure that a user's explicitly assigned permissions replaces any group permissions
|
|
/// that user may belong to
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetByIdWithPermissionsAsync_UserOverrideGroup_Success(IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository, IGroupRepository groupRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var group = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
// Assign the test user to the test group
|
|
await groupRepository.UpdateUsersAsync(group.Id, new[] { orgUser.Id });
|
|
|
|
var collection = new Collection { Name = "Test Collection", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection, groups: new[]
|
|
{
|
|
new CollectionAccessSelection
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = false, Manage = true // Group is Manage
|
|
}
|
|
}, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = true, Manage = false // User is given ReadOnly (should override group)
|
|
}
|
|
});
|
|
|
|
var collectionWithPermissions = await collectionRepository.GetByIdWithPermissionsAsync(collection.Id, user.Id, true);
|
|
|
|
Assert.NotNull(collectionWithPermissions);
|
|
Assert.Equal(1, collectionWithPermissions.Users?.Count());
|
|
Assert.Equal(1, collectionWithPermissions.Groups?.Count());
|
|
Assert.True(collectionWithPermissions.Assigned);
|
|
Assert.False(collectionWithPermissions.Manage);
|
|
Assert.True(collectionWithPermissions.ReadOnly);
|
|
Assert.False(collectionWithPermissions.HidePasswords);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test to ensure that the returned permissions are the most permissive combination of group permissions when
|
|
/// multiple groups are assigned to the same collection with different permissions
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetByIdWithPermissionsAsync_CombineGroupPermissions_Success(IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository, IGroupRepository groupRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var group = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
var group2 = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group 2",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
// Assign the test user to the test groups
|
|
await groupRepository.UpdateUsersAsync(group.Id, new[] { orgUser.Id });
|
|
await groupRepository.UpdateUsersAsync(group2.Id, new[] { orgUser.Id });
|
|
|
|
var collection = new Collection { Name = "Test Collection", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection, groups: new[]
|
|
{
|
|
new CollectionAccessSelection
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = true, Manage = false // Group 1 is ReadOnly
|
|
},
|
|
new CollectionAccessSelection
|
|
{
|
|
Id = group2.Id, HidePasswords = false, ReadOnly = false, Manage = true // Group 2 is Manage
|
|
}
|
|
}, users: new List<CollectionAccessSelection>()); // No explicit user permissions for this test
|
|
|
|
var collectionWithPermissions = await collectionRepository.GetByIdWithPermissionsAsync(collection.Id, user.Id, true);
|
|
|
|
Assert.NotNull(collectionWithPermissions);
|
|
Assert.Equal(2, collectionWithPermissions.Groups?.Count());
|
|
Assert.True(collectionWithPermissions.Assigned);
|
|
|
|
// Since Group2 is Manage the user should have Manage
|
|
Assert.True(collectionWithPermissions.Manage);
|
|
|
|
// Similarly, ReadOnly and HidePassword should be false
|
|
Assert.False(collectionWithPermissions.ReadOnly);
|
|
Assert.False(collectionWithPermissions.HidePasswords);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test to ensure the basic usage works as expected
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetManyByOrganizationIdWithPermissionsAsync_Success(IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository, IGroupRepository groupRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var group = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
var collection1 = new Collection { Name = "Collection 1", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection1, groups: new[]
|
|
{
|
|
new CollectionAccessSelection
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = true, Manage = false
|
|
}
|
|
}, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = false, Manage = true
|
|
}
|
|
});
|
|
|
|
var collection2 = new Collection { Name = "Collection 2", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection2, null, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = true, Manage = false
|
|
}
|
|
});
|
|
|
|
var collection3 = new Collection { Name = "Collection 3", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection3, groups: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = false, Manage = true
|
|
}
|
|
}, null);
|
|
|
|
// Create a default user collection (should be excluded from admin console results)
|
|
var defaultCollection = new Collection
|
|
{
|
|
Name = "My Items Collection",
|
|
OrganizationId = organization.Id,
|
|
Type = CollectionType.DefaultUserCollection
|
|
};
|
|
|
|
await collectionRepository.CreateAsync(defaultCollection, null, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = false, Manage = true
|
|
}
|
|
});
|
|
|
|
var collections = await collectionRepository.GetManySharedByOrganizationIdWithPermissionsAsync(organization.Id, user.Id, true);
|
|
|
|
Assert.NotNull(collections);
|
|
|
|
// Should return only 3 collections (excluding the default user collection)
|
|
Assert.Equal(3, collections.Count);
|
|
|
|
collections = collections.OrderBy(c => c.Name).ToList();
|
|
|
|
Assert.Collection(collections, c1 =>
|
|
{
|
|
Assert.NotNull(c1);
|
|
Assert.Equal(1, c1.Users?.Count());
|
|
Assert.Equal(1, c1.Groups?.Count());
|
|
Assert.True(c1.Assigned);
|
|
Assert.True(c1.Manage);
|
|
Assert.False(c1.ReadOnly);
|
|
Assert.False(c1.HidePasswords);
|
|
Assert.False(c1.Unmanaged);
|
|
}, c2 =>
|
|
{
|
|
Assert.NotNull(c2);
|
|
Assert.Equal(1, c2.Users?.Count());
|
|
Assert.Equal(0, c2.Groups?.Count());
|
|
Assert.True(c2.Assigned);
|
|
Assert.False(c2.Manage);
|
|
Assert.True(c2.ReadOnly);
|
|
Assert.False(c2.HidePasswords);
|
|
Assert.True(c2.Unmanaged);
|
|
}, c3 =>
|
|
{
|
|
Assert.NotNull(c3);
|
|
Assert.Equal(0, c3.Users?.Count());
|
|
Assert.Equal(1, c3.Groups?.Count());
|
|
Assert.False(c3.Assigned);
|
|
Assert.False(c3.Manage);
|
|
Assert.False(c3.ReadOnly);
|
|
Assert.False(c3.HidePasswords);
|
|
Assert.False(c3.Unmanaged);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test to ensure collections assigned to multiple groups do not duplicate in the results
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetManyByOrganizationIdWithPermissionsAsync_GroupBy_Success(IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository, IGroupRepository groupRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var group = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
var group2 = await groupRepository.CreateAsync(new Group
|
|
{
|
|
Name = "Test Group 2",
|
|
OrganizationId = organization.Id,
|
|
});
|
|
|
|
// Assign the test user to the test groups
|
|
await groupRepository.UpdateUsersAsync(group.Id, new[] { orgUser.Id });
|
|
await groupRepository.UpdateUsersAsync(group2.Id, new[] { orgUser.Id });
|
|
|
|
var collection1 = new Collection { Name = "Collection 1", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection1, groups: new[]
|
|
{
|
|
new CollectionAccessSelection
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = true, Manage = false
|
|
},
|
|
}, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = false, Manage = true
|
|
}
|
|
});
|
|
|
|
var collection2 = new Collection { Name = "Collection 2", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection2, null, users: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = orgUser.Id, HidePasswords = false, ReadOnly = true, Manage = false
|
|
}
|
|
});
|
|
|
|
var collection3 = new Collection { Name = "Collection 3", OrganizationId = organization.Id, };
|
|
|
|
await collectionRepository.CreateAsync(collection3, groups: new[]
|
|
{
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = group.Id, HidePasswords = false, ReadOnly = false, Manage = true
|
|
},
|
|
new CollectionAccessSelection()
|
|
{
|
|
Id = group2.Id, HidePasswords = false, ReadOnly = true, Manage = false
|
|
}
|
|
}, null);
|
|
|
|
var collections = await collectionRepository.GetManySharedByOrganizationIdWithPermissionsAsync(organization.Id, user.Id, true);
|
|
|
|
Assert.NotNull(collections);
|
|
|
|
Assert.Equal(3, collections.Count);
|
|
|
|
collections = collections.OrderBy(c => c.Name).ToList();
|
|
|
|
Assert.Collection(collections, c1 =>
|
|
{
|
|
Assert.NotNull(c1);
|
|
Assert.Equal(1, c1.Users?.Count());
|
|
Assert.Equal(1, c1.Groups?.Count());
|
|
Assert.True(c1.Assigned);
|
|
Assert.True(c1.Manage);
|
|
Assert.False(c1.ReadOnly);
|
|
Assert.False(c1.HidePasswords);
|
|
Assert.False(c1.Unmanaged);
|
|
}, c2 =>
|
|
{
|
|
Assert.NotNull(c2);
|
|
Assert.Equal(1, c2.Users?.Count());
|
|
Assert.Equal(0, c2.Groups?.Count());
|
|
Assert.True(c2.Assigned);
|
|
Assert.False(c2.Manage);
|
|
Assert.True(c2.ReadOnly);
|
|
Assert.False(c2.HidePasswords);
|
|
Assert.True(c2.Unmanaged);
|
|
}, c3 =>
|
|
{
|
|
Assert.NotNull(c3);
|
|
Assert.Equal(0, c3.Users?.Count());
|
|
Assert.Equal(2, c3.Groups?.Count());
|
|
Assert.True(c3.Assigned); // User is a member of both Groups
|
|
Assert.True(c3.Manage); // Group 2 is Manage
|
|
Assert.False(c3.ReadOnly);
|
|
Assert.False(c3.HidePasswords);
|
|
Assert.False(c3.Unmanaged);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test to ensure collections are properly retrieved by organization
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetManyByOrganizationIdAsync_Success(
|
|
IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var collection1 = new Collection { Name = "Collection 1", OrganizationId = organization.Id, };
|
|
await collectionRepository.CreateAsync(collection1, null, null);
|
|
|
|
var collection2 = new Collection { Name = "Collection 2", OrganizationId = organization.Id, };
|
|
await collectionRepository.CreateAsync(collection2, null, null);
|
|
|
|
var collection3 = new Collection { Name = "Collection 3", OrganizationId = organization.Id, };
|
|
await collectionRepository.CreateAsync(collection3, null, null);
|
|
|
|
// Create a default user collection
|
|
var defaultCollection = new Collection
|
|
{
|
|
Name = "My Items",
|
|
OrganizationId = organization.Id,
|
|
Type = CollectionType.DefaultUserCollection
|
|
};
|
|
await collectionRepository.CreateAsync(defaultCollection, null, null);
|
|
|
|
var collections = await collectionRepository.GetManyByOrganizationIdAsync(organization.Id);
|
|
|
|
Assert.NotNull(collections);
|
|
Assert.Equal(4, collections.Count);
|
|
Assert.All(collections, c => Assert.Equal(organization.Id, c.OrganizationId));
|
|
|
|
Assert.Contains(collections, c => c.Name == "Collection 1");
|
|
Assert.Contains(collections, c => c.Name == "Collection 2");
|
|
Assert.Contains(collections, c => c.Name == "Collection 3");
|
|
Assert.Contains(collections, c => c.Name == "My Items");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Test to ensure organization properly retrieves shared collections
|
|
/// </summary>
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task GetManySharedCollectionsByOrganizationIdAsync_Success(
|
|
IUserRepository userRepository,
|
|
IOrganizationRepository organizationRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IOrganizationUserRepository organizationUserRepository)
|
|
{
|
|
var user = await userRepository.CreateAsync(new User
|
|
{
|
|
Name = "Test User",
|
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
ApiKey = "TEST",
|
|
SecurityStamp = "stamp",
|
|
});
|
|
|
|
var organization = await organizationRepository.CreateAsync(new Organization
|
|
{
|
|
Name = "Test Org",
|
|
PlanType = PlanType.EnterpriseAnnually,
|
|
Plan = "Test Plan",
|
|
BillingEmail = "billing@email.com"
|
|
});
|
|
|
|
var orgUser = await organizationUserRepository.CreateAsync(new OrganizationUser
|
|
{
|
|
OrganizationId = organization.Id,
|
|
UserId = user.Id,
|
|
Status = OrganizationUserStatusType.Confirmed,
|
|
});
|
|
|
|
var collection1 = new Collection { Name = "Collection 1", OrganizationId = organization.Id, };
|
|
await collectionRepository.CreateAsync(collection1, null, null);
|
|
|
|
var collection2 = new Collection { Name = "Collection 2", OrganizationId = organization.Id, };
|
|
await collectionRepository.CreateAsync(collection2, null, null);
|
|
|
|
var collection3 = new Collection { Name = "Collection 3", OrganizationId = organization.Id, };
|
|
await collectionRepository.CreateAsync(collection3, null, null);
|
|
|
|
// Create a default user collection (should not be returned by this method)
|
|
var defaultCollection = new Collection
|
|
{
|
|
Name = "My Items",
|
|
OrganizationId = organization.Id,
|
|
Type = CollectionType.DefaultUserCollection
|
|
};
|
|
await collectionRepository.CreateAsync(defaultCollection, null, null);
|
|
|
|
var collections = await collectionRepository.GetManySharedCollectionsByOrganizationIdAsync(organization.Id);
|
|
|
|
Assert.NotNull(collections);
|
|
Assert.Equal(3, collections.Count); // Should only return the 3 shared collections, excluding the default user collection
|
|
Assert.All(collections, c => Assert.Equal(organization.Id, c.OrganizationId));
|
|
|
|
Assert.Contains(collections, c => c.Name == "Collection 1");
|
|
Assert.Contains(collections, c => c.Name == "Collection 2");
|
|
Assert.Contains(collections, c => c.Name == "Collection 3");
|
|
Assert.DoesNotContain(collections, c => c.Name == "My Items");
|
|
}
|
|
|
|
[DatabaseTheory, DatabaseData]
|
|
public async Task CreateOrUpdateAccessForManyAsync_CreatesAccessAndBumpsRevisionDate(
|
|
IOrganizationRepository organizationRepository,
|
|
IOrganizationUserRepository organizationUserRepository,
|
|
IGroupRepository groupRepository,
|
|
ICollectionRepository collectionRepository,
|
|
IUserRepository userRepository)
|
|
{
|
|
var organization = await organizationRepository.CreateTestOrganizationAsync();
|
|
var user = await userRepository.CreateTestUserAsync();
|
|
var orgUser = await organizationUserRepository.CreateTestOrganizationUserAsync(organization, user);
|
|
var group = await groupRepository.CreateTestGroupAsync(organization);
|
|
var collection = await collectionRepository.CreateTestCollectionAsync(organization);
|
|
|
|
var revisionDate = DateTime.UtcNow.AddMinutes(10);
|
|
|
|
await collectionRepository.CreateOrUpdateAccessForManyAsync(
|
|
organization.Id,
|
|
[collection.Id],
|
|
[new CollectionAccessSelection { Id = orgUser.Id, Manage = true, HidePasswords = false, ReadOnly = false }],
|
|
[new CollectionAccessSelection { Id = group.Id, Manage = false, HidePasswords = true, ReadOnly = true }],
|
|
revisionDate
|
|
);
|
|
|
|
var (actualCollection, actualAccess) = await collectionRepository.GetByIdWithAccessAsync(collection.Id);
|
|
Assert.NotNull(actualCollection);
|
|
Assert.Equal(revisionDate, actualCollection.RevisionDate, TimeSpan.FromMilliseconds(10));
|
|
|
|
var userAccess = Assert.Single(actualAccess.Users);
|
|
Assert.Equal(orgUser.Id, userAccess.Id);
|
|
Assert.True(userAccess.Manage);
|
|
|
|
var groupAccess = Assert.Single(actualAccess.Groups);
|
|
Assert.Equal(group.Id, groupAccess.Id);
|
|
Assert.True(groupAccess.ReadOnly);
|
|
Assert.True(groupAccess.HidePasswords);
|
|
}
|
|
}
|