diff --git a/src/main/java/org/qortal/api/ApiError.java b/src/main/java/org/qortal/api/ApiError.java index 659104e7..b52332b1 100644 --- a/src/main/java/org/qortal/api/ApiError.java +++ b/src/main/java/org/qortal/api/ApiError.java @@ -79,7 +79,7 @@ public enum ApiError { // BUYER_ALREADY_OWNER(411, 422), // POLLS - // POLL_NO_EXISTS(501, 404), + POLL_NO_EXISTS(501, 404), // POLL_ALREADY_EXISTS(502, 422), // DUPLICATE_OPTION(503, 422), // POLL_OPTION_NO_EXISTS(504, 404), diff --git a/src/main/java/org/qortal/api/resource/AdminResource.java b/src/main/java/org/qortal/api/resource/AdminResource.java index ef2a3f95..154f9159 100644 --- a/src/main/java/org/qortal/api/resource/AdminResource.java +++ b/src/main/java/org/qortal/api/resource/AdminResource.java @@ -153,6 +153,22 @@ public class AdminResource { return nodeStatus; } + @GET + @Path("/settings") + @Operation( + summary = "Fetch node settings", + responses = { + @ApiResponse( + content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Settings.class)) + ) + } + ) + public Settings settings() { + Settings nodeSettings = Settings.getInstance(); + + return nodeSettings; + } + @GET @Path("/stop") @Operation( diff --git a/src/main/java/org/qortal/api/resource/VotingResource.java b/src/main/java/org/qortal/api/resource/VotingResource.java index bd57c9f7..d98d23a3 100644 --- a/src/main/java/org/qortal/api/resource/VotingResource.java +++ b/src/main/java/org/qortal/api/resource/VotingResource.java @@ -29,12 +29,79 @@ import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import java.util.List; +import javax.ws.rs.GET; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import org.qortal.api.ApiException; +import org.qortal.data.voting.PollData; + @Path("/Voting") @Tag(name = "Voting") public class VotingResource { @Context HttpServletRequest request; + @GET + @Operation( + summary = "List all polls", + responses = { + @ApiResponse( + description = "poll info", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + array = @ArraySchema(schema = @Schema(implementation = PollData.class)) + ) + ) + } + ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) + public List getAllPolls(@Parameter( + ref = "limit" + ) @QueryParam("limit") Integer limit, @Parameter( + ref = "offset" + ) @QueryParam("offset") Integer offset, @Parameter( + ref = "reverse" + ) @QueryParam("reverse") Boolean reverse) { + try (final Repository repository = RepositoryManager.getRepository()) { + List allPollData = repository.getVotingRepository().getAllPolls(limit, offset, reverse); + return allPollData; + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + + @GET + @Path("/{pollName}") + @Operation( + summary = "Info on poll", + responses = { + @ApiResponse( + description = "poll info", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = PollData.class) + ) + ) + } + ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) + public PollData getPollData(@PathParam("pollName") String pollName) { + try (final Repository repository = RepositoryManager.getRepository()) { + PollData pollData = repository.getVotingRepository().fromPollName(pollName); + if (pollData == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.POLL_NO_EXISTS); + + return pollData; + } catch (ApiException e) { + throw e; + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + @POST @Path("/CreatePoll") @Operation( diff --git a/src/main/java/org/qortal/data/transaction/TransactionData.java b/src/main/java/org/qortal/data/transaction/TransactionData.java index ec1139f4..838cffd3 100644 --- a/src/main/java/org/qortal/data/transaction/TransactionData.java +++ b/src/main/java/org/qortal/data/transaction/TransactionData.java @@ -12,6 +12,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.transaction.Transaction.ApprovalStatus; import org.qortal.transaction.Transaction.TransactionType; @@ -29,6 +30,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, 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/PollData.java b/src/main/java/org/qortal/data/voting/PollData.java index 4af62087..1850ddc7 100644 --- a/src/main/java/org/qortal/data/voting/PollData.java +++ b/src/main/java/org/qortal/data/voting/PollData.java @@ -14,6 +14,11 @@ public class PollData { // Constructors + // For JAXB + protected PollData() { + super(); + } + public PollData(byte[] creatorPublicKey, String owner, String pollName, String description, List pollOptions, long published) { this.creatorPublicKey = creatorPublicKey; this.owner = owner; @@ -29,22 +34,42 @@ public class PollData { return this.creatorPublicKey; } + public void setCreatorPublicKey(byte[] creatorPublicKey) { + this.creatorPublicKey = creatorPublicKey; + } + public String getOwner() { return this.owner; } + public void setOwner(String owner) { + this.owner = owner; + } + public String getPollName() { return this.pollName; } + public void setPollName(String pollName) { + this.pollName = pollName; + } + public String getDescription() { return this.description; } + public void setDescription(String description) { + this.description = description; + } + public List getPollOptions() { return this.pollOptions; } + public void setPollOptions(List pollOptions) { + this.pollOptions = pollOptions; + } + public long getPublished() { return this.published; } diff --git a/src/main/java/org/qortal/repository/VotingRepository.java b/src/main/java/org/qortal/repository/VotingRepository.java index 28a9f6c7..b0e2954c 100644 --- a/src/main/java/org/qortal/repository/VotingRepository.java +++ b/src/main/java/org/qortal/repository/VotingRepository.java @@ -9,6 +9,8 @@ public interface VotingRepository { // Polls + public List getAllPolls(Integer limit, Integer offset, Boolean reverse) throws DataException; + public PollData fromPollName(String pollName) throws DataException; public boolean pollExists(String pollName) throws DataException; diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBVotingRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBVotingRepository.java index 447fbe4c..cc33426b 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBVotingRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBVotingRepository.java @@ -21,6 +21,55 @@ public class HSQLDBVotingRepository implements VotingRepository { // Polls + @Override + public List getAllPolls(Integer limit, Integer offset, Boolean reverse) throws DataException { + StringBuilder sql = new StringBuilder(512); + + sql.append("SELECT poll_name, description, creator, owner, published_when FROM Polls ORDER BY poll_name"); + + if (reverse != null && reverse) + sql.append(" DESC"); + + HSQLDBRepository.limitOffsetSql(sql, limit, offset); + + List polls = new ArrayList<>(); + + try (ResultSet resultSet = this.repository.checkedExecute(sql.toString())) { + if (resultSet == null) + return polls; + + do { + String pollName = resultSet.getString(1); + String description = resultSet.getString(2); + byte[] creatorPublicKey = resultSet.getBytes(3); + String owner = resultSet.getString(4); + long published = resultSet.getLong(5); + + String optionsSql = "SELECT option_name FROM PollOptions WHERE poll_name = ? ORDER BY option_index ASC"; + try (ResultSet optionsResultSet = this.repository.checkedExecute(optionsSql, pollName)) { + if (optionsResultSet == null) + return null; + + List pollOptions = new ArrayList<>(); + + // NOTE: do-while because checkedExecute() above has already called rs.next() for us + do { + String optionName = optionsResultSet.getString(1); + + pollOptions.add(new PollOptionData(optionName)); + } while (optionsResultSet.next()); + + polls.add(new PollData(creatorPublicKey, owner, pollName, description, pollOptions, published)); + } + + } while (resultSet.next()); + + return polls; + } catch (SQLException e) { + throw new DataException("Unable to fetch polls from repository", e); + } + } + @Override public PollData fromPollName(String pollName) throws DataException { String sql = "SELECT description, creator, owner, published_when FROM Polls WHERE poll_name = ?";