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
32 changes: 32 additions & 0 deletions docs/messages/message_reminders.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,37 @@ MessageReminder updatedReminder = MessageReminder.update("message-id", "user-id"
MessageReminder updatedReminder = MessageReminder.update("message-id", "user-id", null).request();
```

## Expiring a Message Reminder

Set `expiresAt` to have a reminder remove itself. Once that time passes, the reminder no longer shows up in queries, updating or deleting it returns a 404, and it stops counting against the per-user reminder limit. No event is sent when a reminder expires, and creating a reminder on the same message again replaces the expired one.

`expiresAt` must be at least one minute in the future and, when `remindAt` is set, later than `remindAt`.

```java
// Backend SDK

// Bookmark a message for 30 days
Date expiresAt = new Date(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000);

Reminder.createReminder("message-id")
.userId("user-id")
.expiresAt(expiresAt)
.request();
```

An update replaces both `remindAt` and `expiresAt`. A field left unset is cleared, so pass the current value of the one you want to keep.

```java
// Backend SDK

// Move the reminder time and keep the expiry
Reminder.updateReminder("message-id")
.userId("user-id")
.remindAt(newRemindAt)
.expiresAt(reminder.getExpiresAt())
.request();
```

## Deleting a Message Reminder

You can delete a reminder for a message when it's no longer needed.
Expand Down Expand Up @@ -96,6 +127,7 @@ You can filter the reminders based on different criteria:
- `remind_at` - Filter by the reminder time.
- `created_at` - Filter by the creation date.
- `channel_cid` - Filter by the channel ID.
- `expires_at` - Filter by the expiry time. It cannot be used for sorting.

The most common use case would be to filter by the reminder time. Like filtering overdue reminders, upcoming reminders, or reminders with no due date (saved for later).

Expand Down
15 changes: 15 additions & 0 deletions src/main/java/io/getstream/chat/java/models/Reminder.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public class Reminder {
@JsonProperty("remind_at")
private Date remindAt;

@Nullable
@JsonProperty("expires_at")
private Date expiresAt;

@Nullable
@JsonProperty("created_at")
private Date createdAt;
Expand Down Expand Up @@ -92,6 +96,10 @@ public static class ReminderCreateRequestData {
@JsonProperty("remind_at")
private Date remindAt;

@Nullable
@JsonProperty("expires_at")
private Date expiresAt;

public static class ReminderCreateRequest extends StreamRequest<ReminderCreateResponse> {
@NotNull private String messageId;

Expand Down Expand Up @@ -121,6 +129,10 @@ public static class ReminderUpdateRequestData {
@JsonProperty("remind_at")
private Date remindAt;

@Nullable
@JsonProperty("expires_at")
private Date expiresAt;

public static class ReminderUpdateRequest extends StreamRequest<ReminderUpdateResponse> {
@NotNull private String messageId;

Expand Down Expand Up @@ -243,6 +255,9 @@ public static ReminderCreateRequest createReminder(@NotNull String messageId) {
/**
* Updates a reminder for a message.
*
* <p>The update replaces both {@code remind_at} and {@code expires_at}: a field left unset is
* cleared, so pass the current value to keep it.
*
* @param messageId The ID of the message with the reminder
* @return A request builder for updating a reminder
*/
Expand Down
72 changes: 72 additions & 0 deletions src/test/java/io/getstream/chat/java/ReminderExpiresAtTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.getstream.chat.java;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import io.getstream.chat.java.models.Reminder;
import io.getstream.chat.java.models.Reminder.ReminderQueryResponse;
import java.util.Date;
import java.util.TimeZone;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class ReminderExpiresAtTest {

// Mirrors the visibility and date configuration of DefaultClient's mapper.
private static final ObjectMapper MAPPER =
new ObjectMapper()
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.setDateFormat(
new StdDateFormat()
.withColonInTimeZone(true)
.withTimeZone(TimeZone.getTimeZone("UTC")));

private static final Date EXPIRES_AT = new Date(1893456000000L); // 2030-01-01T00:00:00Z

@DisplayName("Create sends expires_at when set")
@Test
void whenCreatingWithExpiresAt_thenBodyCarriesIt() throws Exception {
String body =
MAPPER.writeValueAsString(
Reminder.createReminder("msg").userId("user").expiresAt(EXPIRES_AT).internalBuild());

Assertions.assertTrue(body.contains("\"expires_at\":\"2030-01-01T00:00:00.000+00:00\""), body);
}

@DisplayName("Update sends expires_at when set")
@Test
void whenUpdatingWithExpiresAt_thenBodyCarriesIt() throws Exception {
String body =
MAPPER.writeValueAsString(
Reminder.updateReminder("msg").userId("user").expiresAt(EXPIRES_AT).internalBuild());

Assertions.assertTrue(body.contains("\"expires_at\":\"2030-01-01T00:00:00.000+00:00\""), body);
}

@DisplayName("Create without expires_at sends null, which means no expiry")
@Test
void whenCreatingWithoutExpiresAt_thenBodyCarriesNull() throws Exception {
String body =
MAPPER.writeValueAsString(Reminder.createReminder("msg").userId("user").internalBuild());

Assertions.assertTrue(body.contains("\"expires_at\":null"), body);
}

@DisplayName("Responses read expires_at into the typed field")
@Test
void whenResponseHasExpiresAt_thenGetterReturnsIt() throws Exception {
ReminderQueryResponse response =
MAPPER.readValue(
"{\"reminders\":[{\"id\":\"r\",\"message_id\":\"msg\",\"user_id\":\"user\","
+ "\"channel_cid\":\"messaging:chan\",\"expires_at\":\"2030-01-01T00:00:00Z\"}],"
+ "\"duration\":\"1ms\"}",
ReminderQueryResponse.class);

Reminder reminder = response.getReminders().get(0);
Assertions.assertEquals(EXPIRES_AT, reminder.getExpiresAt());
Assertions.assertFalse(reminder.getAdditionalFields().containsKey("expires_at"));
}
}
Loading