diff --git a/src/main/java/io/getstream/chat/java/models/ChannelType.java b/src/main/java/io/getstream/chat/java/models/ChannelType.java index f1441a25..82d0fde0 100644 --- a/src/main/java/io/getstream/chat/java/models/ChannelType.java +++ b/src/main/java/io/getstream/chat/java/models/ChannelType.java @@ -145,6 +145,10 @@ public class ChannelType { @JsonProperty("count_messages") private Boolean countMessages; + @Nullable + @JsonProperty("polls") + private Boolean polls; + @Data @NoArgsConstructor public static class Threshold { @@ -427,6 +431,10 @@ public static class ChannelTypeCreateRequestData { @JsonProperty("count_messages") private Boolean countMessages; + @Nullable + @JsonProperty("polls") + protected Boolean polls; + public static class ChannelTypeCreateRequest extends StreamRequest { private static final boolean DEFAULT_PUSH_NOTIFICATIONS = true; @@ -579,6 +587,10 @@ public static class ChannelTypeUpdateRequestData { @JsonProperty("count_messages") private Boolean countMessages; + @Nullable + @JsonProperty("polls") + protected Boolean polls; + public static class ChannelTypeUpdateRequest extends StreamRequest { @NotNull private String name; diff --git a/src/main/java/io/getstream/chat/java/models/Poll.java b/src/main/java/io/getstream/chat/java/models/Poll.java new file mode 100644 index 00000000..5f201b37 --- /dev/null +++ b/src/main/java/io/getstream/chat/java/models/Poll.java @@ -0,0 +1,965 @@ +package io.getstream.chat.java.models; + +import com.fasterxml.jackson.annotation.JsonEnumDefaultValue; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.getstream.chat.java.models.Poll.PollCreateRequestData.PollCreateRequest; +import io.getstream.chat.java.models.Poll.PollOptionCreateRequestData.PollOptionCreateRequest; +import io.getstream.chat.java.models.Poll.PollOptionUpdateRequestData.PollOptionUpdateRequest; +import io.getstream.chat.java.models.Poll.PollQueryRequestData.PollQueryRequest; +import io.getstream.chat.java.models.Poll.PollUpdatePartialRequestData.PollUpdatePartialRequest; +import io.getstream.chat.java.models.Poll.PollUpdateRequestData.PollUpdateRequest; +import io.getstream.chat.java.models.Poll.PollVoteCastRequestData.PollVoteCastRequest; +import io.getstream.chat.java.models.Poll.PollVoteQueryRequestData.PollVoteQueryRequest; +import io.getstream.chat.java.models.framework.StreamRequest; +import io.getstream.chat.java.models.framework.StreamResponseObject; +import io.getstream.chat.java.services.PollService; +import io.getstream.chat.java.services.framework.Client; +import java.util.Date; +import java.util.List; +import java.util.Map; +import lombok.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import retrofit2.Call; + +@Data +@NoArgsConstructor +public class Poll { + @NotNull + @JsonProperty("id") + private String id; + + @NotNull + @JsonProperty("name") + private String name; + + @Nullable + @JsonProperty("description") + private String description; + + @Nullable + @JsonProperty("voting_visibility") + private VotingVisibility votingVisibility; + + @NotNull + @JsonProperty("enforce_unique_vote") + private Boolean enforceUniqueVote; + + @Nullable + @JsonProperty("max_votes_allowed") + private Integer maxVotesAllowed; + + @NotNull + @JsonProperty("allow_user_suggested_options") + private Boolean allowUserSuggestedOptions; + + @NotNull + @JsonProperty("allow_answers") + private Boolean allowAnswers; + + @NotNull + @JsonProperty("is_closed") + private Boolean isClosed; + + @Nullable + @JsonProperty("options") + private List options; + + @Nullable + @JsonProperty("vote_count") + private Integer voteCount; + + @Nullable + @JsonProperty("vote_counts_by_option") + private Map voteCountsByOption; + + @Nullable + @JsonProperty("answers_count") + private Integer answersCount; + + @Nullable + @JsonProperty("latest_votes_by_option") + private Map> latestVotesByOption; + + @Nullable + @JsonProperty("latest_answers") + private List latestAnswers; + + @Nullable + @JsonProperty("own_votes") + private List ownVotes; + + @NotNull + @JsonProperty("created_by_id") + private String createdById; + + @Nullable + @JsonProperty("created_by") + private User createdBy; + + @NotNull + @JsonProperty("created_at") + private Date createdAt; + + @NotNull + @JsonProperty("updated_at") + private Date updatedAt; + + @Nullable + @JsonProperty("custom") + private Map custom; + + public enum VotingVisibility { + @JsonProperty("public") + PUBLIC, + @JsonProperty("anonymous") + ANONYMOUS, + @JsonEnumDefaultValue + UNKNOWN + } + + @Data + @NoArgsConstructor + public static class PollOption { + @NotNull + @JsonProperty("id") + private String id; + + @Nullable + @JsonProperty("text") + private String text; + + @Nullable + @JsonProperty("custom") + private Map custom; + } + + @Data + @NoArgsConstructor + public static class PollVote { + @NotNull + @JsonProperty("poll_id") + private String pollId; + + @NotNull + @JsonProperty("id") + private String id; + + @Nullable + @JsonProperty("option_id") + private String optionId; + + @NotNull + @JsonProperty("is_answer") + private Boolean isAnswer; + + @Nullable + @JsonProperty("answer_text") + private String answerText; + + @Nullable + @JsonProperty("user_id") + private String userId; + + @Nullable + @JsonProperty("user") + private User user; + + @NotNull + @JsonProperty("created_at") + private Date createdAt; + + @NotNull + @JsonProperty("updated_at") + private Date updatedAt; + } + + @Builder( + builderClassName = "PollCreateRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollCreateRequestData { + @Nullable + @JsonProperty("id") + private String id; + + @Nullable + @JsonProperty("user_id") + private String userId; + + @Nullable + @JsonProperty("user") + private User user; + + @NotNull + @JsonProperty("name") + private String name; + + @Nullable + @JsonProperty("description") + private String description; + + @Singular + @Nullable + @JsonProperty("options") + private List options; + + @Nullable + @JsonProperty("voting_visibility") + private VotingVisibility votingVisibility; + + @Nullable + @JsonProperty("enforce_unique_vote") + private Boolean enforceUniqueVote; + + @Nullable + @JsonProperty("max_votes_allowed") + private Integer maxVotesAllowed; + + @Nullable + @JsonProperty("allow_user_suggested_options") + private Boolean allowUserSuggestedOptions; + + @Nullable + @JsonProperty("allow_answers") + private Boolean allowAnswers; + + @Nullable + @JsonProperty("is_closed") + private Boolean isClosed; + + @Nullable + @JsonProperty("custom") + private Map custom; + + @Data + @NoArgsConstructor + public static class PollOptionInput { + @Nullable + @JsonProperty("id") + private String id; + + @Nullable + @JsonProperty("text") + private String text; + + @Nullable + @JsonProperty("custom") + private Map custom; + } + + public static class PollCreateRequest extends StreamRequest { + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).create(this.internalBuild()); + } + } + } + + @Getter + @EqualsAndHashCode(callSuper = false) + @RequiredArgsConstructor + public static class PollGetRequest extends StreamRequest { + @NotNull private String pollId; + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).get(pollId); + } + } + + @Builder( + builderClassName = "PollUpdateRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @Setter + @EqualsAndHashCode(callSuper = false) + public static class PollUpdateRequestData { + @Nullable + @JsonProperty("id") + private String id; + + @Nullable + @JsonProperty("user") + private User user; + + @Nullable + @JsonProperty("user_id") + private String userId; + + @NotNull + @JsonProperty("name") + private String name; + + @Nullable + @JsonProperty("description") + private String description; + + @Singular + @Nullable + @JsonProperty("options") + private List options; + + @Nullable + @JsonProperty("voting_visibility") + private VotingVisibility votingVisibility; + + @Nullable + @JsonProperty("enforce_unique_vote") + private Boolean enforceUniqueVote; + + @Nullable + @JsonProperty("max_votes_allowed") + private Integer maxVotesAllowed; + + @Nullable + @JsonProperty("allow_user_suggested_options") + private Boolean allowUserSuggestedOptions; + + @Nullable + @JsonProperty("allow_answers") + private Boolean allowAnswers; + + @Nullable + @JsonProperty("is_closed") + private Boolean isClosed; + + @Nullable + @JsonProperty("custom") + private Map custom; + + @Data + @NoArgsConstructor + public static class PollOptionRequest { + @NotNull + @JsonProperty("id") + private String id; + + @Nullable + @JsonProperty("text") + private String text; + + @Nullable + @JsonProperty("custom") + private Map custom; + } + + public static class PollUpdateRequest extends StreamRequest { + @NotNull private String pollId; + + private PollUpdateRequest(@NotNull String pollId) { + this.pollId = pollId; + } + + @Override + protected Call generateCall(Client client) { + PollUpdateRequestData data = this.internalBuild(); + data.setId(pollId); + return client.create(PollService.class).update(data); + } + } + } + + @Builder( + builderClassName = "PollUpdatePartialRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollUpdatePartialRequestData { + @Nullable + @JsonProperty("user_id") + private String userId; + + @Nullable + @JsonProperty("set") + private Map set; + + @Singular("unset") + @Nullable + @JsonProperty("unset") + private List unset; + + public static class PollUpdatePartialRequest extends StreamRequest { + @NotNull private String pollId; + + private PollUpdatePartialRequest(@NotNull String pollId) { + this.pollId = pollId; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).updatePartial(pollId, this.internalBuild()); + } + } + } + + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollDeleteRequest extends StreamRequest { + @NotNull private String pollId; + @Nullable private String userId; + + public PollDeleteRequest(@NotNull String pollId) { + this.pollId = pollId; + } + + public PollDeleteRequest userId(@NotNull String userId) { + this.userId = userId; + return this; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).delete(pollId, userId); + } + } + + @Builder( + builderClassName = "PollQueryRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollQueryRequestData { + @Nullable + @JsonProperty("filter") + private Map filter; + + @Singular("sort") + @Nullable + @JsonProperty("sort") + private List sorts; + + @Nullable + @JsonProperty("limit") + private Integer limit; + + @Nullable + @JsonProperty("offset") + private Integer offset; + + @Nullable + @JsonProperty("next") + private String next; + + @Nullable + @JsonProperty("prev") + private String prev; + + public static class PollQueryRequest extends StreamRequest { + @Nullable private String userId; + + public PollQueryRequest userId(@NotNull String userId) { + this.userId = userId; + return this; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).query(this.internalBuild(), userId); + } + } + } + + @Builder( + builderClassName = "PollOptionCreateRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollOptionCreateRequestData { + @Nullable + @JsonProperty("user_id") + private String userId; + + @Nullable + @JsonProperty("user") + private User user; + + @NotNull + @JsonProperty("text") + private String text; + + @Nullable + @JsonProperty("custom") + private Map custom; + + public static class PollOptionCreateRequest extends StreamRequest { + @NotNull private String pollId; + + private PollOptionCreateRequest(@NotNull String pollId) { + this.pollId = pollId; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).createOption(pollId, this.internalBuild()); + } + } + } + + @Getter + @EqualsAndHashCode(callSuper = false) + @RequiredArgsConstructor + public static class PollOptionGetRequest extends StreamRequest { + @NotNull private String pollId; + @NotNull private String optionId; + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).getOption(pollId, optionId); + } + } + + @Builder( + builderClassName = "PollOptionUpdateRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollOptionUpdateRequestData { + @Nullable + @JsonProperty("user_id") + private String userId; + + @Nullable + @JsonProperty("user") + private User user; + + @NotNull + @JsonProperty("id") + private String id; + + @NotNull + @JsonProperty("text") + private String text; + + @Nullable + @JsonProperty("custom") + private Map custom; + + public static class PollOptionUpdateRequest extends StreamRequest { + @NotNull private String pollId; + + private PollOptionUpdateRequest(@NotNull String pollId) { + this.pollId = pollId; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).updateOption(pollId, this.internalBuild()); + } + } + } + + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollOptionDeleteRequest extends StreamRequest { + @NotNull private String pollId; + @NotNull private String optionId; + @Nullable private String userId; + + public PollOptionDeleteRequest(@NotNull String pollId, @NotNull String optionId) { + this.pollId = pollId; + this.optionId = optionId; + } + + public PollOptionDeleteRequest userId(@NotNull String userId) { + this.userId = userId; + return this; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).deleteOption(pollId, optionId, userId); + } + } + + @Builder( + builderClassName = "PollVoteQueryRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollVoteQueryRequestData { + @Nullable + @JsonProperty("filter") + private Map filter; + + @Singular("sort") + @Nullable + @JsonProperty("sort") + private List sorts; + + @Nullable + @JsonProperty("limit") + private Integer limit; + + @Nullable + @JsonProperty("offset") + private Integer offset; + + @Nullable + @JsonProperty("next") + private String next; + + @Nullable + @JsonProperty("prev") + private String prev; + + public static class PollVoteQueryRequest extends StreamRequest { + @NotNull private String pollId; + @Nullable private String userId; + + private PollVoteQueryRequest(@NotNull String pollId) { + this.pollId = pollId; + } + + public PollVoteQueryRequest userId(@NotNull String userId) { + this.userId = userId; + return this; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).queryVotes(pollId, this.internalBuild(), userId); + } + } + } + + @Builder( + builderClassName = "PollVoteCastRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class PollVoteCastRequestData { + @Nullable + @JsonProperty("user_id") + private String userId; + + @Nullable + @JsonProperty("user") + private User user; + + @Nullable + @JsonProperty("vote") + private VoteData vote; + + @Data + @NoArgsConstructor + public static class VoteData { + @Nullable + @JsonProperty("option_id") + private String optionId; + + @Nullable + @JsonProperty("answer_text") + private String answerText; + } + + public static class PollVoteCastRequest extends StreamRequest { + @NotNull private String messageId; + @NotNull private String pollId; + + private PollVoteCastRequest(@NotNull String messageId, @NotNull String pollId) { + this.messageId = messageId; + this.pollId = pollId; + } + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).castVote(messageId, pollId, this.internalBuild()); + } + } + } + + @Getter + @EqualsAndHashCode(callSuper = false) + @RequiredArgsConstructor + public static class PollVoteDeleteRequest extends StreamRequest { + @NotNull private String messageId; + @NotNull private String pollId; + @NotNull private String voteId; + + @Override + protected Call generateCall(Client client) { + return client.create(PollService.class).deleteVote(messageId, pollId, voteId); + } + } + + // Response classes + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollCreateResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll") + private Poll poll; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollGetResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll") + private Poll poll; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollUpdateResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll") + private Poll poll; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollUpdatePartialResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll") + private Poll poll; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollDeleteResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll") + private Poll poll; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollQueryResponse extends StreamResponseObject { + @NotNull + @JsonProperty("polls") + private List polls; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollOptionCreateResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll_option") + private PollOption pollOption; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollOptionGetResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll_option") + private PollOption pollOption; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollOptionUpdateResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll_option") + private PollOption pollOption; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollOptionDeleteResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll_option") + private PollOption pollOption; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollVoteQueryResponse extends StreamResponseObject { + @NotNull + @JsonProperty("votes") + private List votes; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollVoteCastResponse extends StreamResponseObject { + @Nullable + @JsonProperty("vote") + private PollVote vote; + + @Nullable + @JsonProperty("poll") + private Poll poll; + } + + @Data + @NoArgsConstructor + @EqualsAndHashCode(callSuper = true) + public static class PollVoteDeleteResponse extends StreamResponseObject { + @NotNull + @JsonProperty("poll") + private Poll poll; + } + + // Factory methods + /** + * Creates a create request + * + * @return the created request + */ + @NotNull + public static PollCreateRequest create() { + return new PollCreateRequest(); + } + + /** + * Creates a get request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollGetRequest get(@NotNull String pollId) { + return new PollGetRequest(pollId); + } + + /** + * Creates an update request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollUpdateRequest update(@NotNull String pollId) { + return new PollUpdateRequest(pollId); + } + + /** + * Creates a partial update request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollUpdatePartialRequest updatePartial(@NotNull String pollId) { + return new PollUpdatePartialRequest(pollId); + } + + /** + * Creates a delete request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollDeleteRequest delete(@NotNull String pollId) { + return new PollDeleteRequest(pollId); + } + + /** + * Creates a query request + * + * @return the created request + */ + @NotNull + public static PollQueryRequest query() { + return new PollQueryRequest(); + } + + /** + * Creates a create option request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollOptionCreateRequest createOption(@NotNull String pollId) { + return new PollOptionCreateRequest(pollId); + } + + /** + * Creates a get option request + * + * @param pollId the poll id + * @param optionId the option id + * @return the created request + */ + @NotNull + public static PollOptionGetRequest getOption(@NotNull String pollId, @NotNull String optionId) { + return new PollOptionGetRequest(pollId, optionId); + } + + /** + * Creates an update option request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollOptionUpdateRequest updateOption(@NotNull String pollId) { + return new PollOptionUpdateRequest(pollId); + } + + /** + * Creates a delete option request + * + * @param pollId the poll id + * @param optionId the option id + * @return the created request + */ + @NotNull + public static PollOptionDeleteRequest deleteOption( + @NotNull String pollId, @NotNull String optionId) { + return new PollOptionDeleteRequest(pollId, optionId); + } + + /** + * Creates a query votes request + * + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollVoteQueryRequest queryVotes(@NotNull String pollId) { + return new PollVoteQueryRequest(pollId); + } + + /** + * Creates a cast vote request + * + * @param messageId the message id + * @param pollId the poll id + * @return the created request + */ + @NotNull + public static PollVoteCastRequest castVote(@NotNull String messageId, @NotNull String pollId) { + return new PollVoteCastRequest(messageId, pollId); + } + + /** + * Creates a delete vote request + * + * @param messageId the message id + * @param pollId the poll id + * @param voteId the vote id + * @return the created request + */ + @NotNull + public static PollVoteDeleteRequest deleteVote( + @NotNull String messageId, @NotNull String pollId, @NotNull String voteId) { + return new PollVoteDeleteRequest(messageId, pollId, voteId); + } +} diff --git a/src/main/java/io/getstream/chat/java/services/PollService.java b/src/main/java/io/getstream/chat/java/services/PollService.java new file mode 100644 index 00000000..c57a68bb --- /dev/null +++ b/src/main/java/io/getstream/chat/java/services/PollService.java @@ -0,0 +1,87 @@ +package io.getstream.chat.java.services; + +import io.getstream.chat.java.models.Poll.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import retrofit2.Call; +import retrofit2.http.*; + +public interface PollService { + + // Poll CRUD endpoints + @POST("polls") + @NotNull + Call create(@NotNull @Body PollCreateRequestData pollCreateRequestData); + + @GET("polls/{poll_id}") + @NotNull + Call get(@NotNull @Path("poll_id") String pollId); + + @PUT("polls") + @NotNull + Call update(@NotNull @Body PollUpdateRequestData pollUpdateRequestData); + + @PATCH("polls/{poll_id}") + @NotNull + Call updatePartial( + @NotNull @Path("poll_id") String pollId, + @NotNull @Body PollUpdatePartialRequestData pollUpdatePartialRequestData); + + @DELETE("polls/{poll_id}") + @NotNull + Call delete( + @NotNull @Path("poll_id") String pollId, @Nullable @Query("user_id") String userId); + + @POST("polls/query") + @NotNull + Call query( + @NotNull @Body PollQueryRequestData pollQueryRequestData, + @Nullable @Query("user_id") String userId); + + // PollOption CRUD endpoints + @POST("polls/{poll_id}/options") + @NotNull + Call createOption( + @NotNull @Path("poll_id") String pollId, + @NotNull @Body PollOptionCreateRequestData pollOptionCreateRequestData); + + @GET("polls/{poll_id}/options/{option_id}") + @NotNull + Call getOption( + @NotNull @Path("poll_id") String pollId, @NotNull @Path("option_id") String optionId); + + @PUT("polls/{poll_id}/options") + @NotNull + Call updateOption( + @NotNull @Path("poll_id") String pollId, + @NotNull @Body PollOptionUpdateRequestData pollOptionUpdateRequestData); + + @DELETE("polls/{poll_id}/options/{option_id}") + @NotNull + Call deleteOption( + @NotNull @Path("poll_id") String pollId, + @NotNull @Path("option_id") String optionId, + @Nullable @Query("user_id") String userId); + + // PollVote endpoints + @POST("polls/{poll_id}/votes") + @NotNull + Call queryVotes( + @NotNull @Path("poll_id") String pollId, + @NotNull @Body PollVoteQueryRequestData pollVoteQueryRequestData, + @Nullable @Query("user_id") String userId); + + @POST("messages/{message_id}/polls/{poll_id}/vote") + @NotNull + Call castVote( + @NotNull @Path("message_id") String messageId, + @NotNull @Path("poll_id") String pollId, + @NotNull @Body PollVoteCastRequestData pollVoteCastRequestData); + + @DELETE("messages/{message_id}/polls/{poll_id}/vote/{vote_id}") + @NotNull + Call deleteVote( + @NotNull @Path("message_id") String messageId, + @NotNull @Path("poll_id") String pollId, + @NotNull @Path("vote_id") String voteId); +} diff --git a/src/test/java/io/getstream/chat/java/PollTest.java b/src/test/java/io/getstream/chat/java/PollTest.java new file mode 100644 index 00000000..1bb52f2c --- /dev/null +++ b/src/test/java/io/getstream/chat/java/PollTest.java @@ -0,0 +1,349 @@ +package io.getstream.chat.java; + +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.ChannelType; +import io.getstream.chat.java.models.FilterCondition; +import io.getstream.chat.java.models.Message; +import io.getstream.chat.java.models.Message.MessageRequestObject; +import io.getstream.chat.java.models.Poll; +import io.getstream.chat.java.models.Poll.PollCreateRequestData.PollOptionInput; +import io.getstream.chat.java.models.Poll.PollUpdateRequestData.PollOptionRequest; +import io.getstream.chat.java.models.Sort; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class PollTest extends BasicTest { + + @BeforeAll + static void setupPolls() { + // Enable polls on the channel type + Assertions.assertDoesNotThrow( + () -> ChannelType.update(testChannel.getType()).polls(true).request()); + + // Also enable polls on the channel via config_overrides + Map configOverrides = new HashMap<>(); + configOverrides.put("polls", true); + + Assertions.assertDoesNotThrow( + () -> + Channel.partialUpdate(testChannel.getType(), testChannel.getId()) + .setValue("config_overrides", configOverrides) + .request()); + + // Wait for changes to propagate + try { + Thread.sleep(6000); + } catch (InterruptedException e) { + // Do nothing + } + } + + @DisplayName("Can create poll") + @Test + void whenCreatingPoll_thenCorrectName() { + String pollName = "test poll"; + PollOptionInput option1 = new PollOptionInput(); + option1.setText("Option 1"); + PollOptionInput option2 = new PollOptionInput(); + option2.setText("Option 2"); + + Poll poll = + Assertions.assertDoesNotThrow( + () -> + Poll.create() + .userId(testUserRequestObject.getId()) + .name(pollName) + .description("Test description") + .options(List.of(option1, option2)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + Assertions.assertEquals(pollName, poll.getName()); + Assertions.assertNotNull(poll.getId()); + Assertions.assertNotNull(poll.getOptions()); + Assertions.assertEquals(2, poll.getOptions().size()); + + // Cleanup + Assertions.assertDoesNotThrow( + () -> Poll.delete(poll.getId()).userId(testUserRequestObject.getId()).request()); + } + + @DisplayName("Can perform poll CRUD operations") + @Test + void whenPerformingPollCRUD_thenCorrectOperations() { + PollOptionInput option1 = new PollOptionInput(); + option1.setText("Option 1"); + PollOptionInput option2 = new PollOptionInput(); + option2.setText("Option 2"); + + // Create + String originalName = "original poll name"; + Poll created = + Assertions.assertDoesNotThrow( + () -> + Poll.create() + .userId(testUserRequestObject.getId()) + .name(originalName) + .description("Original description") + .options(List.of(option1, option2)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + Assertions.assertEquals(originalName, created.getName()); + String pollId = created.getId(); + + pause(); + + // Read + Poll retrieved = Assertions.assertDoesNotThrow(() -> Poll.get(pollId).request()).getPoll(); + Assertions.assertEquals(pollId, retrieved.getId()); + Assertions.assertEquals(originalName, retrieved.getName()); + + // Update + String updatedName = "updated poll name"; + PollOptionRequest updatedOption1 = new PollOptionRequest(); + updatedOption1.setId(created.getOptions().get(0).getId()); + updatedOption1.setText("Updated Option 1"); + PollOptionRequest updatedOption2 = new PollOptionRequest(); + updatedOption2.setId(created.getOptions().get(1).getId()); + updatedOption2.setText("Updated Option 2"); + + Poll updated = + Assertions.assertDoesNotThrow( + () -> + Poll.update(pollId) + .userId(testUserRequestObject.getId()) + .name(updatedName) + .description("Updated description") + .options(List.of(updatedOption1, updatedOption2)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + Assertions.assertEquals(updatedName, updated.getName()); + + pause(); + + // Update Partial + Map setFields = new HashMap<>(); + setFields.put("name", "partially updated name"); + Poll partiallyUpdated = + Assertions.assertDoesNotThrow( + () -> + Poll.updatePartial(pollId) + .userId(testUserRequestObject.getId()) + .set(setFields) + .request()) + .getPoll(); + Assertions.assertEquals("partially updated name", partiallyUpdated.getName()); + + pause(); + + // Delete + Assertions.assertDoesNotThrow( + () -> Poll.delete(pollId).userId(testUserRequestObject.getId()).request()); + } + + @DisplayName("Can perform poll option CRUD operations") + @Test + void whenPerformingPollOptionCRUD_thenCorrectOperations() { + PollOptionInput option1 = new PollOptionInput(); + option1.setText("Option 1"); + + Poll created = + Assertions.assertDoesNotThrow( + () -> + Poll.create() + .userId(testUserRequestObject.getId()) + .name("poll with options") + .description("Test poll") + .options(List.of(option1)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + String pollId = created.getId(); + + pause(); + + // Create option + Poll.PollOption newOption = + Assertions.assertDoesNotThrow( + () -> + Poll.createOption(pollId) + .userId(testUserRequestObject.getId()) + .text("New Option") + .request()) + .getPollOption(); + Assertions.assertNotNull(newOption.getId()); + Assertions.assertEquals("New Option", newOption.getText()); + + pause(); + + // Get option + Poll.PollOption retrievedOption = + Assertions.assertDoesNotThrow(() -> Poll.getOption(pollId, newOption.getId()).request()) + .getPollOption(); + Assertions.assertEquals(newOption.getId(), retrievedOption.getId()); + + // Update option + Poll.PollOption updatedOption = + Assertions.assertDoesNotThrow( + () -> + Poll.updateOption(pollId) + .userId(testUserRequestObject.getId()) + .id(newOption.getId()) + .text("Updated Option Text") + .request()) + .getPollOption(); + Assertions.assertEquals("Updated Option Text", updatedOption.getText()); + + pause(); + + // Delete option + Assertions.assertDoesNotThrow( + () -> + Poll.deleteOption(pollId, updatedOption.getId()) + .userId(testUserRequestObject.getId()) + .request()); + + // Cleanup + Assertions.assertDoesNotThrow( + () -> Poll.delete(pollId).userId(testUserRequestObject.getId()).request()); + } + + @DisplayName("Can query polls") + @Test + void whenQueryingPolls_thenCorrectResults() { + PollOptionInput option1 = new PollOptionInput(); + option1.setText("Option 1"); + + Poll created = + Assertions.assertDoesNotThrow( + () -> + Poll.create() + .userId(testUserRequestObject.getId()) + .name("query test poll") + .description("Test poll for query") + .options(List.of(option1)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + String pollId = created.getId(); + + pause(); + + // Query by ID + List polls = + Assertions.assertDoesNotThrow( + () -> + Poll.query() + .userId(testUserRequestObject.getId()) + .filter(FilterCondition.eq("id", pollId)) + .sorts( + List.of( + Sort.builder() + .field("created_at") + .direction(Sort.Direction.DESC) + .build())) + .limit(10) + .request()) + .getPolls(); + Assertions.assertTrue( + polls.stream().anyMatch(p -> p.getId().equals(pollId)), + "Created poll should be found in query results"); + + // Cleanup + Assertions.assertDoesNotThrow( + () -> Poll.delete(pollId).userId(testUserRequestObject.getId()).request()); + } + + @DisplayName("Can create poll without ID") + @Test + void whenCreatingPollWithoutId_thenIdIsGenerated() { + PollOptionInput option1 = new PollOptionInput(); + option1.setText("Option 1"); + + Poll poll = + Assertions.assertDoesNotThrow( + () -> + Poll.create() + .userId(testUserRequestObject.getId()) + .name("auto id poll") + .description("Test poll") + .options(List.of(option1)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + Assertions.assertNotNull(poll.getId()); + Assertions.assertFalse(poll.getId().isEmpty()); + + // Cleanup + Assertions.assertDoesNotThrow( + () -> Poll.delete(poll.getId()).userId(testUserRequestObject.getId()).request()); + } + + @DisplayName("Can query poll votes") + @Test + void whenQueryingPollVotes_thenCorrectResults() { + PollOptionInput option1 = new PollOptionInput(); + option1.setText("Option 1"); + PollOptionInput option2 = new PollOptionInput(); + option2.setText("Option 2"); + + Poll created = + Assertions.assertDoesNotThrow( + () -> + Poll.create() + .userId(testUserRequestObject.getId()) + .name("poll for votes") + .description("Test poll") + .options(List.of(option1, option2)) + .votingVisibility(Poll.VotingVisibility.PUBLIC) + .enforceUniqueVote(false) + .request()) + .getPoll(); + String pollId = created.getId(); + + pause(); + + // Attach poll to a message (required before querying votes) + MessageRequestObject messageRequest = + MessageRequestObject.builder() + .text("Message with poll") + .userId(testUserRequestObject.getId()) + .additionalField("poll_id", pollId) + .build(); + Assertions.assertDoesNotThrow( + () -> + Message.send(testChannel.getType(), testChannel.getId()) + .message(messageRequest) + .request()); + + pause(); + + // Query votes (should be empty initially) + List votes = + Assertions.assertDoesNotThrow( + () -> + Poll.queryVotes(pollId) + .userId(testUserRequestObject.getId()) + .limit(10) + .request()) + .getVotes(); + Assertions.assertNotNull(votes); + + // Cleanup + Assertions.assertDoesNotThrow( + () -> Poll.delete(pollId).userId(testUserRequestObject.getId()).request()); + } +}