diff --git a/SVSim.EmulatedEntrypoint/Controllers/FriendController.cs b/SVSim.EmulatedEntrypoint/Controllers/FriendController.cs index 527718c..59560f2 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/FriendController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/FriendController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using SVSim.Database.Services.Friend; using SVSim.EmulatedEntrypoint.Models.Dtos.Friend; +using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; namespace SVSim.EmulatedEntrypoint.Controllers; @@ -17,7 +18,7 @@ public sealed class FriendController : SVSimController public FriendController(IFriendService friend) => _friend = friend; [HttpPost("info")] - public async Task> Info(CancellationToken ct) + public async Task> Info([FromBody] BaseRequest _, CancellationToken ct) { if (!TryGetViewerId(out var viewerId)) return Unauthorized(); var result = await _friend.GetFriendsAsync(viewerId, ct); @@ -30,7 +31,7 @@ public sealed class FriendController : SVSimController } [HttpPost("receive_apply_info")] - public async Task> ReceiveApplyInfo(CancellationToken ct) + public async Task> ReceiveApplyInfo([FromBody] BaseRequest _, CancellationToken ct) { if (!TryGetViewerId(out var viewerId)) return Unauthorized(); var result = await _friend.GetReceiveAppliesAsync(viewerId, ct); @@ -42,7 +43,7 @@ public sealed class FriendController : SVSimController } [HttpPost("send_apply_info")] - public async Task> SendApplyInfo(CancellationToken ct) + public async Task> SendApplyInfo([FromBody] BaseRequest _, CancellationToken ct) { if (!TryGetViewerId(out var viewerId)) return Unauthorized(); var result = await _friend.GetSendAppliesAsync(viewerId, ct); @@ -55,7 +56,7 @@ public sealed class FriendController : SVSimController } [HttpPost("played_together_info")] - public async Task> PlayedTogetherInfo(CancellationToken ct) + public async Task> PlayedTogetherInfo([FromBody] BaseRequest _, CancellationToken ct) { if (!TryGetViewerId(out var viewerId)) return Unauthorized(); var result = await _friend.GetPlayedTogetherAsync(viewerId, ct); @@ -109,7 +110,7 @@ public sealed class FriendController : SVSimController } [HttpPost("reject_apply_all")] - public async Task RejectApplyAll(CancellationToken ct) + public async Task RejectApplyAll([FromBody] BaseRequest _, CancellationToken ct) { if (!TryGetViewerId(out var viewerId)) return Unauthorized(); await _friend.RejectAllAppliesAsync(viewerId, ct); @@ -117,7 +118,7 @@ public sealed class FriendController : SVSimController } [HttpPost("cancel_apply_all")] - public async Task CancelApplyAll(CancellationToken ct) + public async Task CancelApplyAll([FromBody] BaseRequest _, CancellationToken ct) { if (!TryGetViewerId(out var viewerId)) return Unauthorized(); await _friend.CancelAllAppliesAsync(viewerId, ct); diff --git a/SVSim.UnitTests/Controllers/FriendControllerTests.cs b/SVSim.UnitTests/Controllers/FriendControllerTests.cs index e16c696..9efb286 100644 --- a/SVSim.UnitTests/Controllers/FriendControllerTests.cs +++ b/SVSim.UnitTests/Controllers/FriendControllerTests.cs @@ -13,6 +13,13 @@ public class FriendControllerTests { private static StringContent JsonBody(string json) => new(json, Encoding.UTF8, "application/json"); + // Minimal BaseRequest-shaped payload. Body-less /friend/* actions now declare + // [FromBody] BaseRequest _ so the prod translation middleware can deserialize + // the encrypted msgpack body (it requires at least one parameter). Tests post + // these auth fields so [ApiController] model validation passes — the actual + // viewer_id comes from the session claim, not the body. + private const string EmptyBody = """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}"""; + private static async Task SeedViewer(SVSimTestFactory factory, ulong steamId, string name = "Test Viewer") => await factory.SeedViewerAsync(steamId: steamId, displayName: name); @@ -23,7 +30,7 @@ public class FriendControllerTests long viewerId = await SeedViewer(factory, 76_561_198_000_010_001UL); using var client = factory.CreateAuthenticatedClient(viewerId); - var response = await client.PostAsync("/friend/info", JsonBody("{}")); + var response = await client.PostAsync("/friend/info", JsonBody(EmptyBody)); var raw = await response.Content.ReadAsStringAsync(); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), raw); @@ -40,7 +47,7 @@ public class FriendControllerTests long viewerId = await SeedViewer(factory, 76_561_198_000_010_002UL); using var client = factory.CreateAuthenticatedClient(viewerId); - var response = await client.PostAsync("/friend/receive_apply_info", JsonBody("{}")); + var response = await client.PostAsync("/friend/receive_apply_info", JsonBody(EmptyBody)); var raw = await response.Content.ReadAsStringAsync(); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), raw); @@ -56,7 +63,7 @@ public class FriendControllerTests long viewerId = await SeedViewer(factory, 76_561_198_000_010_003UL); using var client = factory.CreateAuthenticatedClient(viewerId); - var response = await client.PostAsync("/friend/send_apply_info", JsonBody("{}")); + var response = await client.PostAsync("/friend/send_apply_info", JsonBody(EmptyBody)); var raw = await response.Content.ReadAsStringAsync(); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), raw); @@ -73,7 +80,7 @@ public class FriendControllerTests long viewerId = await SeedViewer(factory, 76_561_198_000_010_004UL); using var client = factory.CreateAuthenticatedClient(viewerId); - var response = await client.PostAsync("/friend/played_together_info", JsonBody("{}")); + var response = await client.PostAsync("/friend/played_together_info", JsonBody(EmptyBody)); var raw = await response.Content.ReadAsStringAsync(); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK), raw); @@ -223,7 +230,7 @@ public class FriendControllerTests } using var client = factory.CreateAuthenticatedClient(me); - var response = await client.PostAsync("/friend/reject_apply_all", JsonBody("{}")); + var response = await client.PostAsync("/friend/reject_apply_all", JsonBody(EmptyBody)); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK)); using var verifyScope = factory.Services.CreateScope(); @@ -245,7 +252,7 @@ public class FriendControllerTests } using var client = factory.CreateAuthenticatedClient(me); - var response = await client.PostAsync("/friend/cancel_apply_all", JsonBody("{}")); + var response = await client.PostAsync("/friend/cancel_apply_all", JsonBody(EmptyBody)); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK)); using var verifyScope = factory.Services.CreateScope(); @@ -281,7 +288,7 @@ public class FriendControllerTests using var factory = new SVSimTestFactory(); var client = factory.CreateClient(); - var response = await client.PostAsync("/friend/info", JsonBody("{}")); + var response = await client.PostAsync("/friend/info", JsonBody(EmptyBody)); Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); } @@ -303,7 +310,7 @@ public class FriendControllerTests int applyId; using (var clientB = factory.CreateAuthenticatedClient(viewerB)) { - var resp = await clientB.PostAsync("/friend/receive_apply_info", JsonBody("{}")); + var resp = await clientB.PostAsync("/friend/receive_apply_info", JsonBody(EmptyBody)); var raw = await resp.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(raw); var applies = doc.RootElement.GetProperty("receive_applies"); @@ -323,7 +330,7 @@ public class FriendControllerTests async Task GetFriendName(long ownerId) { using var client = factory.CreateAuthenticatedClient(ownerId); - var resp = await client.PostAsync("/friend/info", JsonBody("{}")); + var resp = await client.PostAsync("/friend/info", JsonBody(EmptyBody)); var raw = await resp.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(raw); var friends = doc.RootElement.GetProperty("friends");