From ce32a9c6b745320a696cd4c218b1c6d902cba0ac Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 8 Jun 2026 18:57:38 -0400 Subject: [PATCH] feat(home-dialog): seed file + importer + bootstrap hookup Mirrors banners pattern: clear-and-rewrite from per-table JSON seed. Ships one entry pointing at parent_gacha_id 80032 to match the 2026-06-03 prod capture. Co-Authored-By: Claude Opus 4.7 --- SVSim.Bootstrap/Data/seeds/home-dialogs.json | 14 ++++++ .../Importers/MyPageGlobalsImporter.cs | 35 ++++++++++++++ SVSim.Bootstrap/Models/Seed/HomeDialogSeed.cs | 16 +++++++ SVSim.Bootstrap/Program.cs | 1 + .../Importers/MyPageGlobalsImporterTests.cs | 47 +++++++++++++++++++ .../Infrastructure/SVSimTestFactory.cs | 1 + 6 files changed, 114 insertions(+) create mode 100644 SVSim.Bootstrap/Data/seeds/home-dialogs.json create mode 100644 SVSim.Bootstrap/Models/Seed/HomeDialogSeed.cs diff --git a/SVSim.Bootstrap/Data/seeds/home-dialogs.json b/SVSim.Bootstrap/Data/seeds/home-dialogs.json new file mode 100644 index 0000000..7958135 --- /dev/null +++ b/SVSim.Bootstrap/Data/seeds/home-dialogs.json @@ -0,0 +1,14 @@ +[ + { + "id": 1, + "title_text_id": "HomeDialog_0066", + "image": "home_dialog_000312", + "button_list": [ + { "button_text_id": "HomeDialog_0002", "scene": "card_pack", "status": "80032" } + ], + "begin_time": "2026-06-01 02:00:00", + "end_time": "2026-07-01 01:59:59", + "type": 1, + "priority": 0 + } +] diff --git a/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs b/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs index d18386e..9373c81 100644 --- a/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs +++ b/SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs @@ -46,6 +46,41 @@ public class MyPageGlobalsImporter return seed.Count; } + public async Task ImportHomeDialogsAsync(SVSimDbContext context, string seedDir) + { + var seed = SeedLoader.LoadList(Path.Combine(seedDir, "home-dialogs.json")); + if (seed.Count == 0) + { + Console.WriteLine("[MyPageGlobalsImporter] No home-dialog seed rows; skipping."); + return 0; + } + + // Clear-and-rewrite — same semantics as banners. Seed file is authoritative. + var existing = await context.HomeDialogEntries.ToListAsync(); + context.HomeDialogEntries.RemoveRange(existing); + + foreach (var s in seed) + { + context.HomeDialogEntries.Add(new HomeDialogEntry + { + Id = s.Id, + TitleTextId = s.TitleTextId, + Image = s.Image, + ButtonListJson = s.ButtonList.ValueKind == JsonValueKind.Undefined + ? "[]" + : JsonSerializer.Serialize(s.ButtonList), + BeginTime = ImporterBase.ParseWireDateTime(s.BeginTime), + EndTime = ImporterBase.ParseWireDateTime(s.EndTime), + Type = s.Type, + Priority = s.Priority, + }); + } + + await context.SaveChangesAsync(); + Console.WriteLine($"[MyPageGlobalsImporter] HomeDialogs: -{existing.Count}/+{seed.Count}"); + return seed.Count; + } + public async Task ImportColosseumAsync(SVSimDbContext context, string seedDir) { var s = SeedLoader.LoadObject(Path.Combine(seedDir, "colosseum.json")); diff --git a/SVSim.Bootstrap/Models/Seed/HomeDialogSeed.cs b/SVSim.Bootstrap/Models/Seed/HomeDialogSeed.cs new file mode 100644 index 0000000..4edc56b --- /dev/null +++ b/SVSim.Bootstrap/Models/Seed/HomeDialogSeed.cs @@ -0,0 +1,16 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace SVSim.Bootstrap.Models.Seed; + +public sealed class HomeDialogSeed +{ + [JsonPropertyName("id")] public int Id { get; set; } + [JsonPropertyName("title_text_id")] public string TitleTextId { get; set; } = ""; + [JsonPropertyName("image")] public string Image { get; set; } = ""; + [JsonPropertyName("button_list")] public JsonElement ButtonList { get; set; } + [JsonPropertyName("begin_time")] public string BeginTime { get; set; } = ""; + [JsonPropertyName("end_time")] public string EndTime { get; set; } = ""; + [JsonPropertyName("type")] public int? Type { get; set; } + [JsonPropertyName("priority")] public int Priority { get; set; } +} diff --git a/SVSim.Bootstrap/Program.cs b/SVSim.Bootstrap/Program.cs index 83b88b7..e789072 100644 --- a/SVSim.Bootstrap/Program.cs +++ b/SVSim.Bootstrap/Program.cs @@ -115,6 +115,7 @@ public static class Program await mypage.ImportSealedAsync(context, opts.SeedDir); await mypage.ImportMasterPointRankingPeriodAsync(context, opts.SeedDir); await mypage.ImportSpecialDeckFormatsAsync(context, opts.SeedDir); + await mypage.ImportHomeDialogsAsync(context, opts.SeedDir); await new DefaultDeckImporter().ImportAsync(context, opts.SeedDir); await new PackImporter().ImportAsync(context, opts.SeedDir); diff --git a/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs b/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs index a163b4a..728362e 100644 --- a/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs +++ b/SVSim.UnitTests/Importers/MyPageGlobalsImporterTests.cs @@ -157,6 +157,53 @@ public class MyPageGlobalsImporterTests "SealedSeason singleton must remain a single row on re-run"); } + [Test] + public async Task Imports_home_dialogs_from_seed_file() + { + using var factory = new SVSimTestFactory(); + using var scope = factory.Services.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + var importer = new MyPageGlobalsImporter(); + await importer.ImportHomeDialogsAsync(db, SeedDir); + + var rows = await db.HomeDialogEntries.OrderBy(e => e.Id).ToListAsync(); + Assert.That(rows.Count, Is.GreaterThan(0), "seed must contain at least one home dialog"); + + var first = rows[0]; + Assert.That(first.TitleTextId, Is.Not.Empty); + Assert.That(first.Image, Is.Not.Empty); + Assert.That(first.ButtonListJson, Does.StartWith("["), + "button_list must round-trip as a JSON array string"); + Assert.That(first.EndTime, Is.GreaterThan(first.BeginTime)); + } + + [Test] + public async Task Home_dialogs_are_clear_and_rewrite() + { + using var factory = new SVSimTestFactory(); + using var scope = factory.Services.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + + db.HomeDialogEntries.Add(new HomeDialogEntry + { + Id = 999, + TitleTextId = "legacy", + Image = "legacy_image", + ButtonListJson = "[]", + BeginTime = DateTime.UtcNow.AddYears(-1), + EndTime = DateTime.UtcNow.AddYears(-1).AddDays(1), + }); + await db.SaveChangesAsync(); + + var importer = new MyPageGlobalsImporter(); + await importer.ImportHomeDialogsAsync(db, SeedDir); + + var stale = await db.HomeDialogEntries.FindAsync(999); + Assert.That(stale, Is.Null, + "ImportHomeDialogsAsync must clear-and-rewrite — pre-existing legacy rows must be removed"); + } + [Test] public async Task Master_point_ranking_period_leaves_existing_rows_untouched() { diff --git a/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs b/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs index ce65536..43b33fc 100644 --- a/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs +++ b/SVSim.UnitTests/Infrastructure/SVSimTestFactory.cs @@ -276,6 +276,7 @@ internal sealed class SVSimTestFactory : WebApplicationFactory await mypage.ImportSealedAsync(ctx, seedDir); await mypage.ImportMasterPointRankingPeriodAsync(ctx, seedDir); await mypage.ImportSpecialDeckFormatsAsync(ctx, seedDir); + await mypage.ImportHomeDialogsAsync(ctx, seedDir); await new DefaultDeckImporter().ImportAsync(ctx, seedDir); await new PackImporter().ImportAsync(ctx, seedDir);