diff --git a/DOCS.md b/DOCS.md index f775c34dd..f10f4a463 100644 --- a/DOCS.md +++ b/DOCS.md @@ -367,6 +367,17 @@ User.list() FilterCondition.contains("teams", "red")))); ``` +**Get channel (type,id)** + +Returns the channel without creating it. A channel that does not exist yields a 404, so this also works as an existence check. + +```java +Channel.getChannel("messaging", "travel") + .state(true) + .messagesLimit(20) + .request(); +``` + **Get or create channel (type,id)** Standard diff --git a/src/main/java/io/getstream/chat/java/models/Channel.java b/src/main/java/io/getstream/chat/java/models/Channel.java index 2730e18f7..cdc99b0d8 100644 --- a/src/main/java/io/getstream/chat/java/models/Channel.java +++ b/src/main/java/io/getstream/chat/java/models/Channel.java @@ -17,6 +17,7 @@ import io.getstream.chat.java.models.Channel.ChannelTruncateRequestData.ChannelTruncateRequest; import io.getstream.chat.java.models.Channel.ChannelUnMuteRequestData.ChannelUnMuteRequest; import io.getstream.chat.java.models.Channel.ChannelUpdateRequestData.ChannelUpdateRequest; +import io.getstream.chat.java.models.Channel.GetChannelRequestData.GetChannelRequest; import io.getstream.chat.java.models.Channel.MarkDeliveredRequestData.MarkDeliveredRequest; import io.getstream.chat.java.models.ChannelType.BlocklistBehavior; import io.getstream.chat.java.models.ChannelType.ChannelTypeWithCommands; @@ -551,6 +552,48 @@ protected Call generateCall(Client client) { } } + @Builder( + builderClassName = "GetChannelRequest", + builderMethodName = "", + buildMethodName = "internalBuild") + @Getter + @EqualsAndHashCode(callSuper = false) + public static class GetChannelRequestData { + @Nullable + @JsonProperty("state") + private Boolean state; + + @Nullable + @JsonProperty("messages_limit") + private Integer messagesLimit; + + @Nullable + @JsonProperty("members_limit") + private Integer membersLimit; + + @Nullable + @JsonProperty("watchers_limit") + private Integer watchersLimit; + + public static class GetChannelRequest extends StreamRequest { + @NotNull private String channelType; + + @NotNull private String channelId; + + private GetChannelRequest(@NotNull String channelType, @NotNull String channelId) { + this.channelType = channelType; + this.channelId = channelId; + } + + @Override + protected Call generateCall(Client client) { + return client + .create(ChannelService.class) + .getChannel(this.channelType, this.channelId, this.internalBuild()); + } + } + } + @Builder( builderClassName = "ChannelUpdateRequest", builderMethodName = "", @@ -1643,6 +1686,19 @@ public static ChannelGetRequest getOrCreate(@NotNull String type) { return new ChannelGetRequest(type, null); } + /** + * Creates a get channel request. The channel is never created: a missing, deleted or disabled + * channel yields a 404, so this request doubles as an existence check. + * + * @param type the channel type + * @param id the channel id + * @return the created request + */ + @NotNull + public static GetChannelRequest getChannel(@NotNull String type, @NotNull String id) { + return new GetChannelRequest(type, id); + } + /** * Creates an update request * diff --git a/src/main/java/io/getstream/chat/java/services/ChannelService.java b/src/main/java/io/getstream/chat/java/services/ChannelService.java index 82a2b8e2e..f71803836 100644 --- a/src/main/java/io/getstream/chat/java/services/ChannelService.java +++ b/src/main/java/io/getstream/chat/java/services/ChannelService.java @@ -27,6 +27,14 @@ Call getOrCreateWithoutId( @NotNull @Path("type") String channelType, @Nullable @Body ChannelGetRequestData channelGetRequestData); + // The endpoint reads its options from a JSON `payload` query parameter and fails with 400 without + // one, so the request data goes there instead of into flat query parameters. + @GET("channels/{type}/{id}") + Call getChannel( + @NotNull @Path("type") String channelType, + @NotNull @Path("id") String channelId, + @NotNull @ToJson @Query("payload") GetChannelRequestData getChannelRequestData); + @DELETE("channels/{type}/{id}") Call delete( @NotNull @Path("type") String channelType, @NotNull @Path("id") String channelId); diff --git a/src/test/java/io/getstream/chat/java/ChannelTest.java b/src/test/java/io/getstream/chat/java/ChannelTest.java index d871b1452..a468c145e 100644 --- a/src/test/java/io/getstream/chat/java/ChannelTest.java +++ b/src/test/java/io/getstream/chat/java/ChannelTest.java @@ -1,5 +1,6 @@ package io.getstream.chat.java; +import io.getstream.chat.java.exceptions.StreamException; import io.getstream.chat.java.models.Channel; import io.getstream.chat.java.models.Channel.*; import io.getstream.chat.java.models.DeleteStrategy; @@ -37,6 +38,31 @@ void whenRetrievingChannel_thenNoException() { .request()); } + @DisplayName("Can get an existing channel") + @Test + void whenGettingExistingChannel_thenReturnsChannel() { + var response = + Assertions.assertDoesNotThrow( + () -> + Channel.getChannel(testChannel.getType(), testChannel.getId()) + .state(true) + .request()); + Assertions.assertNotNull(response.getChannel()); + Assertions.assertEquals(testChannel.getId(), response.getChannel().getId()); + } + + @DisplayName("Get channel does not create a missing channel") + @Test + void whenGettingMissingChannel_thenNotFound() { + var exception = + Assertions.assertThrows( + StreamException.class, + () -> + Channel.getChannel(testChannel.getType(), RandomStringUtils.randomAlphabetic(12)) + .request()); + Assertions.assertEquals(404, exception.getResponseData().getStatusCode()); + } + @DisplayName("Can create channel with invites") @Test void whenCreatingChannelWithInvites_thenNoException() { diff --git a/src/test/java/io/getstream/chat/java/GetChannelTest.java b/src/test/java/io/getstream/chat/java/GetChannelTest.java new file mode 100644 index 000000000..100e32a57 --- /dev/null +++ b/src/test/java/io/getstream/chat/java/GetChannelTest.java @@ -0,0 +1,47 @@ +package io.getstream.chat.java; + +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.services.ChannelService; +import io.getstream.chat.java.services.framework.DefaultClient; +import java.util.Properties; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class GetChannelTest { + + @Test + @DisplayName("Get channel sends a GET with its options in the payload query parameter") + void whenBuildingGetChannelRequest_thenOptionsGoIntoPayloadQueryParameter() { + var data = Channel.getChannel("messaging", "abc").state(true).messagesLimit(5).internalBuild(); + + var request = + client().create(ChannelService.class).getChannel("messaging", "abc", data).request(); + + Assertions.assertEquals("GET", request.method()); + Assertions.assertEquals("/channels/messaging/abc", request.url().encodedPath()); + + var payload = request.url().queryParameter("payload"); + Assertions.assertNotNull(payload); + Assertions.assertTrue(payload.contains("\"state\":true"), payload); + Assertions.assertTrue(payload.contains("\"messages_limit\":5"), payload); + } + + @Test + @DisplayName("Get channel sends a payload query parameter even without options") + void whenBuildingGetChannelRequestWithoutOptions_thenPayloadQueryParameterIsStillSent() { + var data = Channel.getChannel("messaging", "abc").internalBuild(); + + var request = + client().create(ChannelService.class).getChannel("messaging", "abc", data).request(); + + Assertions.assertNotNull(request.url().queryParameter("payload")); + } + + private DefaultClient client() { + var properties = new Properties(); + properties.put(DefaultClient.API_KEY_PROP_NAME, "test-key"); + properties.put(DefaultClient.API_SECRET_PROP_NAME, "test-secret"); + return new DefaultClient(properties); + } +}