From 025c2a8c5675284f80a49e4c095d1335792abeff Mon Sep 17 00:00:00 2001 From: gamer147 Date: Fri, 12 Jun 2026 23:33:50 -0400 Subject: [PATCH] feat(mission): /mission/receive_reward stub (refresh-only, no decomp) Co-Authored-By: Claude Sonnet 4.6 --- .../Controllers/MissionController.cs | 17 ++++++++++++ .../Mission/MissionReceiveRewardRequest.cs | 17 ++++++++++++ .../MissionControllerReceiveRewardTests.cs | 26 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Mission/MissionReceiveRewardRequest.cs create mode 100644 SVSim.UnitTests/Controllers/MissionControllerReceiveRewardTests.cs diff --git a/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs b/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs index ef5cb212..05c03b3d 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs @@ -6,6 +6,7 @@ using SVSim.Database.Repositories.Mission; using SVSim.EmulatedEntrypoint.Models.Dtos.Common.Mission; using SVSim.EmulatedEntrypoint.Models.Dtos.Mission; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; +using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Mission; using SVSim.EmulatedEntrypoint.Services; namespace SVSim.EmulatedEntrypoint.Controllers; @@ -133,6 +134,22 @@ public class MissionController : SVSimController return Ok(dto); } + [HttpPost("receive_reward")] + public async Task ReceiveReward(MissionReceiveRewardRequest _, CancellationToken ct) + { + if (!TryGetViewerId(out long viewerId)) return Unauthorized(); + + // Spec is INFERRED — no decomp task class. Safe stub: refresh MissionInfoDetail + // so the client sees its current state. Real reward granting deferred until we + // observe a wire call. + var viewer = await LoadViewer(viewerId, ct); + await _state.EnsureCurrentAsync(viewer.Id, ct); + await _db.SaveChangesAsync(ct); + + var dto = await _assembler.BuildAsync(viewer, ct); + return Ok(dto); + } + private Task LoadViewer(long viewerId, CancellationToken ct) => _db.Viewers .Include(v => v.MissionData) diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Mission/MissionReceiveRewardRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Mission/MissionReceiveRewardRequest.cs new file mode 100644 index 00000000..b9c2dfc0 --- /dev/null +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Mission/MissionReceiveRewardRequest.cs @@ -0,0 +1,17 @@ +using MessagePack; +using System.Text.Json.Serialization; + +namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Mission; + +/// +/// INFERRED shape — the spec at docs/api-spec/endpoints/post-login/mission-receive-reward.md +/// flags this as not present in the client decompilation. Almost certainly an id of the +/// mission to claim. +/// +[MessagePackObject] +public class MissionReceiveRewardRequest : BaseRequest +{ + [JsonPropertyName("id")] + [Key("id")] + public long Id { get; set; } +} diff --git a/SVSim.UnitTests/Controllers/MissionControllerReceiveRewardTests.cs b/SVSim.UnitTests/Controllers/MissionControllerReceiveRewardTests.cs new file mode 100644 index 00000000..6df88384 --- /dev/null +++ b/SVSim.UnitTests/Controllers/MissionControllerReceiveRewardTests.cs @@ -0,0 +1,26 @@ +using System.Net; +using System.Text; +using NUnit.Framework; +using SVSim.UnitTests.Infrastructure; + +namespace SVSim.UnitTests.Controllers; + +public class MissionControllerReceiveRewardTests +{ + [Test] + public async Task ReceiveReward_returns_ok() + { + using var factory = new SVSimTestFactory(); + long viewerId = await factory.SeedViewerAsync(tutorialState: 0); + using var client = factory.CreateAuthenticatedClient(viewerId); + + // INFERRED: id of the mission to claim. Defensive stub accepts even when + // the id doesn't match a current mission — there is no decomp Parse() to + // tell us how the server errors. + var requestJson = """{"id":1,"viewer_id":"0","steam_id":0,"steam_session_ticket":""}"""; + var response = await client.PostAsync("/mission/receive_reward", + new StringContent(requestJson, Encoding.UTF8, "application/json")); + + Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + } +}