diff --git a/util/Seeder/RecipeResult.cs b/util/Seeder/RecipeResult.cs index b7b42b72ff..8e3a5ba55a 100644 --- a/util/Seeder/RecipeResult.cs +++ b/util/Seeder/RecipeResult.cs @@ -1,7 +1,7 @@ -namespace Bit.Seeder; +namespace Bit.Seeder; public class RecipeResult { public required object Result { get; init; } public Dictionary> TrackedEntities { get; init; } = new(); -} \ No newline at end of file +} diff --git a/util/Seeder/Recipes/SingleUserRecipe.cs b/util/Seeder/Recipes/SingleUserRecipe.cs index b62013db1d..49a59d2a72 100644 --- a/util/Seeder/Recipes/SingleUserRecipe.cs +++ b/util/Seeder/Recipes/SingleUserRecipe.cs @@ -6,7 +6,7 @@ namespace Bit.Seeder.Recipes; public class SingleUserRecipe(DatabaseContext db) { - public Dictionary Seed(string email) + public RecipeResult Seed(string email) { var userSeeder = new UserSeeder(Guid.NewGuid()); var user = userSeeder.CreateUser(email); @@ -14,16 +14,23 @@ public class SingleUserRecipe(DatabaseContext db) db.Add(user); db.SaveChanges(); - return userSeeder.GetMangleMap(user, new UserData + return new RecipeResult { - Email = email, - Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), - Key = "seeded_key", - PublicKey = "seeded_public_key", - PrivateKey = "seeded_private_key", - ApiKey = "seeded_api_key", - Kdf = KdfType.PBKDF2_SHA256, - KdfIterations = 600_000, - }); + Result = userSeeder.GetMangleMap(user, new UserData + { + Email = email, + Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), + Key = "seeded_key", + PublicKey = "seeded_public_key", + PrivateKey = "seeded_private_key", + ApiKey = "seeded_api_key", + Kdf = KdfType.PBKDF2_SHA256, + KdfIterations = 600_000, + }), + TrackedEntities = new Dictionary> + { + ["User"] = [user.Id] + } + }; } } diff --git a/util/SeederApi/Controllers/SeedController.cs b/util/SeederApi/Controllers/SeedController.cs index b547fac999..413b7cd814 100644 --- a/util/SeederApi/Controllers/SeedController.cs +++ b/util/SeederApi/Controllers/SeedController.cs @@ -1,7 +1,7 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; using Bit.SeederApi.Services; using Microsoft.AspNetCore.Mvc; -using System.ComponentModel.DataAnnotations; -using System.Text.Json; namespace Bit.SeederApi.Controllers; @@ -99,4 +99,44 @@ public class SeedController : Controller }); } } + + [HttpDelete("/seed")] + public async Task DeleteAll() + { + _logger.LogInformation("Deleting all seeded data"); + + // Pull all Seeded Data ids + var seededData = _recipeService.GetAllSeededData(); + + var aggregateException = new AggregateException(); + + await Task.Run(() => + { + foreach (var sd in seededData) + { + try + { + _recipeService.DestroyRecipe(sd.Id); + } + catch (Exception ex) + { + aggregateException = new AggregateException(aggregateException, ex); + _logger.LogError(ex, "Error deleting seeded data: {SeedId}", sd.Id); + } + } + }); + + if (aggregateException.InnerExceptions.Count > 0) + { + return BadRequest(new + { + Error = "One or more errors occurred while deleting seeded data", + Details = aggregateException.InnerExceptions.Select(e => e.Message).ToList() + }); + } + return Ok(new + { + Message = "All seeded data deleted successfully" + }); + } } diff --git a/util/SeederApi/Services/IRecipeService.cs b/util/SeederApi/Services/IRecipeService.cs index 1347cf9b72..22e9d898ab 100644 --- a/util/SeederApi/Services/IRecipeService.cs +++ b/util/SeederApi/Services/IRecipeService.cs @@ -1,4 +1,5 @@ -using System.Text.Json; +using System.Text.Json; +using Bit.Infrastructure.EntityFramework.Models; namespace Bit.SeederApi.Services; @@ -21,4 +22,5 @@ public interface IRecipeService /// The result of the destroy operation /// Thrown when there's an error destroying the seeded data object? DestroyRecipe(Guid seedId); + List GetAllSeededData(); } diff --git a/util/SeederApi/Services/RecipeService.cs b/util/SeederApi/Services/RecipeService.cs index 587ebb8356..af2ba520e9 100644 --- a/util/SeederApi/Services/RecipeService.cs +++ b/util/SeederApi/Services/RecipeService.cs @@ -1,8 +1,8 @@ +using System.Reflection; +using System.Text.Json; using Bit.Infrastructure.EntityFramework.Models; using Bit.Infrastructure.EntityFramework.Repositories; using Bit.Seeder; -using System.Reflection; -using System.Text.Json; namespace Bit.SeederApi.Services; @@ -17,6 +17,11 @@ public class RecipeService : IRecipeService _logger = logger; } + public List GetAllSeededData() + { + return _databaseContext.SeededData.ToList(); + } + public (object? Result, Guid? SeedId) ExecuteRecipe(string templateName, JsonElement? arguments) { var result = ExecuteRecipeMethod(templateName, arguments, "Seed");