Skip to content

Commit

Permalink
feat: Add migration endpoint (#5)
Browse files Browse the repository at this point in the history
Co-authored-by: Joyd <joyd@meero.com>
  • Loading branch information
JoydS and Joyd authored May 6, 2024
1 parent 8362b7a commit 966890e
Show file tree
Hide file tree
Showing 5 changed files with 313 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,7 @@ issues:
text: "got 'user_ids' want 'user_i_ds'"
linters:
- tagliatelle
- path: 'pkg/message/migrate_messages.go'
text: "got 'mentioned_user_ids' want 'mention_user_i_ds'"
linters:
- tagliatelle
4 changes: 4 additions & 0 deletions pkg/message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ type Message interface {
// ListMessages retrieves a list of messages in a channel.
// See https://sendbird.com/docs/chat/platform-api/v3/message/messaging-basics/list-messages
ListMessages(ctx context.Context, channelType ChannelType, channelURL string, listMessagesRequest ListMessagesRequest) (*ListMessagesResponse, error)

// MigrateMessages migrates messages to a channel.
// See https://sendbird.com/docs/chat/platform-api/v3/message/migration/migrate-messages
MigrateMessages(ctx context.Context, channelURL string, migrateMessagesRequest MigrateMessagesRequest) error
}

type message struct {
Expand Down
94 changes: 94 additions & 0 deletions pkg/message/migrate_messages.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package message

import (
"context"
"errors"
"fmt"
)

type TextMessage struct {
// UserID specifies the user ID of the sender - required.
UserID string `json:"user_id"`

// MessageType specifies the type of the message - required.
MessageType MessageType `json:"message_type"`

// Message specifies the content of the message - required.
Message string `json:"message,omitempty"`

// Timestamp specifies the time when the message was sent in Unix milliseconds format - required.
Timestamp int64 `json:"timestamp,omitempty"`

// CustomType specifies a custom message type used for message grouping. The
// length is limited to 128 characters - optional.
CustomType string `json:"custom_type,omitempty"`

// MentionUserIDs specifies an array of IDs of the users to mention in the
// message. This property is used only when mention_type is users - optional.
MentionUserIDs []string `json:"mentioned_user_ids,omitempty"`

// Data specifies additional message information. This property serves as a
// container for a long text of any type of characters which can also be a
// JSON-formatted string like {"font-size": "24px"} - optional.
Data string `json:"data,omitempty"`

// DedupID specifies a unique ID for the message created by another system.
// In general, this property is used to prevent the same message data from
// getting inserted when migrating messages from another system to the
// Sendbird server. If specified, the server performs a duplicate check using
// the property value - optional.
DedupID string `json:"dedup_id,omitempty"`
}

// MigrateMessagesRequest is the request to migrate messages to a channel.
type MigrateMessagesRequest struct {
// Messages specifies an array of messages to migrate - required.
Messages []TextMessage `json:"messages"`

// UpdateReadTS determines whether to update the read receipt time for all channel members when message.timestamp
// of the latest migrated message is prior to their read receipt time
UpdateReadTS bool `json:"update_read_ts,omitempty"`
}

func (smr *MigrateMessagesRequest) Validate() error {
if len(smr.Messages) == 0 {
return errors.New("messages cannot be empty")
}

for _, message := range smr.Messages {
if message.UserID == "" {
return errors.New("user_id cannot be empty")
}

if message.MessageType == "" {
return errors.New("message_type cannot be empty")
}

if message.Message == "" {
return errors.New("message cannot be empty")
}

if message.Timestamp == 0 {
return errors.New("timestamp cannot be empty")
}
}

return nil
}

// MigrateMessages migrates messages to a channel.
// See https://sendbird.com/docs/chat/platform-api/v3/message/migration/migrate-messages
func (m *message) MigrateMessages(ctx context.Context, channelURL string, migrateMessagesRequest MigrateMessagesRequest) error {
if err := migrateMessagesRequest.Validate(); err != nil {
return fmt.Errorf("failed to validate migrate messages request: %w", err)
}

path := "/migration/" + channelURL

_, err := m.client.Post(ctx, path, migrateMessagesRequest, nil)
if err != nil {
return fmt.Errorf("failed to migrate messages: %w", err)
}

return nil
}
132 changes: 132 additions & 0 deletions pkg/message/migrate_messages_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package message

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/tomMoulard/sendbird-go/pkg/client"
)

func TestValidateMMR(t *testing.T) {
t.Parallel()

tests := []struct {
name string
request MigrateMessagesRequest
assertErr assert.ErrorAssertionFunc
}{
{
name: "invalid request - empty messages",
request: MigrateMessagesRequest{
Messages: []TextMessage{},
},
assertErr: assert.Error,
},
{
name: "invalid request - missing user_id",
request: MigrateMessagesRequest{
Messages: []TextMessage{
{
MessageType: MessageTypeText,
Message: "Hello, World!",
Timestamp: 1609459200000,
},
},
},
assertErr: assert.Error,
},
{
name: "invalid request - missing message_type",
request: MigrateMessagesRequest{
Messages: []TextMessage{
{
UserID: "42",
Message: "Hello, World!",
Timestamp: 1609459200000,
},
},
},
assertErr: assert.Error,
},
{
name: "invalid request - missing message",
request: MigrateMessagesRequest{
Messages: []TextMessage{
{
UserID: "42",
MessageType: MessageTypeText,
Timestamp: 1609459200000,
},
},
},
assertErr: assert.Error,
},
{
name: "invalid request - missing timestamp",
request: MigrateMessagesRequest{
Messages: []TextMessage{
{
UserID: "42",
MessageType: MessageTypeText,
Message: "Hello, World!",
},
},
},
assertErr: assert.Error,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

err := test.request.Validate()
test.assertErr(t, err)
})
}
}

func TestMigrateMessages(t *testing.T) {
t.Parallel()

validRequest := MigrateMessagesRequest{
Messages: []TextMessage{
{
UserID: "42",
MessageType: MessageTypeText,
Message: "Hello, World!",
Timestamp: 1609459200000,
CustomType: "greeting",
Data: `{ "emotion": "happy" }`,
DedupID: "unique123",
},
},
}

tests := []struct {
name string
request MigrateMessagesRequest
assertErr assert.ErrorAssertionFunc
}{
{
name: "valid request",
request: validRequest,
assertErr: assert.NoError,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

client := client.NewClientMock(t).
OnPost("/migration/channel_url", test.request, nil).TypedReturns(nil, nil).Once().
Parent
message := NewMessage(client)

err := message.MigrateMessages(context.Background(), "channel_url", test.request)
test.assertErr(t, err)
})
}
}
79 changes: 79 additions & 0 deletions pkg/message/mock_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 966890e

Please sign in to comment.