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:
gamer147
2026-06-13 15:32:33 -04:00
parent ba7040580f
commit f707fb2ffb
13 changed files with 4 additions and 117 deletions

View File

@@ -1,14 +0,0 @@
[
{
"id": 1,
"bonus_data": []
},
{
"id": 3,
"bonus_data": []
},
{
"id": 4,
"bonus_data": []
}
]

View File

@@ -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;
}
}

View File

@@ -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; }
}

View File

@@ -94,7 +94,6 @@ public static class Program
await new MissionCatalogImporter().ImportAsync(context, opts.SeedDir);
await new AchievementCatalogImporter().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 CardListsImporter().ImportAsync(context, opts.SeedDir);
await new RotationFlagUpdater().UpdateAsync(context);

View File

@@ -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; } = "[]";
}

View File

@@ -59,9 +59,6 @@ public class GlobalsRepository : IGlobalsRepository
public Task<List<BattlePassLevelEntry>> GetBattlePassLevels() =>
_dbContext.BattlePassLevels.AsNoTracking().ToListAsync();
public Task<List<DailyLoginBonusEntry>> GetDailyLoginBonus() =>
_dbContext.DailyLoginBonuses.AsNoTracking().ToListAsync();
public Task<List<BannerEntry>> GetBanners() =>
_dbContext.Banners.AsNoTracking().OrderBy(b => b.Id).ToListAsync();

View File

@@ -19,7 +19,6 @@ public interface IGlobalsRepository
Task<List<UnlimitedRestrictionEntry>> GetUnlimitedRestrictions();
Task<List<LoadingExclusionCardEntry>> GetLoadingExclusionCards();
Task<List<BattlePassLevelEntry>> GetBattlePassLevels();
Task<List<DailyLoginBonusEntry>> GetDailyLoginBonus();
Task<List<BannerEntry>> GetBanners();
Task<IReadOnlyList<HomeDialogEntry>> GetActiveHomeDialogsAsync(DateTime nowUtc);
Task<SealedConfig?> GetCurrentSealedSeason();

View File

@@ -60,7 +60,6 @@ public class SVSimDbContext : DbContext
public DbSet<ViewerMission> ViewerMissions => Set<ViewerMission>();
public DbSet<ViewerAchievement> ViewerAchievements => Set<ViewerAchievement>();
public DbSet<ViewerEventCounter> ViewerEventCounters => Set<ViewerEventCounter>();
public DbSet<DailyLoginBonusEntry> DailyLoginBonuses => Set<DailyLoginBonusEntry>();
public DbSet<BannerEntry> Banners => Set<BannerEntry>();
public DbSet<HomeDialogEntry> HomeDialogEntries => Set<HomeDialogEntry>();
public DbSet<SealedConfig> SealedSeasons => Set<SealedConfig>();

View File

@@ -229,10 +229,8 @@ public class LoadController : SVSimController
MaintenanceCards = (await _globalsRepository.GetMaintenanceCards())
.Select(e => e.Id).ToList(),
RedEtherOverrides = new List<RedEtherOverride>(),
// Optional per spec (load-index.md:247). Skeleton-seeded rows in DailyLoginBonuses table
// capture prod's empty-period shape ({"1":[], "3":[], "4":[]}); the spec-shaped DTO
// ({normal?, total?, campaign?[]}) carries nothing meaningful until an active campaign
// is captured.
// Optional per spec (load-index.md:247). Populated by ILoginBonusService (Task 6)
// when the viewer has an active bonus period.
DailyLoginBonus = null,
UserRankedMatches = new List<UserRankedMatches>(),
UserRankInfo = RankFormats.Select(f => new UserRankInfo

View File

@@ -150,9 +150,7 @@ public class IndexResponse
/// <summary>
/// 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
/// rows in DailyLoginBonuses table (prod sent {"1":[], "3":[], "4":[]}) preserve the capture
/// for archive but don't make it into the wire response.
/// Populated by ILoginBonusService when the viewer has an active bonus period; null otherwise.
/// </summary>
[JsonPropertyName("daily_login_bonus")]
[Key("daily_login_bonus")]

View File

@@ -8,7 +8,7 @@ namespace SVSim.UnitTests.Importers;
/// <summary>
/// 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
/// 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).
@@ -73,19 +73,6 @@ public class LoadIndexImporterTests
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]
public async Task PreReleaseInfoImporter_writes_singleton()
{

View File

@@ -266,7 +266,6 @@ internal class SVSimTestFactory : WebApplicationFactory<Program>
await new BattlePassImporter().ImportAsync(ctx, seedDir);
await new BattlePassSeasonImporter().ImportAsync(ctx, seedDir);
await new BattlePassRewardImporter().ImportAsync(ctx, seedDir);
await new DailyLoginBonusImporter().ImportAsync(ctx, seedDir);
await new PreReleaseInfoImporter().ImportAsync(ctx, seedDir);
await new CardListsImporter().ImportAsync(ctx, seedDir);
await new RotationFlagUpdater().UpdateAsync(ctx);

View File

@@ -80,16 +80,6 @@ public class GlobalsRepositoryTests
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]
public async Task GetPreReleaseInfo_returns_singleton()
{