Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/channels/channel_management/deleting.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ Channel.delete(
> If you recreate this channel, it will show up empty. Recovering old messages is not supported. Use the disable method if you want a reversible change.


### Keeping the messages

Call `setSkipTruncate(true)` to keep the messages of a soft deleted channel, so recreating the channel with the same id restores its history. It cannot be combined with a hard delete, and only distinct channels are eligible.

```java
Channel.delete("messaging", channelId).setSkipTruncate(true).request();

// same option on the batch endpoint
Channel.deleteMany(Arrays.asList(cid1, cid2)).setSkipTruncate(true).request();
```

## Deleting Many Channels

You can delete up to 100 channels and optionally all of their messages using this method. This can be a large amount of data to delete, so this endpoint processes asynchronously, meaning responses contain a `task ID` which can be polled using the [getTask endpoint](/chat/docs/java#tasks-gettask) to check status of the deletions. Channels will be soft-deleted immediately so that channels no longer return from queries, but permanently deleting the channel and deleting messages takes longer to process.
Expand Down
27 changes: 26 additions & 1 deletion src/main/java/io/getstream/chat/java/models/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -792,9 +792,22 @@ public static class ChannelDeleteRequest extends StreamRequest<ChannelDeleteResp

@NotNull private String channelId;

@Nullable private Boolean skipTruncate;

/**
* Keeps the messages of a soft deleted channel, so recreating it with the same id restores the
* history. Cannot be combined with a hard delete, and only distinct channels are eligible.
*/
public ChannelDeleteRequest setSkipTruncate(boolean skipTruncate) {
this.skipTruncate = skipTruncate;
return this;
}

@Override
protected Call<ChannelDeleteResponse> generateCall(Client client) {
return client.create(ChannelService.class).delete(this.channelType, this.channelId);
return client
.create(ChannelService.class)
.delete(this.channelType, this.channelId, this.skipTruncate);
}
}

Expand All @@ -811,11 +824,23 @@ public static class ChannelDeleteManyRequest extends StreamRequest<ChannelDelete
@Setter(AccessLevel.NONE)
private boolean hardDelete;

@JsonProperty("skip_truncate")
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private Boolean skipTruncate;

public ChannelDeleteManyRequest setDeleteStrategy(DeleteStrategy strategy) {
hardDelete = strategy == DeleteStrategy.HARD;
return this;
}

/** See {@link ChannelDeleteRequest#setSkipTruncate(boolean)}. */
public ChannelDeleteManyRequest setSkipTruncate(boolean skipTruncate) {
this.skipTruncate = skipTruncate;
return this;
}

@Override
protected Call<ChannelDeleteManyResponse> generateCall(Client svcFactory)
throws StreamException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ Call<ChannelGetResponse> getChannel(
Call<ChannelDeleteResponse> delete(
@NotNull @Path("type") String channelType, @NotNull @Path("id") String channelId);

@DELETE("channels/{type}/{id}")
Call<ChannelDeleteResponse> delete(
@NotNull @Path("type") String channelType,
@NotNull @Path("id") String channelId,
@Nullable @Query("skip_truncate") Boolean skipTruncate);

@POST("channels/delete")
Call<Channel.ChannelDeleteManyResponse> deleteMany(
@NotNull @Body Channel.ChannelDeleteManyRequest channelDeleteManyRequest);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.getstream.chat.java;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.getstream.chat.java.models.Channel;
import io.getstream.chat.java.services.ChannelService;
import java.util.Arrays;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;

public class ChannelDeleteSkipTruncateTest {

// Mirrors the visibility configuration of DefaultClient's mapper.
private static final ObjectMapper MAPPER =
new ObjectMapper()
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

private static ChannelService service() {
return new Retrofit.Builder()
.baseUrl("https://chat.example.com/")
.addConverterFactory(JacksonConverterFactory.create(MAPPER))
.build()
.create(ChannelService.class);
}

@DisplayName("Delete sends skip_truncate as a query param when set")
@Test
void whenSkipTruncateSet_thenQueryParamIsSent() {
String url = service().delete("messaging", "chan", true).request().url().toString();

Assertions.assertTrue(url.contains("skip_truncate=true"), url);
}

@DisplayName("Delete omits skip_truncate when unset")
@Test
void whenSkipTruncateUnset_thenQueryParamIsOmitted() {
String url = service().delete("messaging", "chan", null).request().url().toString();

Assertions.assertFalse(url.contains("skip_truncate"), url);
}

@DisplayName("The two argument delete overload is still callable")
@Test
void whenCallingTwoArgumentDelete_thenNoQueryParamIsSent() {
String url = service().delete("messaging", "chan").request().url().toString();

Assertions.assertFalse(url.contains("skip_truncate"), url);
}

@DisplayName("Delete request carries the flag to the service call")
@Test
void whenSettingSkipTruncateOnRequest_thenFlagIsKept() {
Assertions.assertEquals(
true, Channel.delete("messaging", "chan").setSkipTruncate(true).getSkipTruncate());
Assertions.assertNull(Channel.delete("messaging", "chan").getSkipTruncate());
}

@DisplayName("Delete many serializes skip_truncate only when set")
@Test
void whenSettingSkipTruncateOnDeleteMany_thenBodyCarriesIt() throws Exception {
Assertions.assertFalse(
MAPPER
.writeValueAsString(Channel.deleteMany(Arrays.asList("messaging:chan")))
.contains("skip_truncate"));
Assertions.assertTrue(
MAPPER
.writeValueAsString(
Channel.deleteMany(Arrays.asList("messaging:chan")).setSkipTruncate(true))
.contains("\"skip_truncate\":true"));
}
}
Loading