using Bit.Core.Enums; using Bit.Core.Utilities; using Bit.Infrastructure.EntityFramework.Repositories; using LinqToDB.EntityFrameworkCore; namespace Bit.Seeder.Recipes; public class CollectionsRecipe(DatabaseContext db) { /// /// Adds collections to an organization and creates relationships between users and collections. /// /// The ID of the organization to add collections to. /// The number of collections to add. /// The IDs of the users to create relationships with. /// The maximum number of users to create relationships with. public List AddToOrganization(Guid organizationId, int collections, List organizationUserIds, int maxUsersWithRelationships = 1000) { var collectionList = CreateAndSaveCollections(organizationId, collections); if (collectionList.Any()) { CreateAndSaveCollectionUserRelationships(collectionList, organizationUserIds, maxUsersWithRelationships); } return collectionList.Select(c => c.Id).ToList(); } private List CreateAndSaveCollections(Guid organizationId, int count) { var collectionList = new List(); for (var i = 0; i < count; i++) { collectionList.Add(new Core.Entities.Collection { Id = CoreHelpers.GenerateComb(), OrganizationId = organizationId, Name = $"Collection {i + 1}", Type = CollectionType.SharedCollection, CreationDate = DateTime.UtcNow, RevisionDate = DateTime.UtcNow }); } if (collectionList.Any()) { db.BulkCopy(collectionList); } return collectionList; } private void CreateAndSaveCollectionUserRelationships( List collections, List organizationUserIds, int maxUsersWithRelationships) { if (!organizationUserIds.Any() || maxUsersWithRelationships <= 0) { return; } var collectionUsers = BuildCollectionUserRelationships(collections, organizationUserIds, maxUsersWithRelationships); if (collectionUsers.Any()) { db.BulkCopy(collectionUsers); } } /// /// Creates user-to-collection relationships with varied assignment patterns for realistic test data. /// Each user gets 1-3 collections based on a rotating pattern. /// private List BuildCollectionUserRelationships( List collections, List organizationUserIds, int maxUsersWithRelationships) { var maxRelationships = Math.Min(organizationUserIds.Count, maxUsersWithRelationships); var collectionUsers = new List(); for (var i = 0; i < maxRelationships; i++) { var orgUserId = organizationUserIds[i]; var userCollectionAssignments = CreateCollectionAssignmentsForUser(collections, orgUserId, i); collectionUsers.AddRange(userCollectionAssignments); } return collectionUsers; } /// /// Assigns collections to a user with varying permissions. /// Pattern: 1-3 collections per user (cycles: 1, 2, 3, 1, 2, 3...). /// First collection has Manage rights, subsequent ones are ReadOnly. /// private List CreateCollectionAssignmentsForUser( List collections, Guid organizationUserId, int userIndex) { var assignments = new List(); var userCollectionCount = (userIndex % 3) + 1; // Cycles through 1, 2, or 3 collections for (var j = 0; j < userCollectionCount; j++) { var collectionIndex = (userIndex + j) % collections.Count; // Distribute across available collections assignments.Add(new Core.Entities.CollectionUser { CollectionId = collections[collectionIndex].Id, OrganizationUserId = organizationUserId, ReadOnly = j > 0, // First assignment gets write access HidePasswords = false, Manage = j == 0 // First assignment gets manage permissions }); } return assignments; } }