using AutoMapper; using Bit.Core.Entities; using Bit.Infrastructure.EntityFramework.Repositories; using Bit.Seeder.Services; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; namespace Bit.Seeder.Pipeline; /// /// Orchestrates preset-based seeding by coordinating the Pipeline infrastructure. /// internal sealed class PresetExecutor(DatabaseContext db, IMapper mapper) { /// /// Executes a preset by registering its recipe, building a service provider, and running all steps. /// /// Name of the embedded preset (e.g., "dunder-mifflin-full") /// Password hasher for user creation /// Mangler service for test isolation /// Optional password for all seeded accounts /// Execution result with organization ID and entity counts internal ExecutionResult Execute( string presetName, IPasswordHasher passwordHasher, IManglerService manglerService, string? password = null) { var reader = new SeedReader(); var services = new ServiceCollection(); services.AddSingleton(passwordHasher); services.AddSingleton(manglerService); services.AddSingleton(reader); services.AddSingleton(new SeederSettings(password)); services.AddSingleton(db); PresetLoader.RegisterRecipe(presetName, reader, services); using var serviceProvider = services.BuildServiceProvider(); var committer = new BulkCommitter(db, mapper); var executor = new RecipeExecutor(presetName, serviceProvider, committer); return executor.Execute(); } /// /// Lists all available embedded presets and fixtures. /// /// Available presets grouped by category internal static AvailableSeeds ListAvailable() { var seedReader = new SeedReader(); var all = seedReader.ListAvailable(); var presets = all.Where(n => n.StartsWith("presets.")) .Select(n => n["presets.".Length..]) .ToList(); var fixtures = all.Where(n => !n.StartsWith("presets.")) .GroupBy(n => n.Split('.')[0]) .ToDictionary( g => g.Key, g => (IReadOnlyList)g.ToList()); return new AvailableSeeds(presets, fixtures); } } /// /// Result of pipeline execution with organization ID and entity counts. /// internal record ExecutionResult( Guid OrganizationId, string? OwnerEmail, int UsersCount, int GroupsCount, int CollectionsCount, int CiphersCount); /// /// Available presets and fixtures grouped by category. /// internal record AvailableSeeds( IReadOnlyList Presets, IReadOnlyDictionary> Fixtures);