diff --git a/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs b/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs index 0d729f90..ef5cb212 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/MissionController.cs @@ -116,6 +116,23 @@ public class MissionController : SVSimController return Ok(dto); } + [HttpPost("buy_additional_right")] + public async Task BuyAdditionalRight(BaseRequest _, CancellationToken ct) + { + if (!TryGetViewerId(out long viewerId)) return Unauthorized(); + + // The client-side task class is absent from the decompilation; the URL is + // registered but no Parse() is documented. Spec marks the shape as INFERRED. + // Safe stub: refresh MissionInfoDetail and let the client re-render — same + // shape as /mission/info. No currency debit until we see a real 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.UnitTests/Controllers/MissionControllerBuyAdditionalRightTests.cs b/SVSim.UnitTests/Controllers/MissionControllerBuyAdditionalRightTests.cs new file mode 100644 index 00000000..7d2d2b90 --- /dev/null +++ b/SVSim.UnitTests/Controllers/MissionControllerBuyAdditionalRightTests.cs @@ -0,0 +1,25 @@ +using System.Net; +using System.Text; +using NUnit.Framework; +using SVSim.UnitTests.Infrastructure; + +namespace SVSim.UnitTests.Controllers; + +public class MissionControllerBuyAdditionalRightTests +{ + [Test] + public async Task BuyAdditionalRight_returns_ok() + { + using var factory = new SVSimTestFactory(); + long viewerId = await factory.SeedViewerAsync(tutorialState: 0); + using var client = factory.CreateAuthenticatedClient(viewerId); + + // Body shape is INFERRED — we send the bare base envelope and expect the server + // to refresh MissionInfoDetail. + var requestJson = """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}"""; + var response = await client.PostAsync("/mission/buy_additional_right", + new StringContent(requestJson, Encoding.UTF8, "application/json")); + + Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + } +}