From cda32a47f182aca1f2563fc5d10f7fbd01e66294 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Mon, 8 May 2023 20:23:54 -0400 Subject: [PATCH 1/3] Added API call to get votes --- .../qortal/api/resource/PollsResource.java | 30 +++++++++++++++++++ .../data/transaction/TransactionData.java | 3 +- .../qortal/data/voting/VoteOnPollData.java | 17 +++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/api/resource/PollsResource.java b/src/main/java/org/qortal/api/resource/PollsResource.java index 952cbdc5..ab163342 100644 --- a/src/main/java/org/qortal/api/resource/PollsResource.java +++ b/src/main/java/org/qortal/api/resource/PollsResource.java @@ -37,6 +37,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import org.qortal.api.ApiException; import org.qortal.data.voting.PollData; +import org.qortal.data.voting.VoteOnPollData; @Path("/polls") @Tag(name = "Polls") @@ -102,6 +103,35 @@ public class PollsResource { } } + @GET + @Path("/votes/{pollName}") + @Operation( + summary = "Votes on poll", + responses = { + @ApiResponse( + description = "poll votes", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = VoteOnPollData.class) + ) + ) + } + ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) + public List getVoteOnPollData(@PathParam("pollName") String pollName) { + try (final Repository repository = RepositoryManager.getRepository()) { + if (repository.getVotingRepository().fromPollName(pollName) == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.POLL_NO_EXISTS); + + List voteOnPollData = repository.getVotingRepository().getVotes(pollName); + return voteOnPollData; + } catch (ApiException e) { + throw e; + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + @POST @Path("/create") @Operation( diff --git a/src/main/java/org/qortal/data/transaction/TransactionData.java b/src/main/java/org/qortal/data/transaction/TransactionData.java index 838cffd3..4bf3152c 100644 --- a/src/main/java/org/qortal/data/transaction/TransactionData.java +++ b/src/main/java/org/qortal/data/transaction/TransactionData.java @@ -13,6 +13,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode; import org.qortal.crypto.Crypto; import org.qortal.data.voting.PollData; +import org.qortal.data.voting.VoteOnPollData; import org.qortal.transaction.Transaction.ApprovalStatus; import org.qortal.transaction.Transaction.TransactionType; @@ -30,7 +31,7 @@ import io.swagger.v3.oas.annotations.media.Schema.AccessMode; @XmlSeeAlso({GenesisTransactionData.class, PaymentTransactionData.class, RegisterNameTransactionData.class, UpdateNameTransactionData.class, SellNameTransactionData.class, CancelSellNameTransactionData.class, BuyNameTransactionData.class, CreatePollTransactionData.class, VoteOnPollTransactionData.class, ArbitraryTransactionData.class, - PollData.class, + PollData.class, VoteOnPollData.class, IssueAssetTransactionData.class, TransferAssetTransactionData.class, CreateAssetOrderTransactionData.class, CancelAssetOrderTransactionData.class, MultiPaymentTransactionData.class, DeployAtTransactionData.class, MessageTransactionData.class, ATTransactionData.class, diff --git a/src/main/java/org/qortal/data/voting/VoteOnPollData.java b/src/main/java/org/qortal/data/voting/VoteOnPollData.java index 47c06a54..531ed286 100644 --- a/src/main/java/org/qortal/data/voting/VoteOnPollData.java +++ b/src/main/java/org/qortal/data/voting/VoteOnPollData.java @@ -9,6 +9,11 @@ public class VoteOnPollData { // Constructors + // For JAXB + protected VoteOnPollData() { + super(); + } + public VoteOnPollData(String pollName, byte[] voterPublicKey, int optionIndex) { this.pollName = pollName; this.voterPublicKey = voterPublicKey; @@ -21,12 +26,24 @@ public class VoteOnPollData { return this.pollName; } + public void setPollName(String pollName) { + this.pollName = pollName; + } + public byte[] getVoterPublicKey() { return this.voterPublicKey; } + public void setVoterPublicKey(byte[] voterPublicKey) { + this.voterPublicKey = voterPublicKey; + } + public int getOptionIndex() { return this.optionIndex; } + public void setOptionIndex(int optionIndex) { + this.optionIndex = optionIndex; + } + } From 49c0d45bc6ec11766bf89844e0f4b320ffa0be23 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Mon, 8 May 2023 23:26:23 -0400 Subject: [PATCH 2/3] Added count to get votes API call --- .../java/org/qortal/api/model/PollVotes.java | 56 +++++++++++++++++++ .../qortal/api/resource/PollsResource.java | 37 ++++++++++-- 2 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/qortal/api/model/PollVotes.java diff --git a/src/main/java/org/qortal/api/model/PollVotes.java b/src/main/java/org/qortal/api/model/PollVotes.java new file mode 100644 index 00000000..c57ebc37 --- /dev/null +++ b/src/main/java/org/qortal/api/model/PollVotes.java @@ -0,0 +1,56 @@ +package org.qortal.api.model; + +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; + +import io.swagger.v3.oas.annotations.media.Schema; + +import org.qortal.data.voting.VoteOnPollData; + +@Schema(description = "Poll vote info, including voters") +// All properties to be converted to JSON via JAX-RS +@XmlAccessorType(XmlAccessType.FIELD) +public class PollVotes { + + @Schema(description = "List of individual votes") + @XmlElement(name = "votes") + public List votes; + + @Schema(description = "Total number of votes") + public Integer totalVotes; + + @Schema(description = "List of vote counts for each option") + public List voteCounts; + + // For JAX-RS + protected PollVotes() { + } + + public PollVotes(List votes, Integer totalVotes, List voteCounts) { + this.votes = votes; + this.totalVotes = totalVotes; + this.voteCounts = voteCounts; + } + + @Schema(description = "Vote info") + // All properties to be converted to JSON via JAX-RS + @XmlAccessorType(XmlAccessType.FIELD) + public static class OptionCount { + @Schema(description = "Option name") + public String optionName; + + @Schema(description = "Vote count") + public Integer voteCount; + + // For JAX-RS + protected OptionCount() { + } + + public OptionCount(String optionName, Integer voteCount) { + this.optionName = optionName; + this.voteCount = voteCount; + } + } +} diff --git a/src/main/java/org/qortal/api/resource/PollsResource.java b/src/main/java/org/qortal/api/resource/PollsResource.java index ab163342..999fa2fd 100644 --- a/src/main/java/org/qortal/api/resource/PollsResource.java +++ b/src/main/java/org/qortal/api/resource/PollsResource.java @@ -31,12 +31,17 @@ import javax.ws.rs.core.MediaType; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.ArraySchema; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javax.ws.rs.GET; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import org.qortal.api.ApiException; +import org.qortal.api.model.PollVotes; import org.qortal.data.voting.PollData; +import org.qortal.data.voting.PollOptionData; import org.qortal.data.voting.VoteOnPollData; @Path("/polls") @@ -112,19 +117,41 @@ public class PollsResource { description = "poll votes", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = VoteOnPollData.class) + schema = @Schema(implementation = PollVotes.class) ) ) } ) @ApiErrors({ApiError.REPOSITORY_ISSUE}) - public List getVoteOnPollData(@PathParam("pollName") String pollName) { + public PollVotes getPollVotes(@PathParam("pollName") String pollName) { try (final Repository repository = RepositoryManager.getRepository()) { - if (repository.getVotingRepository().fromPollName(pollName) == null) + PollData pollData = repository.getVotingRepository().fromPollName(pollName); + if (pollData == null) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.POLL_NO_EXISTS); - List voteOnPollData = repository.getVotingRepository().getVotes(pollName); - return voteOnPollData; + List votes = repository.getVotingRepository().getVotes(pollName); + + // Initialize map for counting votes + Map voteCountMap = new HashMap<>(); + for (PollOptionData optionData : pollData.getPollOptions()) { + voteCountMap.put(optionData.getOptionName(), 0); + } + + int totalVotes = 0; + for (VoteOnPollData vote : votes) { + String selectedOption = pollData.getPollOptions().get(vote.getOptionIndex()).getOptionName(); + if (voteCountMap.containsKey(selectedOption)) { + voteCountMap.put(selectedOption, voteCountMap.get(selectedOption) + 1); + totalVotes++; + } + } + + // Convert map to list of VoteInfo + List voteCounts = voteCountMap.entrySet().stream() + .map(entry -> new PollVotes.OptionCount(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + + return new PollVotes(votes, totalVotes, voteCounts); } catch (ApiException e) { throw e; } catch (DataException e) { From 3e45948646c3e9fa22108c898c7334c51605314c Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Mon, 8 May 2023 23:41:31 -0400 Subject: [PATCH 3/3] Added get votes option to return only counts --- src/main/java/org/qortal/api/resource/PollsResource.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/PollsResource.java b/src/main/java/org/qortal/api/resource/PollsResource.java index 999fa2fd..c64a8caf 100644 --- a/src/main/java/org/qortal/api/resource/PollsResource.java +++ b/src/main/java/org/qortal/api/resource/PollsResource.java @@ -123,7 +123,7 @@ public class PollsResource { } ) @ApiErrors({ApiError.REPOSITORY_ISSUE}) - public PollVotes getPollVotes(@PathParam("pollName") String pollName) { + public PollVotes getPollVotes(@PathParam("pollName") String pollName, @QueryParam("onlyCounts") Boolean onlyCounts) { try (final Repository repository = RepositoryManager.getRepository()) { PollData pollData = repository.getVotingRepository().fromPollName(pollName); if (pollData == null) @@ -151,7 +151,11 @@ public class PollsResource { .map(entry -> new PollVotes.OptionCount(entry.getKey(), entry.getValue())) .collect(Collectors.toList()); - return new PollVotes(votes, totalVotes, voteCounts); + if (onlyCounts != null && onlyCounts) { + return new PollVotes(null, totalVotes, voteCounts); + } else { + return new PollVotes(votes, totalVotes, voteCounts); + } } catch (ApiException e) { throw e; } catch (DataException e) {