diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 650a960..8c09999 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,9 +26,9 @@ jobs: uses: actions/setup-go@v3 with: go-version: '1.13.0' - # - # - name: lint - # uses: morphy2k/revive-action@v2 + + - name: lint + uses: morphy2k/revive-action@v2 - name: build run: ./scripts/test.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a8df91..ad9b680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v1.14.0 + +- refactor(im): build reply and update message with standalone methods +- feat(im): UpdateMessage supports text and post in addition to card +- feat(im): ReplyMessage suports reply in thread + ## v1.13.3 - feat(event): support message_recalled, message_reaction_created, and message_reaction_deleted diff --git a/api_message.go b/api_message.go index f07927f..cbd5435 100644 --- a/api_message.go +++ b/api_message.go @@ -27,10 +27,11 @@ type PostMessageResponse struct { // IMMessageRequest . type IMMessageRequest struct { - ReceiveID string `json:"receive_id"` - Content string `json:"content"` - MsgType string `json:"msg_type"` - UUID string `json:"uuid,omitempty"` + Content string `json:"content"` + MsgType string `json:"msg_type,omitempty"` + ReceiveID string `json:"receive_id,omitempty"` + UUID string `json:"uuid,omitempty"` + ReplyInThread bool `json:"reply_in_thread,omitempty"` } // IMSender . @@ -56,19 +57,20 @@ type IMBody struct { // IMMessage . type IMMessage struct { - MessageID string `json:"message_id"` - UpperMessageID string `json:"upper_message_id"` - RootID string `json:"root_id"` - ParentID string `json:"parent_id"` - ChatID string `json:"chat_id"` - MsgType string `json:"msg_type"` - CreateTime string `json:"create_time"` - UpdateTime string `json:"update_time"` - Deleted bool `json:"deleted"` - Updated bool `json:"updated"` - Sender IMSender - Mentions []IMMention - Body IMBody + MessageID string `json:"message_id"` + UpperMessageID string `json:"upper_message_id"` + RootID string `json:"root_id"` + ParentID string `json:"parent_id"` + ThreadID string `json:"thread_id"` + ChatID string `json:"chat_id"` + MsgType string `json:"msg_type"` + CreateTime string `json:"create_time"` + UpdateTime string `json:"update_time"` + Deleted bool `json:"deleted"` + Updated bool `json:"updated"` + Sender IMSender `json:"sender"` + Mentions []IMMention `json:"mentions"` + Body IMBody `json:"body"` } // ReactionResponse . @@ -266,7 +268,7 @@ func (bot Bot) PostMessage(om OutcomingMessage) (*PostMessageResponse, error) { // ReplyMessage replies a message func (bot Bot) ReplyMessage(om OutcomingMessage) (*PostMessageResponse, error) { - req, err := BuildMessage(om) + req, err := buildReplyMessage(om) if err != nil { return nil, err } @@ -299,16 +301,22 @@ func (bot Bot) DeleteReaction(messageID string, reactionID string) (*ReactionRes // UpdateMessage updates a message func (bot Bot) UpdateMessage(messageID string, om OutcomingMessage) (*UpdateMessageResponse, error) { - if om.MsgType != MsgInteractive { + if om.MsgType != MsgInteractive && + om.MsgType != MsgText && + om.MsgType != MsgPost { return nil, ErrMessageType } - req, err := BuildMessage(om) + req, err := buildUpdateMessage(om) if err != nil { return nil, err } url := fmt.Sprintf(updateMessageURL, messageID) var respData UpdateMessageResponse - err = bot.PatchAPIRequest("UpdateMessage", url, true, req, &respData) + if om.MsgType == MsgInteractive { + err = bot.PatchAPIRequest("UpdateMessage", url, true, req, &respData) + } else { + err = bot.PutAPIRequest("UpdateMessage", url, true, req, &respData) + } return &respData, err } diff --git a/api_message_test.go b/api_message_test.go index a61fc0e..268df4c 100644 --- a/api_message_test.go +++ b/api_message_test.go @@ -59,7 +59,17 @@ func TestReplyMessage(t *testing.T) { assert.Equal(t, 0, resp.Code) assert.NotEmpty(t, resp.Data.MessageID) } - resp, err = bot.PostTextMentionAndReply("PostTextMentionAndReply", testUserOpenID, WithChatID(testGroupChatID), resp.Data.MessageID) + replyID := resp.Data.MessageID + resp, err = bot.PostTextMentionAndReply("PostTextMentionAndReply", testUserOpenID, WithChatID(testGroupChatID), replyID) + if assert.NoError(t, err) { + assert.Equal(t, 0, resp.Code) + assert.NotEmpty(t, resp.Data.MessageID) + } + // Reply with Outcoming Message + mb := NewMsgBuffer(MsgText) + tb := NewTextBuilder() + om := mb.Text(tb.Text("Reply raw").Render()).BindReply(replyID).ReplyInThread(true).Build() + resp, err = bot.ReplyMessage(om) if assert.NoError(t, err) { assert.Equal(t, 0, resp.Code) assert.NotEmpty(t, resp.Data.MessageID) @@ -210,6 +220,20 @@ func TestPostPostMessage(t *testing.T) { if assert.NoError(t, err) { assert.Equal(t, 0, resp.Code) assert.NotEmpty(t, resp.Data.MessageID) + + newOM := NewMsgBuffer(MsgPost). + BindOpenChatID(testGroupChatID). + Post( + NewPostBuilder(). + Title("modified title"). + TextTag("modified content", 1, true). + Render(), + ). + Build() + _, err = bot.UpdateMessage(resp.Data.MessageID, newOM) + if assert.NoError(t, err) { + assert.Equal(t, 0, resp.Code) + } } } @@ -446,7 +470,7 @@ func TestPinMessages(t *testing.T) { } } -func TestReactionMessage(t *testing.T) { +func TestMessageReactions(t *testing.T) { msg := NewMsgBuffer(MsgText) om := msg.BindEmail(testUserEmail).Text("hello, world").Build() resp, err := bot.PostMessage(om) diff --git a/message.go b/message.go index 2efe9af..53ce042 100644 --- a/message.go +++ b/message.go @@ -27,7 +27,8 @@ type OutcomingMessage struct { ChatID string `json:"chat_id,omitempty"` UnionID string `json:"-"` // For reply - RootID string `json:"root_id,omitempty"` + RootID string `json:"root_id,omitempty"` + ReplyInThread bool `json:"reply_in_thread,omitempty"` // Sign for notification bot Sign string `json:"sign"` // Timestamp for sign diff --git a/message_v2.go b/message_v2.go index 2adab12..c2f3ae6 100644 --- a/message_v2.go +++ b/message_v2.go @@ -23,6 +23,36 @@ func BuildMessage(om OutcomingMessage) (*IMMessageRequest, error) { return &req, nil } +func buildReplyMessage(om OutcomingMessage) (*IMMessageRequest, error) { + req := IMMessageRequest{ + MsgType: string(om.MsgType), + Content: buildContent(om), + ReceiveID: buildReceiveID(om), + } + if req.Content == "" { + return nil, ErrMessageNotBuild + } + if om.ReplyInThread == true { + req.ReplyInThread = om.ReplyInThread + } + + return &req, nil +} + +func buildUpdateMessage(om OutcomingMessage) (*IMMessageRequest, error) { + req := IMMessageRequest{ + Content: buildContent(om), + } + if om.MsgType != MsgInteractive { + req.MsgType = om.MsgType + } + if req.Content == "" { + return nil, ErrMessageNotBuild + } + + return &req, nil +} + func buildContent(om OutcomingMessage) string { var ( content = "" diff --git a/msg_buf.go b/msg_buf.go index a0b1cfd..4f5cb4e 100644 --- a/msg_buf.go +++ b/msg_buf.go @@ -76,6 +76,12 @@ func (m *MsgBuffer) BindReply(rootID string) *MsgBuffer { return m } +// ReplyInThread replies message in thread +func (m *MsgBuffer) ReplyInThread(replyInThread bool) *MsgBuffer { + m.message.ReplyInThread = replyInThread + return m +} + // WithSign generates sign for notification bot check func (m *MsgBuffer) WithSign(secret string, ts int64) *MsgBuffer { m.message.Sign, _ = GenSign(secret, ts) diff --git a/msg_buf_test.go b/msg_buf_test.go index 07ca30f..7d73c3b 100644 --- a/msg_buf_test.go +++ b/msg_buf_test.go @@ -41,6 +41,8 @@ func TestBindingUserIDs(t *testing.T) { mb.Clear() msgReplyID := mb.BindReply("om_f779ffe0ffa3d1b94fc1ef5fcb6f1063").Build() assert.Equal(t, "om_f779ffe0ffa3d1b94fc1ef5fcb6f1063", msgReplyID.RootID) + mb.ReplyInThread(true) + assert.False(t, msgReplyID.ReplyInThread) } func TestMsgShareChat(t *testing.T) {