refactor: drop unused DailyLoginBonuses table + importer
The captured shape ({"1":[], "3":[], "4":[]}) is the empty-period
wire echo; the client parser (LoadDetail.cs:553) only reads normal/total/
campaign. Table, entity, seed, and importer were never wired to a code path.
Replaced by config-section catalog + service in the follow-up commits.
This commit is contained in:
@@ -1,14 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"bonus_data": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"bonus_data": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"bonus_data": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
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 daily-login-bonus campaign rows from <c>seeds/daily-login-bonus.json</c>.
|
|
||||||
/// <c>bonus_data</c> array preserved verbatim — prod observed empty arrays outside active events.
|
|
||||||
/// </summary>
|
|
||||||
public class DailyLoginBonusImporter
|
|
||||||
{
|
|
||||||
public async Task<int> ImportAsync(SVSimDbContext context, string seedDir)
|
|
||||||
{
|
|
||||||
var seed = SeedLoader.LoadList<DailyLoginBonusSeed>(Path.Combine(seedDir, "daily-login-bonus.json"));
|
|
||||||
if (seed.Count == 0) return 0;
|
|
||||||
|
|
||||||
var existing = await context.DailyLoginBonuses.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 DailyLoginBonusEntry { Id = s.Id };
|
|
||||||
entry.BonusData = s.BonusData.ValueKind == JsonValueKind.Undefined
|
|
||||||
? "[]"
|
|
||||||
: JsonSerializer.Serialize(s.BonusData);
|
|
||||||
if (ex is null) { context.DailyLoginBonuses.Add(entry); existing[s.Id] = entry; created++; }
|
|
||||||
else updated++;
|
|
||||||
}
|
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
Console.WriteLine($"[DailyLoginBonusImporter] +{created}/~{updated}");
|
|
||||||
return created + updated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace SVSim.Bootstrap.Models.Seed;
|
|
||||||
|
|
||||||
/// <summary>Mirrors <c>seeds/daily-login-bonus.json</c>. <c>bonus_data</c> preserved verbatim.</summary>
|
|
||||||
public sealed class DailyLoginBonusSeed
|
|
||||||
{
|
|
||||||
[JsonPropertyName("id")] public int Id { get; set; }
|
|
||||||
[JsonPropertyName("bonus_data")] public JsonElement BonusData { get; set; }
|
|
||||||
}
|
|
||||||
@@ -94,7 +94,6 @@ public static class Program
|
|||||||
await new MissionCatalogImporter().ImportAsync(context, opts.SeedDir);
|
await new MissionCatalogImporter().ImportAsync(context, opts.SeedDir);
|
||||||
await new AchievementCatalogImporter().ImportAsync(context, opts.SeedDir);
|
await new AchievementCatalogImporter().ImportAsync(context, opts.SeedDir);
|
||||||
await new BattlePassMonthlyMissionImporter().ImportAsync(context, opts.SeedDir);
|
await new BattlePassMonthlyMissionImporter().ImportAsync(context, opts.SeedDir);
|
||||||
await new DailyLoginBonusImporter().ImportAsync(context, opts.SeedDir);
|
|
||||||
await new PreReleaseInfoImporter().ImportAsync(context, opts.SeedDir);
|
await new PreReleaseInfoImporter().ImportAsync(context, opts.SeedDir);
|
||||||
await new CardListsImporter().ImportAsync(context, opts.SeedDir);
|
await new CardListsImporter().ImportAsync(context, opts.SeedDir);
|
||||||
await new RotationFlagUpdater().UpdateAsync(context);
|
await new RotationFlagUpdater().UpdateAsync(context);
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using SVSim.Database.Common;
|
|
||||||
|
|
||||||
namespace SVSim.Database.Models;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Daily login bonus campaign from /load/index data.daily_login_bonus (dict keyed by bonus_id,
|
|
||||||
/// values are arrays of bonus days). Prod observed keys {1, 3, 4} with empty arrays — recapture
|
|
||||||
/// target during active login bonus events.
|
|
||||||
/// </summary>
|
|
||||||
public class DailyLoginBonusEntry : BaseEntity<int>
|
|
||||||
{
|
|
||||||
public int BonusId { get => Id; set => Id = value; }
|
|
||||||
|
|
||||||
[Column(TypeName = "jsonb")]
|
|
||||||
public string BonusData { get; set; } = "[]";
|
|
||||||
}
|
|
||||||
@@ -59,9 +59,6 @@ public class GlobalsRepository : IGlobalsRepository
|
|||||||
public Task<List<BattlePassLevelEntry>> GetBattlePassLevels() =>
|
public Task<List<BattlePassLevelEntry>> GetBattlePassLevels() =>
|
||||||
_dbContext.BattlePassLevels.AsNoTracking().ToListAsync();
|
_dbContext.BattlePassLevels.AsNoTracking().ToListAsync();
|
||||||
|
|
||||||
public Task<List<DailyLoginBonusEntry>> GetDailyLoginBonus() =>
|
|
||||||
_dbContext.DailyLoginBonuses.AsNoTracking().ToListAsync();
|
|
||||||
|
|
||||||
public Task<List<BannerEntry>> GetBanners() =>
|
public Task<List<BannerEntry>> GetBanners() =>
|
||||||
_dbContext.Banners.AsNoTracking().OrderBy(b => b.Id).ToListAsync();
|
_dbContext.Banners.AsNoTracking().OrderBy(b => b.Id).ToListAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public interface IGlobalsRepository
|
|||||||
Task<List<UnlimitedRestrictionEntry>> GetUnlimitedRestrictions();
|
Task<List<UnlimitedRestrictionEntry>> GetUnlimitedRestrictions();
|
||||||
Task<List<LoadingExclusionCardEntry>> GetLoadingExclusionCards();
|
Task<List<LoadingExclusionCardEntry>> GetLoadingExclusionCards();
|
||||||
Task<List<BattlePassLevelEntry>> GetBattlePassLevels();
|
Task<List<BattlePassLevelEntry>> GetBattlePassLevels();
|
||||||
Task<List<DailyLoginBonusEntry>> GetDailyLoginBonus();
|
|
||||||
Task<List<BannerEntry>> GetBanners();
|
Task<List<BannerEntry>> GetBanners();
|
||||||
Task<IReadOnlyList<HomeDialogEntry>> GetActiveHomeDialogsAsync(DateTime nowUtc);
|
Task<IReadOnlyList<HomeDialogEntry>> GetActiveHomeDialogsAsync(DateTime nowUtc);
|
||||||
Task<SealedConfig?> GetCurrentSealedSeason();
|
Task<SealedConfig?> GetCurrentSealedSeason();
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ public class SVSimDbContext : DbContext
|
|||||||
public DbSet<ViewerMission> ViewerMissions => Set<ViewerMission>();
|
public DbSet<ViewerMission> ViewerMissions => Set<ViewerMission>();
|
||||||
public DbSet<ViewerAchievement> ViewerAchievements => Set<ViewerAchievement>();
|
public DbSet<ViewerAchievement> ViewerAchievements => Set<ViewerAchievement>();
|
||||||
public DbSet<ViewerEventCounter> ViewerEventCounters => Set<ViewerEventCounter>();
|
public DbSet<ViewerEventCounter> ViewerEventCounters => Set<ViewerEventCounter>();
|
||||||
public DbSet<DailyLoginBonusEntry> DailyLoginBonuses => Set<DailyLoginBonusEntry>();
|
|
||||||
public DbSet<BannerEntry> Banners => Set<BannerEntry>();
|
public DbSet<BannerEntry> Banners => Set<BannerEntry>();
|
||||||
public DbSet<HomeDialogEntry> HomeDialogEntries => Set<HomeDialogEntry>();
|
public DbSet<HomeDialogEntry> HomeDialogEntries => Set<HomeDialogEntry>();
|
||||||
public DbSet<SealedConfig> SealedSeasons => Set<SealedConfig>();
|
public DbSet<SealedConfig> SealedSeasons => Set<SealedConfig>();
|
||||||
|
|||||||
@@ -229,10 +229,8 @@ public class LoadController : SVSimController
|
|||||||
MaintenanceCards = (await _globalsRepository.GetMaintenanceCards())
|
MaintenanceCards = (await _globalsRepository.GetMaintenanceCards())
|
||||||
.Select(e => e.Id).ToList(),
|
.Select(e => e.Id).ToList(),
|
||||||
RedEtherOverrides = new List<RedEtherOverride>(),
|
RedEtherOverrides = new List<RedEtherOverride>(),
|
||||||
// Optional per spec (load-index.md:247). Skeleton-seeded rows in DailyLoginBonuses table
|
// Optional per spec (load-index.md:247). Populated by ILoginBonusService (Task 6)
|
||||||
// capture prod's empty-period shape ({"1":[], "3":[], "4":[]}); the spec-shaped DTO
|
// when the viewer has an active bonus period.
|
||||||
// ({normal?, total?, campaign?[]}) carries nothing meaningful until an active campaign
|
|
||||||
// is captured.
|
|
||||||
DailyLoginBonus = null,
|
DailyLoginBonus = null,
|
||||||
UserRankedMatches = new List<UserRankedMatches>(),
|
UserRankedMatches = new List<UserRankedMatches>(),
|
||||||
UserRankInfo = RankFormats.Select(f => new UserRankInfo
|
UserRankInfo = RankFormats.Select(f => new UserRankInfo
|
||||||
|
|||||||
@@ -150,9 +150,7 @@ public class IndexResponse
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spec: optional. Shape is {normal?, total?, campaign?[]} per common/types.ts.md DailyLoginBonus.
|
/// Spec: optional. Shape is {normal?, total?, campaign?[]} per common/types.ts.md DailyLoginBonus.
|
||||||
/// Until we have an active login-bonus campaign to surface in spec shape, omit. The skeleton
|
/// Populated by ILoginBonusService when the viewer has an active bonus period; null otherwise.
|
||||||
/// rows in DailyLoginBonuses table (prod sent {"1":[], "3":[], "4":[]}) preserve the capture
|
|
||||||
/// for archive but don't make it into the wire response.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("daily_login_bonus")]
|
[JsonPropertyName("daily_login_bonus")]
|
||||||
[Key("daily_login_bonus")]
|
[Key("daily_login_bonus")]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace SVSim.UnitTests.Importers;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Happy-path coverage for the load-index importer classes introduced in Stage 9B
|
/// Happy-path coverage for the load-index importer classes introduced in Stage 9B
|
||||||
/// (RotationConfig, MyRotation, AvatarAbility, ArenaSeason, DailyLoginBonus,
|
/// (RotationConfig, MyRotation, AvatarAbility, ArenaSeason,
|
||||||
/// PreReleaseInfo). Each test instantiates the importer in isolation and verifies it inserts
|
/// PreReleaseInfo). Each test instantiates the importer in isolation and verifies it inserts
|
||||||
/// rows from the corresponding seed file under <c>Data/seeds/</c>.
|
/// rows from the corresponding seed file under <c>Data/seeds/</c>.
|
||||||
/// Idempotency, edge cases, and per-importer detail tests live in dedicated *ImporterTests files (e.g. BattlePassImporterTests).
|
/// Idempotency, edge cases, and per-importer detail tests live in dedicated *ImporterTests files (e.g. BattlePassImporterTests).
|
||||||
@@ -73,19 +73,6 @@ public class LoadIndexImporterTests
|
|||||||
Assert.That(row!.FormatInfo, Is.Not.EqualTo("{}"), "format_info blob must be populated from seed");
|
Assert.That(row!.FormatInfo, Is.Not.EqualTo("{}"), "format_info blob must be populated from seed");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task DailyLoginBonusImporter_writes_bonus_rows()
|
|
||||||
{
|
|
||||||
using var factory = new SVSimTestFactory();
|
|
||||||
using var scope = factory.Services.CreateScope();
|
|
||||||
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
|
||||||
|
|
||||||
await new DailyLoginBonusImporter().ImportAsync(db, SeedDir);
|
|
||||||
|
|
||||||
Assert.That(await db.DailyLoginBonuses.CountAsync(), Is.GreaterThan(0),
|
|
||||||
"daily-login-bonus.json must produce rows");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task PreReleaseInfoImporter_writes_singleton()
|
public async Task PreReleaseInfoImporter_writes_singleton()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -266,7 +266,6 @@ internal class SVSimTestFactory : WebApplicationFactory<Program>
|
|||||||
await new BattlePassImporter().ImportAsync(ctx, seedDir);
|
await new BattlePassImporter().ImportAsync(ctx, seedDir);
|
||||||
await new BattlePassSeasonImporter().ImportAsync(ctx, seedDir);
|
await new BattlePassSeasonImporter().ImportAsync(ctx, seedDir);
|
||||||
await new BattlePassRewardImporter().ImportAsync(ctx, seedDir);
|
await new BattlePassRewardImporter().ImportAsync(ctx, seedDir);
|
||||||
await new DailyLoginBonusImporter().ImportAsync(ctx, seedDir);
|
|
||||||
await new PreReleaseInfoImporter().ImportAsync(ctx, seedDir);
|
await new PreReleaseInfoImporter().ImportAsync(ctx, seedDir);
|
||||||
await new CardListsImporter().ImportAsync(ctx, seedDir);
|
await new CardListsImporter().ImportAsync(ctx, seedDir);
|
||||||
await new RotationFlagUpdater().UpdateAsync(ctx);
|
await new RotationFlagUpdater().UpdateAsync(ctx);
|
||||||
|
|||||||
@@ -80,16 +80,6 @@ public class GlobalsRepositoryTests
|
|||||||
Assert.That(levels.Count, Is.EqualTo(100));
|
Assert.That(levels.Count, Is.EqualTo(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task GetDailyLoginBonus_returns_three_skeleton_entries()
|
|
||||||
{
|
|
||||||
var (factory, repo) = await SetupAsync();
|
|
||||||
using var _ = factory;
|
|
||||||
var bonuses = await repo.GetDailyLoginBonus();
|
|
||||||
Assert.That(bonuses.Count, Is.EqualTo(3),
|
|
||||||
"Prod capture has keys {1, 3, 4} with empty arrays — skeleton presence still seeded.");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task GetPreReleaseInfo_returns_singleton()
|
public async Task GetPreReleaseInfo_returns_singleton()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user