From 2e4dbde7c91e32213ea3962196fa91352bd39aad Mon Sep 17 00:00:00 2001 From: Daniel Widgren Date: Sat, 4 Jul 2026 18:31:06 +0200 Subject: [PATCH] feat(votes): typed Vote model for AsobiVotes Extracts the only still-unique content from the stale #15 branch: a typed Vote/VoteListResponse model so AsobiVotes.GetAsync/ListForMatchAsync return parsed objects instead of raw JSON strings. Scalar fields deserialize via JsonUtility; the jsonb fields (options/votes_cast/result/distribution) arrive as arrays/objects and are captured as raw JSON via ExtractJsonField, matching the established ParseMatchRecord convention. #15's other changes are dropped as already-landed: auth (#19), the dispatcher/test infra (#13), .editorconfig (#17). --- Runtime/Api/AsobiVotes.cs | 10 ++++++---- Runtime/JsonHelper.cs | 23 +++++++++++++++++++++++ Runtime/Models/VoteModels.cs | 29 +++++++++++++++++++++++++++++ Runtime/Models/VoteModels.cs.meta | 11 +++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 Runtime/Models/VoteModels.cs create mode 100644 Runtime/Models/VoteModels.cs.meta diff --git a/Runtime/Api/AsobiVotes.cs b/Runtime/Api/AsobiVotes.cs index 38a0ffd..4af5e93 100644 --- a/Runtime/Api/AsobiVotes.cs +++ b/Runtime/Api/AsobiVotes.cs @@ -7,14 +7,16 @@ public class AsobiVotes readonly AsobiClient _client; internal AsobiVotes(AsobiClient client) => _client = client; - public async Task ListForMatchAsync(string matchId) + public async Task ListForMatchAsync(string matchId) { - return await _client.Http.GetRaw($"/api/v1/matches/{matchId}/votes"); + var raw = await _client.Http.GetRaw($"/api/v1/matches/{matchId}/votes"); + return JsonHelper.ParseVoteList(raw); } - public async Task GetAsync(string voteId) + public async Task GetAsync(string voteId) { - return await _client.Http.GetRaw($"/api/v1/votes/{voteId}"); + var raw = await _client.Http.GetRaw($"/api/v1/votes/{voteId}"); + return JsonHelper.ParseVote(raw); } } } diff --git a/Runtime/JsonHelper.cs b/Runtime/JsonHelper.cs index 12583fe..74a80b8 100644 --- a/Runtime/JsonHelper.cs +++ b/Runtime/JsonHelper.cs @@ -54,6 +54,29 @@ internal static MatchListResponse ParseMatchList(string json) return new MatchListResponse { matches = matches }; } + internal static Vote ParseVote(string json) + { + var vote = JsonUtility.FromJson(json); + vote.options = ExtractJsonField(json, "options"); + vote.votes_cast = ExtractJsonField(json, "votes_cast"); + vote.result = ExtractJsonField(json, "result"); + vote.distribution = ExtractJsonField(json, "distribution"); + return vote; + } + + internal static VoteListResponse ParseVoteList(string json) + { + var votesJson = ExtractJsonField(json, "votes"); + if (string.IsNullOrEmpty(votesJson)) + return new VoteListResponse { votes = Array.Empty() }; + + var items = SplitJsonArray(votesJson); + var votes = new Vote[items.Length]; + for (int i = 0; i < items.Length; i++) + votes[i] = ParseVote(items[i]); + return new VoteListResponse { votes = votes }; + } + internal static Notification ParseNotification(string json) { var notif = JsonUtility.FromJson(json); diff --git a/Runtime/Models/VoteModels.cs b/Runtime/Models/VoteModels.cs new file mode 100644 index 0000000..89f4c5d --- /dev/null +++ b/Runtime/Models/VoteModels.cs @@ -0,0 +1,29 @@ +using System; + +namespace Asobi +{ + [Serializable] + public class Vote + { + public string id; + public string match_id; + public string template; + public string method; + public string options; + public string votes_cast; + public string result; + public string distribution; + public float turnout; + public int eligible_count; + public int window_ms; + public string opened_at; + public string closed_at; + public string inserted_at; + } + + [Serializable] + public class VoteListResponse + { + public Vote[] votes; + } +} diff --git a/Runtime/Models/VoteModels.cs.meta b/Runtime/Models/VoteModels.cs.meta new file mode 100644 index 0000000..9f57e98 --- /dev/null +++ b/Runtime/Models/VoteModels.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d538144a366c4498b233f4a3bc55c479 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: