refactor(bootstrap): migrate mypage-index globals to seed files
This commit is contained in:
@@ -27,7 +27,6 @@ public class GlobalsImporter
|
||||
Console.WriteLine($"[GlobalsImporter] Loading captures from {capturesDir}...");
|
||||
|
||||
JsonElement? loadIndex = LoadCapture(capturesDir, "load-index");
|
||||
JsonElement? mypageIndex = LoadCapture(capturesDir, "mypage-index");
|
||||
JsonElement? deckInfo = LoadCapture(capturesDir, "deck-info");
|
||||
JsonElement? packInfo = LoadCapture(capturesDir, "pack-info");
|
||||
|
||||
@@ -51,15 +50,6 @@ public class GlobalsImporter
|
||||
total += await UpdateRotationCardSetFlags(context, loadIndex.Value);
|
||||
}
|
||||
|
||||
if (mypageIndex.HasValue)
|
||||
{
|
||||
total += await ImportBanners(context, mypageIndex.Value);
|
||||
total += await ImportColosseum(context, mypageIndex.Value);
|
||||
total += await ImportSealed(context, mypageIndex.Value);
|
||||
total += await ImportMasterPointRankingPeriod(context, mypageIndex.Value);
|
||||
total += await ImportRoomTypeInSession(context, mypageIndex.Value);
|
||||
}
|
||||
|
||||
if (deckInfo.HasValue)
|
||||
{
|
||||
total += await ImportDefaultDecks(context, deckInfo.Value);
|
||||
@@ -521,135 +511,6 @@ public class GlobalsImporter
|
||||
return updated;
|
||||
}
|
||||
|
||||
// ---------- Mypage: Banners ----------
|
||||
|
||||
private async Task<int> ImportBanners(SVSimDbContext context, JsonElement mypage)
|
||||
{
|
||||
if (!mypage.TryGetProperty("banner", out var arr) || arr.ValueKind != JsonValueKind.Array) return 0;
|
||||
|
||||
// Banners have no wire ID; we treat the capture as authoritative — clear and rewrite.
|
||||
var existing = await context.Banners.ToListAsync();
|
||||
context.Banners.RemoveRange(existing);
|
||||
|
||||
int created = 0;
|
||||
int idx = 1;
|
||||
foreach (var el in arr.EnumerateArray())
|
||||
{
|
||||
context.Banners.Add(new BannerEntry
|
||||
{
|
||||
Id = idx++,
|
||||
ImageName = GetString(el, "image_name"),
|
||||
Click = GetString(el, "click"),
|
||||
Status = GetString(el, "status"),
|
||||
ChangeTime = GetInt(el, "change_time"),
|
||||
RemainingTime = GetInt(el, "remaining_time"),
|
||||
ImagePaths = el.TryGetProperty("image_paths", out var ip) ? Serialize(ip) : "[]"
|
||||
});
|
||||
created++;
|
||||
}
|
||||
Console.WriteLine($"[GlobalsImporter] Banners: {(existing.Count > 0 ? $"-{existing.Count}/" : "")}+{created}");
|
||||
return created;
|
||||
}
|
||||
|
||||
// ---------- Mypage: Colosseum (singleton) ----------
|
||||
|
||||
private async Task<int> ImportColosseum(SVSimDbContext context, JsonElement mypage)
|
||||
{
|
||||
if (!mypage.TryGetProperty("colosseum_info", out var info) || info.ValueKind != JsonValueKind.Object) return 0;
|
||||
|
||||
var existing = await context.Colosseums.FirstOrDefaultAsync(e => e.Id == 1);
|
||||
var entry = existing ?? new ColosseumConfig { Id = 1 };
|
||||
entry.ColosseumId = GetString(info, "colosseum_id");
|
||||
entry.ColosseumName = GetString(info, "colosseum_name");
|
||||
entry.CardPoolName = GetString(info, "card_pool_name");
|
||||
entry.DeckFormat = GetString(info, "deck_format");
|
||||
entry.StartTime = ParseWireDateTime(GetString(info, "start_time"));
|
||||
entry.EndTime = ParseWireDateTime(GetString(info, "end_time"));
|
||||
entry.NowRound = GetString(info, "now_round");
|
||||
entry.IsDisplayTips = GetString(info, "is_display_tips");
|
||||
entry.TipsId = GetString(info, "tips_id");
|
||||
entry.IsColosseumPeriod = GetBool(info, "is_colosseum_period");
|
||||
entry.IsRoundPeriod = GetBool(info, "is_round_period");
|
||||
entry.IsNormalTwoPick = GetString(info, "is_normal_two_pick");
|
||||
entry.IsSpecialMode = GetString(info, "is_special_mode");
|
||||
entry.IsAllCardEnabled = GetInt(info, "is_all_card_enabled");
|
||||
entry.SalesPeriodInfo = info.TryGetProperty("sales_period_info", out var sp) ? Serialize(sp) : "{}";
|
||||
if (existing is null) context.Colosseums.Add(entry);
|
||||
Console.WriteLine($"[GlobalsImporter] Colosseum: {(existing is null ? "+1" : "~1")}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------- Mypage: Sealed (singleton) ----------
|
||||
|
||||
private async Task<int> ImportSealed(SVSimDbContext context, JsonElement mypage)
|
||||
{
|
||||
if (!mypage.TryGetProperty("sealed_info", out var info) || info.ValueKind != JsonValueKind.Object) return 0;
|
||||
|
||||
var existing = await context.SealedSeasons.FirstOrDefaultAsync(e => e.Id == 1);
|
||||
var entry = existing ?? new SealedConfig { Id = 1 };
|
||||
entry.Enable = GetInt(info, "enable");
|
||||
entry.CrystalCost = GetInt(info, "crystal_cost");
|
||||
entry.RupyCost = GetInt(info, "rupy_cost");
|
||||
entry.TicketCost = GetInt(info, "ticket_cost");
|
||||
entry.DeckUsingNumMin = GetInt(info, "deck_using_num_min");
|
||||
entry.ScheduleId = GetInt(info, "schedule_id");
|
||||
entry.IsJoin = GetBool(info, "is_join");
|
||||
entry.IsDeckCodeMaintenance = GetBool(info, "is_deck_code_maintenance");
|
||||
entry.PackInfo = info.TryGetProperty("pack_info", out var pi) ? Serialize(pi) : "[]";
|
||||
entry.SalesPeriodInfo = info.TryGetProperty("sales_period_info", out var sp) ? Serialize(sp) : "{}";
|
||||
if (existing is null) context.SealedSeasons.Add(entry);
|
||||
Console.WriteLine($"[GlobalsImporter] Sealed: {(existing is null ? "+1" : "~1")}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------- Mypage: Master Point Ranking Period ----------
|
||||
|
||||
private async Task<int> ImportMasterPointRankingPeriod(SVSimDbContext context, JsonElement mypage)
|
||||
{
|
||||
if (!mypage.TryGetProperty("master_point_ranking_period", out var info) || info.ValueKind != JsonValueKind.Object) return 0;
|
||||
|
||||
int id = GetInt(info, "id");
|
||||
if (id == 0) return 0;
|
||||
|
||||
var existing = await context.MasterPointRankingPeriods.FirstOrDefaultAsync(e => e.Id == id);
|
||||
var entry = existing ?? new MasterPointRankingPeriodEntry { Id = id };
|
||||
entry.PeriodNum = GetInt(info, "period_num");
|
||||
entry.NecessaryScore = GetLong(info, "necessary_score");
|
||||
entry.BeginTime = ParseWireDateTime(GetString(info, "begin_time"));
|
||||
entry.EndTime = ParseWireDateTime(GetString(info, "end_time"));
|
||||
if (existing is null) context.MasterPointRankingPeriods.Add(entry);
|
||||
Console.WriteLine($"[GlobalsImporter] MasterPointRankingPeriod (id={id}): {(existing is null ? "+1" : "~1")}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------- Mypage: Room Type In Session (special deck formats) ----------
|
||||
|
||||
private async Task<int> ImportRoomTypeInSession(SVSimDbContext context, JsonElement mypage)
|
||||
{
|
||||
if (!mypage.TryGetProperty("room_type_in_session", out var rt) || rt.ValueKind != JsonValueKind.Object) return 0;
|
||||
if (!rt.TryGetProperty("special_deck_format_list", out var arr) || arr.ValueKind != JsonValueKind.Array) return 0;
|
||||
|
||||
// Same shape semantics as Banners — the wire has no stable id, treat the capture as
|
||||
// authoritative and clear-and-rewrite with a synthetic ordinal.
|
||||
var existing = await context.SpecialDeckFormats.ToListAsync();
|
||||
context.SpecialDeckFormats.RemoveRange(existing);
|
||||
|
||||
int created = 0;
|
||||
int idx = 1;
|
||||
foreach (var el in arr.EnumerateArray())
|
||||
{
|
||||
context.SpecialDeckFormats.Add(new SpecialDeckFormatEntry
|
||||
{
|
||||
Id = idx++,
|
||||
DeckFormat = GetString(el, "deck_format"),
|
||||
EndTime = ParseWireDateTime(GetString(el, "end_time"))
|
||||
});
|
||||
created++;
|
||||
}
|
||||
Console.WriteLine($"[GlobalsImporter] SpecialDeckFormats: {(existing.Count > 0 ? $"-{existing.Count}/" : "")}+{created}");
|
||||
return created;
|
||||
}
|
||||
|
||||
// ---------- Deck/info: Default Decks ----------
|
||||
|
||||
private async Task<int> ImportDefaultDecks(SVSimDbContext context, JsonElement deckInfo)
|
||||
|
||||
185
SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs
Normal file
185
SVSim.Bootstrap/Importers/MyPageGlobalsImporter.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Bootstrap.Models.Seed;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Models;
|
||||
|
||||
namespace SVSim.Bootstrap.Importers;
|
||||
|
||||
/// <summary>
|
||||
/// Idempotent upsert of /mypage/index-derived globals from per-table seed files.
|
||||
/// Banners and SpecialDeckFormats use CLEAR-AND-REWRITE semantics (no stable wire ID, capture is authoritative).
|
||||
/// Colosseum and SealedSeason are singletons (Id=1). MasterPointRankingPeriod upserts by wire id.
|
||||
/// </summary>
|
||||
public class MyPageGlobalsImporter
|
||||
{
|
||||
public async Task<int> ImportBannersAsync(SVSimDbContext context, string seedDir)
|
||||
{
|
||||
var seed = SeedLoader.LoadList<BannerSeed>(Path.Combine(seedDir, "banners.json"));
|
||||
if (seed.Count == 0)
|
||||
{
|
||||
Console.WriteLine("[MyPageGlobalsImporter] No banner seed rows; skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Clear-and-rewrite: banners have no stable wire ID, the capture is authoritative.
|
||||
var existing = await context.Banners.ToListAsync();
|
||||
context.Banners.RemoveRange(existing);
|
||||
|
||||
foreach (var s in seed)
|
||||
{
|
||||
context.Banners.Add(new BannerEntry
|
||||
{
|
||||
Id = s.Id,
|
||||
ImageName = s.ImageName,
|
||||
Click = s.Click,
|
||||
Status = s.Status,
|
||||
ChangeTime = s.ChangeTime,
|
||||
RemainingTime = s.RemainingTime,
|
||||
ImagePaths = s.ImagePaths.ValueKind == JsonValueKind.Undefined
|
||||
? "[]"
|
||||
: JsonSerializer.Serialize(s.ImagePaths),
|
||||
});
|
||||
}
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine($"[MyPageGlobalsImporter] Banners: -{existing.Count}/+{seed.Count}");
|
||||
return seed.Count;
|
||||
}
|
||||
|
||||
public async Task<int> ImportColosseumAsync(SVSimDbContext context, string seedDir)
|
||||
{
|
||||
var s = SeedLoader.LoadObject<ColosseumSeed>(Path.Combine(seedDir, "colosseum.json"));
|
||||
if (s is null)
|
||||
{
|
||||
Console.WriteLine("[MyPageGlobalsImporter] No colosseum seed; skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var existing = await context.Colosseums.FirstOrDefaultAsync(e => e.Id == 1);
|
||||
var entry = existing ?? new ColosseumConfig { Id = 1 };
|
||||
|
||||
entry.ColosseumId = s.ColosseumId;
|
||||
entry.ColosseumName = s.ColosseumName;
|
||||
entry.CardPoolName = s.CardPoolName;
|
||||
entry.DeckFormat = s.DeckFormat;
|
||||
entry.StartTime = ImporterBase.ParseWireDateTime(s.StartTime);
|
||||
entry.EndTime = ImporterBase.ParseWireDateTime(s.EndTime);
|
||||
entry.NowRound = s.NowRound;
|
||||
entry.IsDisplayTips = s.IsDisplayTips;
|
||||
entry.TipsId = s.TipsId;
|
||||
entry.IsColosseumPeriod = s.IsColosseumPeriod;
|
||||
entry.IsRoundPeriod = s.IsRoundPeriod;
|
||||
entry.IsNormalTwoPick = s.IsNormalTwoPick;
|
||||
entry.IsSpecialMode = s.IsSpecialMode;
|
||||
entry.IsAllCardEnabled = s.IsAllCardEnabled;
|
||||
entry.SalesPeriodInfo = s.SalesPeriodInfo.ValueKind == JsonValueKind.Undefined
|
||||
? "{}"
|
||||
: JsonSerializer.Serialize(s.SalesPeriodInfo);
|
||||
|
||||
if (existing is null) context.Colosseums.Add(entry);
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine($"[MyPageGlobalsImporter] Colosseum: {(existing is null ? "+1" : "~1")}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
public async Task<int> ImportSealedAsync(SVSimDbContext context, string seedDir)
|
||||
{
|
||||
var s = SeedLoader.LoadObject<SealedSeasonSeed>(Path.Combine(seedDir, "sealed-season.json"));
|
||||
if (s is null)
|
||||
{
|
||||
Console.WriteLine("[MyPageGlobalsImporter] No sealed-season seed; skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var existing = await context.SealedSeasons.FirstOrDefaultAsync(e => e.Id == 1);
|
||||
var entry = existing ?? new SealedConfig { Id = 1 };
|
||||
|
||||
entry.Enable = s.Enable;
|
||||
entry.CrystalCost = s.CrystalCost;
|
||||
entry.RupyCost = s.RupyCost;
|
||||
entry.TicketCost = s.TicketCost;
|
||||
entry.DeckUsingNumMin = s.DeckUsingNumMin;
|
||||
entry.ScheduleId = s.ScheduleId;
|
||||
entry.IsJoin = s.IsJoin;
|
||||
entry.IsDeckCodeMaintenance = s.IsDeckCodeMaintenance;
|
||||
entry.PackInfo = s.PackInfo.ValueKind == JsonValueKind.Undefined
|
||||
? "[]"
|
||||
: JsonSerializer.Serialize(s.PackInfo);
|
||||
entry.SalesPeriodInfo = s.SalesPeriodInfo.ValueKind == JsonValueKind.Undefined
|
||||
? "{}"
|
||||
: JsonSerializer.Serialize(s.SalesPeriodInfo);
|
||||
|
||||
if (existing is null) context.SealedSeasons.Add(entry);
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine($"[MyPageGlobalsImporter] SealedSeason: {(existing is null ? "+1" : "~1")}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
public async Task<int> ImportMasterPointRankingPeriodAsync(SVSimDbContext context, string seedDir)
|
||||
{
|
||||
var seed = SeedLoader.LoadList<MasterPointRankingPeriodSeed>(
|
||||
Path.Combine(seedDir, "master-point-ranking-periods.json"));
|
||||
if (seed.Count == 0)
|
||||
{
|
||||
Console.WriteLine("[MyPageGlobalsImporter] No master-point-ranking-period seed rows; skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
var existing = await context.MasterPointRankingPeriods.ToDictionaryAsync(e => e.Id);
|
||||
int created = 0, updated = 0;
|
||||
|
||||
foreach (var s in seed)
|
||||
{
|
||||
if (s.Id == 0) continue;
|
||||
|
||||
var entry = existing.TryGetValue(s.Id, out var ex)
|
||||
? ex : new MasterPointRankingPeriodEntry { Id = s.Id };
|
||||
|
||||
entry.PeriodNum = s.PeriodNum;
|
||||
entry.NecessaryScore = s.NecessaryScore;
|
||||
entry.BeginTime = ImporterBase.ParseWireDateTime(s.BeginTime);
|
||||
entry.EndTime = ImporterBase.ParseWireDateTime(s.EndTime);
|
||||
|
||||
if (ex is null)
|
||||
{
|
||||
context.MasterPointRankingPeriods.Add(entry);
|
||||
existing[s.Id] = entry;
|
||||
created++;
|
||||
}
|
||||
else updated++;
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine($"[MyPageGlobalsImporter] MasterPointRankingPeriod: +{created}/~{updated}");
|
||||
return created + updated;
|
||||
}
|
||||
|
||||
public async Task<int> ImportSpecialDeckFormatsAsync(SVSimDbContext context, string seedDir)
|
||||
{
|
||||
var seed = SeedLoader.LoadList<SpecialDeckFormatSeed>(
|
||||
Path.Combine(seedDir, "special-deck-formats.json"));
|
||||
if (seed.Count == 0)
|
||||
{
|
||||
Console.WriteLine("[MyPageGlobalsImporter] No special-deck-format seed rows; skipping.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Clear-and-rewrite: same semantics as banners — no stable wire ID, capture is authoritative.
|
||||
var existing = await context.SpecialDeckFormats.ToListAsync();
|
||||
context.SpecialDeckFormats.RemoveRange(existing);
|
||||
|
||||
foreach (var s in seed)
|
||||
{
|
||||
context.SpecialDeckFormats.Add(new SpecialDeckFormatEntry
|
||||
{
|
||||
Id = s.Id,
|
||||
DeckFormat = s.DeckFormat,
|
||||
EndTime = ImporterBase.ParseWireDateTime(s.EndTime),
|
||||
});
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine($"[MyPageGlobalsImporter] SpecialDeckFormats: -{existing.Count}/+{seed.Count}");
|
||||
return seed.Count;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user