From 3104c7e0cbcc1f30705d3b4dbd4ed9dfc37ed2a7 Mon Sep 17 00:00:00 2001 From: Ali Momen Sani Date: Fri, 24 May 2024 10:27:44 +0200 Subject: [PATCH] feat: add message history (#278) * feat: add message history * fix: check length of map instead of nil equality --- message_history.go | 68 +++++++++++++++++++++++++++++++ message_history_test.go | 90 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 message_history.go create mode 100644 message_history_test.go diff --git a/message_history.go b/message_history.go new file mode 100644 index 0000000..df460d2 --- /dev/null +++ b/message_history.go @@ -0,0 +1,68 @@ +package stream_chat + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "time" +) + +type QueryMessageHistoryRequest struct { + Filter map[string]any `json:"filter"` + Sort []*SortOption `json:"sort,omitempty"` + + Limit int `json:"limit,omitempty"` + Next string `json:"next,omitempty"` + Prev string `json:"prev,omitempty"` +} + +type MessageHistoryEntry struct { + MessageID string `json:"message_id"` + MessageUpdatedByID string `json:"message_updated_by_id"` + MessageUpdatedAt time.Time `json:"message_updated_at"` + + Text string `json:"text"` + Attachments []*Attachment `json:"attachments"` + ExtraData map[string]interface{} `json:"-"` +} + +var _ json.Unmarshaler = (*MessageHistoryEntry)(nil) +var _ json.Marshaler = (*MessageHistoryEntry)(nil) + +type messageHistoryJson MessageHistoryEntry + +func (m *MessageHistoryEntry) UnmarshalJSON(data []byte) error { + var m2 messageHistoryJson + if err := json.Unmarshal(data, &m2); err != nil { + return err + } + *m = MessageHistoryEntry(m2) + + if err := json.Unmarshal(data, &m.ExtraData); err != nil { + return err + } + removeFromMap(m.ExtraData, *m) + return nil +} + +func (m MessageHistoryEntry) MarshalJSON() ([]byte, error) { + return addToMapAndMarshal(m.ExtraData, messageHistoryJson(m)) +} + +type QueryMessageHistoryResponse struct { + MessageHistory []*MessageHistoryEntry `json:"message_history"` + + Next *string `json:"next,omitempty"` + Prev *string `json:"prev,omitempty"` + Response +} + +func (c *Client) QueryMessageHistory(ctx context.Context, request QueryMessageHistoryRequest) (*QueryMessageHistoryResponse, error) { + if len(request.Filter) == 0 { + return nil, errors.New("you need specify one filter at least") + } + var resp QueryMessageHistoryResponse + err := c.makeRequest(ctx, http.MethodPost, "messages/history", nil, request, &resp) + return &resp, err +} diff --git a/message_history_test.go b/message_history_test.go new file mode 100644 index 0000000..4067ddf --- /dev/null +++ b/message_history_test.go @@ -0,0 +1,90 @@ +package stream_chat + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMessageHistory(t *testing.T) { + client := initClient(t) + users := randomUsers(t, client, 2) + user1 := users[0] + user2 := users[1] + + ch := initChannel(t, client, user1.ID) + + ctx := context.Background() + initialText := "initial text" + customField := "custom_field" + initialCustomFieldValue := "custom value" + // send a message with initial text + response, err := ch.SendMessage(ctx, &Message{Text: initialText, ExtraData: map[string]interface{}{customField: initialCustomFieldValue}}, user1.ID) + require.NoError(t, err) + message := response.Message + + updatedText1 := "updated text" + updatedCustomFieldValue := "updated custom value" + // update the message by user1 + _, err = client.UpdateMessage(ctx, &Message{Text: updatedText1, ExtraData: map[string]interface{}{customField: updatedCustomFieldValue}, UserID: user1.ID}, message.ID) + assert.NoError(t, err) + + updatedText2 := "updated text 2" + // update the message by user2 + _, err = client.UpdateMessage(ctx, &Message{Text: updatedText2, UserID: user2.ID}, message.ID) + assert.NoError(t, err) + + t.Run("test query", func(t *testing.T) { + req := QueryMessageHistoryRequest{ + Filter: map[string]interface{}{ + "message_id": message.ID, + }, + } + messageHistoryResponse, err := client.QueryMessageHistory(ctx, req) + assert.NoError(t, err) + assert.NotNil(t, messageHistoryResponse) + + history := messageHistoryResponse.MessageHistory + assert.Equal(t, 2, len(history)) + + firstUpdate := history[1] + assert.Equal(t, initialText, firstUpdate.Text) + assert.Equal(t, user1.ID, firstUpdate.MessageUpdatedByID) + assert.Equal(t, initialCustomFieldValue, firstUpdate.ExtraData[customField].(string)) + + secondUpdate := history[0] + assert.Equal(t, updatedText1, secondUpdate.Text) + assert.Equal(t, user2.ID, secondUpdate.MessageUpdatedByID) + assert.Equal(t, updatedCustomFieldValue, secondUpdate.ExtraData[customField].(string)) + }) + + t.Run("test sorting", func(t *testing.T) { + sortedHistoryQueryRequest := QueryMessageHistoryRequest{ + Filter: map[string]interface{}{ + "message_id": message.ID, + }, + Sort: []*SortOption{ + { + Field: "message_updated_at", + Direction: 1, + }, + }, + } + sortedHistoryResponse, err := client.QueryMessageHistory(ctx, sortedHistoryQueryRequest) + assert.NoError(t, err) + assert.NotNil(t, sortedHistoryResponse) + + sortedHistory := sortedHistoryResponse.MessageHistory + assert.Equal(t, 2, len(sortedHistory)) + + firstUpdate := sortedHistory[0] + assert.Equal(t, initialText, firstUpdate.Text) + assert.Equal(t, user1.ID, firstUpdate.MessageUpdatedByID) + + secondUpdate := sortedHistory[1] + assert.Equal(t, updatedText1, secondUpdate.Text) + assert.Equal(t, user2.ID, secondUpdate.MessageUpdatedByID) + }) +}