From a3106978308a3163b0b6697339a681dd8c60a9e3 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Sun, 31 May 2026 16:40:16 -0400 Subject: [PATCH] refactor(puzzle): route finish rewards through InventoryService Replace RewardGrantService + HttpContext.RequestServices viewer load with IInventoryService tx. Single BeginAsync/GrantAsync/CommitAsync wraps all mission rewards on the win path. Co-Authored-By: Claude Opus 4.7 --- .../Controllers/PuzzleController.cs | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/SVSim.EmulatedEntrypoint/Controllers/PuzzleController.cs b/SVSim.EmulatedEntrypoint/Controllers/PuzzleController.cs index aad054c..bde4c48 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/PuzzleController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/PuzzleController.cs @@ -1,12 +1,11 @@ using System.Text.Json; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using SVSim.Database; +using SVSim.Database.Enums; using SVSim.Database.Repositories.Globals; using SVSim.Database.Repositories.Viewer; -using SVSim.Database.Services; +using SVSim.Database.Services.Inventory; using SVSim.EmulatedEntrypoint.Models.Dtos.Common.BasicPuzzle; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.BasicPuzzle; @@ -26,20 +25,20 @@ public class PuzzleController : SVSimController private readonly IPuzzleCatalogRepository _catalog; private readonly IPuzzleClearRepository _clears; private readonly PuzzleMissionEvaluator _evaluator; - private readonly RewardGrantService _rewards; + private readonly IInventoryService _inv; private readonly ILogger _logger; public PuzzleController( IPuzzleCatalogRepository catalog, IPuzzleClearRepository clears, PuzzleMissionEvaluator evaluator, - RewardGrantService rewards, + IInventoryService inv, ILogger logger) { _catalog = catalog; _clears = clears; _evaluator = evaluator; - _rewards = rewards; + _inv = inv; _logger = logger; } @@ -175,28 +174,15 @@ public class PuzzleController : SVSimController if (fresh.Count > 0) { - // Load viewer with all the collections RewardGrantService might mutate. Split-query - // to avoid the cartesian-explode pitfall (CLAUDE.md "EF split query"). - var ctx = HttpContext.RequestServices.GetRequiredService(); - var viewer = await ctx.Viewers - .Include(v => v.Cards).ThenInclude(c => c.Card) - .Include(v => v.Sleeves) - .Include(v => v.Emblems) - .Include(v => v.LeaderSkins) - .Include(v => v.Degrees) - .Include(v => v.MyPageBackgrounds) - .Include(v => v.Items).ThenInclude(i => i.Item) - .AsSplitQuery() - .FirstAsync(v => v.Id == viewerId); + await using var tx = await _inv.BeginAsync(viewerId); foreach (var status in fresh) { - IReadOnlyList granted; + IReadOnlyList granted; try { - granted = await _rewards.ApplyAsync( - viewer, - (SVSim.Database.Enums.UserGoodsType)status.Mission.RewardType, + granted = await tx.GrantAsync( + (UserGoodsType)status.Mission.RewardType, status.Mission.RewardDetailId, status.Mission.RewardNumber); } @@ -229,7 +215,7 @@ public class PuzzleController : SVSimController } } - await ctx.SaveChangesAsync(); + await tx.CommitAsync(); } response.WinCount = "1";