fix(guild): friend_list returns bare array-at-root (matches GuildFriendListTask.Parse)

GuildFriendListTask.Parse() reads base.ResponseData[data][i] directly —
data must be a bare JSON array, not {friends:[...]}.  Delete the
GuildFriendListResponse wrapper DTO; promote GuildInviteCandidateDto to its
own file.  Controller now returns List<GuildInviteCandidateDto> so the
middleware wraps it as data:[…].  Update wire-shape and integration tests to
assert array-at-root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-27 14:35:20 -04:00
parent f2b996a593
commit 484b51086a
4 changed files with 58 additions and 68 deletions

View File

@@ -174,13 +174,13 @@ public sealed class GuildController : SVSimController
}
[HttpPost("friend_list")]
public async Task<ActionResult<GuildFriendListResponse>> FriendList([FromBody] BaseRequest _, CancellationToken ct)
public async Task<ActionResult<List<GuildInviteCandidateDto>>> FriendList([FromBody] BaseRequest _, CancellationToken ct)
{
if (!TryGetViewerId(out var viewerId)) return Unauthorized();
var friendInfo = await _friends.GetFriendsAsync(viewerId, ct);
if (friendInfo.Friends.Count == 0)
return new GuildFriendListResponse { Friends = new() };
return new List<GuildInviteCandidateDto>();
// For each friend, determine if they are already in a guild (is_join_guild).
var friendViewerIds = friendInfo.Friends.Select(f => (long)f.ViewerId).ToList();
@@ -206,7 +206,7 @@ public sealed class GuildController : SVSimController
});
}
return new GuildFriendListResponse { Friends = candidates };
return candidates;
}
[HttpPost("invite_user_list")]

View File

@@ -1,26 +1,14 @@
using MessagePack;
using System.Text.Json.Serialization;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common.Guild;
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Guild;
/// <summary>
/// Response for POST /guild/friend_list.
/// NOTE: per guild-friend_list.md, `data` is an array at the root — BUT we return this
/// as a wrapper for now; the controller returns the List directly.
/// TODO(task-14): verify array-root shape via capture; may need a custom response wrapper.
/// One entry in the /guild/friend_list response.
/// GuildFriendListTask.Parse() iterates base.ResponseData["data"][i] directly — data is a
/// bare JSON array, not a wrapper object. This DTO is the element type of that array.
/// </summary>
[MessagePackObject]
public class GuildFriendListResponse
{
// Placeholder — see controller; actual wire shape is array-at-root per spec.
// The controller returns List<GuildInviteCandidateDto> directly for now.
[JsonPropertyName("friends"), Key("friends")]
public List<GuildInviteCandidateDto> Friends { get; set; } = new();
}
/// <summary>InviteCandidate — UserInfoBase + is_join_guild flag.</summary>
[MessagePackObject]
public class GuildInviteCandidateDto
{
[JsonPropertyName("viewer_id"), Key("viewer_id"), JsonConverter(typeof(SVSim.EmulatedEntrypoint.Models.Dtos.Common.StringifiedLongConverter))]