commit
7f8f188ded
81
v1/client.go
81
v1/client.go
@ -586,6 +586,87 @@ func (c *MgClient) MessagesHistory(request SendHistoryMessageRequest) (MessagesR
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
// AddMessageReaction adds reactions to the message.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// client := New("https://message-gateway.url", "cb8ccf05e38a47543ad8477d4999be73bff503ea6")
|
||||
//
|
||||
// _, status, err := client.AddMessageReaction(ReactionRequest{
|
||||
// ChannelID: 305,
|
||||
// Message: ReactionMessageReference{
|
||||
// ExternalID: "uid_1",
|
||||
// },
|
||||
// Reaction: "😁",
|
||||
// })
|
||||
// if err != nil {
|
||||
// log.Fatalf("request error: %s (%d)", err, status)
|
||||
// }
|
||||
//
|
||||
// log.Printf("status: %d", status)
|
||||
func (c *MgClient) AddMessageReaction(request ReactionRequest) (MessageReactionResponse, int, error) {
|
||||
var (
|
||||
resp MessageReactionResponse
|
||||
outgoing = &bytes.Buffer{}
|
||||
)
|
||||
_ = json.NewEncoder(outgoing).Encode(request)
|
||||
|
||||
data, status, err := c.PostRequest("/messages/reaction", outgoing)
|
||||
if err != nil {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
if e := json.Unmarshal(data, &resp); e != nil {
|
||||
return resp, status, e
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
return resp, status, NewAPIClientError(data)
|
||||
}
|
||||
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
// DeleteMessagesReaction removes reactions to the message.
|
||||
// The reaction field is optional. If it is passed, the specific reaction will be deleted.
|
||||
// If it is not passed - the first found reaction from the user to the message will be deleted.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// client := New("https://message-gateway.url", "cb8ccf05e38a47543ad8477d4999be73bff503ea6")
|
||||
//
|
||||
// _, status, err := client.DeleteMessagesReaction(ReactionRequest{
|
||||
// ChannelID: 305,
|
||||
// Message: ReactionMessageReference{
|
||||
// ExternalID: "uid_1",
|
||||
// },
|
||||
// Reaction: "😁",
|
||||
// })
|
||||
// if err != nil {
|
||||
// log.Fatalf("request error: %s (%d)", err, status)
|
||||
// }
|
||||
//
|
||||
// log.Printf("status: %d", status)
|
||||
func (c *MgClient) DeleteMessagesReaction(request ReactionRequest) (MessageReactionResponse, int, error) {
|
||||
var resp MessageReactionResponse
|
||||
outgoing, _ := json.Marshal(&request)
|
||||
|
||||
data, status, err := c.DeleteRequest("/messages/reaction", outgoing)
|
||||
if err != nil {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
if e := json.Unmarshal(data, &resp); e != nil {
|
||||
return resp, status, e
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
return resp, status, NewAPIClientError(data)
|
||||
}
|
||||
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
// UpdateMessages edits existing message. Only text messages are supported.
|
||||
//
|
||||
// Example:
|
||||
|
@ -83,14 +83,17 @@ func (t *MGClientTest) Test_TransportChannels() {
|
||||
Quoting: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureReceive,
|
||||
MaxCharsCount: 4096,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Product: Product{
|
||||
Creating: ChannelFeatureReceive,
|
||||
Editing: ChannelFeatureReceive,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Order: Order{
|
||||
Creating: ChannelFeatureReceive,
|
||||
Editing: ChannelFeatureReceive,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
File: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
@ -98,6 +101,7 @@ func (t *MGClientTest) Test_TransportChannels() {
|
||||
Quoting: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureReceive,
|
||||
Max: 1,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Image: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
@ -105,6 +109,7 @@ func (t *MGClientTest) Test_TransportChannels() {
|
||||
Quoting: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureReceive,
|
||||
Max: 1, // nolint:gomnd
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Suggestions: ChannelSettingsSuggestions{
|
||||
Text: ChannelFeatureBoth,
|
||||
@ -115,6 +120,10 @@ func (t *MGClientTest) Test_TransportChannels() {
|
||||
SendingPolicy: SendingPolicy{
|
||||
NewCustomer: ChannelFeatureSendingPolicyTemplate,
|
||||
},
|
||||
Reactions: Reactions{
|
||||
Dictionary: []string{"👏", "😁", "🤔"},
|
||||
MaxCount: 3,
|
||||
},
|
||||
},
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: &createdAt,
|
||||
@ -149,20 +158,29 @@ func (t *MGClientTest) Test_ActivateTransportChannel() {
|
||||
Quoting: ChannelFeatureReceive,
|
||||
Deleting: ChannelFeatureBoth,
|
||||
MaxCharsCount: 2000,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Product: Product{
|
||||
Creating: ChannelFeatureSend,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Order: Order{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Image: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
File: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Reactions: Reactions{
|
||||
Dictionary: []string{"👏", "😁", "🤔"},
|
||||
MaxCount: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -203,20 +221,29 @@ func (t *MGClientTest) Test_ActivateNewTransportChannel() {
|
||||
Editing: ChannelFeatureSend,
|
||||
Quoting: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Product: Product{
|
||||
Creating: ChannelFeatureSend,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Order: Order{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Image: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
File: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Reactions: Reactions{
|
||||
Dictionary: []string{"👏", "😁", "🤔"},
|
||||
MaxCount: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -274,20 +301,29 @@ func (t *MGClientTest) Test_UpdateTransportChannel() {
|
||||
Editing: ChannelFeatureBoth,
|
||||
Quoting: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Product: Product{
|
||||
Creating: ChannelFeatureSend,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Order: Order{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Deleting: ChannelFeatureSend,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Image: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
File: ChannelSettingsFilesBase{
|
||||
Creating: ChannelFeatureBoth,
|
||||
Reaction: ChannelFeatureAny,
|
||||
},
|
||||
Reactions: Reactions{
|
||||
Dictionary: []string{"👏", "😁", "🤔"},
|
||||
MaxCount: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -850,6 +886,52 @@ func (t *MGClientTest) Test_MessagesHistory() {
|
||||
t.Assert().Equal(1, data.MessageID)
|
||||
}
|
||||
|
||||
func (t *MGClientTest) Test_AddMessageReaction() {
|
||||
c := t.client()
|
||||
|
||||
snd := ReactionRequest{
|
||||
ChannelID: 1,
|
||||
Message: ReactionMessageReference{
|
||||
ExternalID: "external_1",
|
||||
},
|
||||
Reaction: "😁",
|
||||
}
|
||||
|
||||
defer gock.Off()
|
||||
t.gock().
|
||||
Post(t.transportURL("messages/reaction")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(MessageReactionResponse{})
|
||||
|
||||
_, status, err := c.AddMessageReaction(snd)
|
||||
t.Require().NoError(err)
|
||||
t.Assert().Equal(http.StatusOK, status)
|
||||
t.Assert().Empty(gock.GetUnmatchedRequests())
|
||||
}
|
||||
|
||||
func (t *MGClientTest) Test_DeleteMessagesReaction() {
|
||||
c := t.client()
|
||||
|
||||
snd := ReactionRequest{
|
||||
ChannelID: 1,
|
||||
Message: ReactionMessageReference{
|
||||
ExternalID: "external_1",
|
||||
},
|
||||
Reaction: "😁",
|
||||
}
|
||||
|
||||
defer gock.Off()
|
||||
t.gock().
|
||||
Delete(t.transportURL("messages/reaction")).
|
||||
Reply(http.StatusOK).
|
||||
JSON(MessageReactionResponse{})
|
||||
|
||||
_, status, err := c.DeleteMessagesReaction(snd)
|
||||
t.Require().NoError(err)
|
||||
t.Assert().Equal(http.StatusOK, status)
|
||||
t.Assert().Empty(gock.GetUnmatchedRequests())
|
||||
}
|
||||
|
||||
func (t *MGClientTest) Test_MarkMessageReadAndDelete() {
|
||||
c := t.client()
|
||||
|
||||
|
37
v1/types.go
37
v1/types.go
@ -104,6 +104,7 @@ type ChannelSettings struct {
|
||||
Order Order `json:"order"`
|
||||
File ChannelSettingsFilesBase `json:"file"`
|
||||
Image ChannelSettingsFilesBase `json:"image"`
|
||||
Reactions Reactions `json:"reactions"`
|
||||
CustomerExternalID string `json:"customer_external_id,omitempty"`
|
||||
SendingPolicy SendingPolicy `json:"sending_policy,omitempty"`
|
||||
Suggestions ChannelSettingsSuggestions `json:"suggestions,omitempty"`
|
||||
@ -117,6 +118,12 @@ type Product struct {
|
||||
Creating string `json:"creating,omitempty"`
|
||||
Editing string `json:"editing,omitempty"`
|
||||
Deleting string `json:"deleting,omitempty"`
|
||||
Reaction string `json:"reaction,omitempty"`
|
||||
}
|
||||
|
||||
type Reactions struct {
|
||||
Dictionary []string `json:"dictionary,omitempty"`
|
||||
MaxCount uint16 `json:"max_count,omitempty"`
|
||||
}
|
||||
|
||||
// Order type.
|
||||
@ -124,6 +131,7 @@ type Order struct {
|
||||
Creating string `json:"creating,omitempty"`
|
||||
Editing string `json:"editing,omitempty"`
|
||||
Deleting string `json:"deleting,omitempty"`
|
||||
Reaction string `json:"reaction,omitempty"`
|
||||
}
|
||||
|
||||
// Status struct.
|
||||
@ -138,6 +146,7 @@ type ChannelSettingsText struct {
|
||||
Editing string `json:"editing,omitempty"`
|
||||
Quoting string `json:"quoting,omitempty"`
|
||||
Deleting string `json:"deleting,omitempty"`
|
||||
Reaction string `json:"reaction,omitempty"`
|
||||
MaxCharsCount uint16 `json:"max_chars_count,omitempty"`
|
||||
}
|
||||
|
||||
@ -147,6 +156,7 @@ type ChannelSettingsFilesBase struct {
|
||||
Editing string `json:"editing,omitempty"`
|
||||
Quoting string `json:"quoting,omitempty"`
|
||||
Deleting string `json:"deleting,omitempty"`
|
||||
Reaction string `json:"reaction,omitempty"`
|
||||
Max uint64 `json:"max_items_count,omitempty"`
|
||||
NoteMaxCharsCount *uint16 `json:"note_max_chars_count,omitempty"`
|
||||
MaxItemSize *uint64 `json:"max_item_size,omitempty"`
|
||||
@ -157,6 +167,7 @@ type ChannelSettingsAudio struct {
|
||||
Creating string `json:"creating,omitempty"`
|
||||
Quoting string `json:"quoting,omitempty"`
|
||||
Deleting string `json:"deleting,omitempty"`
|
||||
Reaction string `json:"reaction,omitempty"`
|
||||
MaxItemsCount uint64 `json:"max_items_count,omitempty"`
|
||||
MaxItemSize *uint64 `json:"max_item_size,omitempty"`
|
||||
}
|
||||
@ -346,6 +357,16 @@ type SendHistoryMessageRequest struct {
|
||||
ReplyDeadline *time.Time `json:"reply_deadline,omitempty"`
|
||||
}
|
||||
|
||||
type ReactionRequest struct {
|
||||
ChannelID uint64 `json:"channel_id"`
|
||||
Message ReactionMessageReference `json:"message"`
|
||||
Reaction string `json:"reaction,omitempty"`
|
||||
}
|
||||
|
||||
type ReactionMessageReference struct {
|
||||
ExternalID string `json:"external_id"`
|
||||
}
|
||||
|
||||
type SendMessageRequestMessage struct {
|
||||
Type string `json:"type"`
|
||||
ExternalID string `json:"external_id,omitempty"`
|
||||
@ -382,6 +403,8 @@ type SendMessageRequestQuote struct {
|
||||
// MarkMessageReadResponse type.
|
||||
type MarkMessageReadResponse struct{}
|
||||
|
||||
type MessageReactionResponse struct{}
|
||||
|
||||
// MarkMessageReadRequest type.
|
||||
type MarkMessageReadRequest struct {
|
||||
Message MarkMessageReadRequestMessage `json:"message"`
|
||||
@ -462,6 +485,20 @@ type MessageWebhookData struct {
|
||||
InAppID int32 `json:"in_app_id,omitempty"`
|
||||
}
|
||||
|
||||
type ReactionWebhookData struct {
|
||||
ExternalUserID string `json:"external_user_id"`
|
||||
ExternalChatID string `json:"external_chat_id"`
|
||||
ChannelID uint64 `json:"channel_id"`
|
||||
ExternalMessageID string `json:"external_message_id"`
|
||||
NewReaction string `json:"new_reaction,omitempty"`
|
||||
OldReaction string `json:"old_reaction,omitempty"`
|
||||
AllReactions []ReactionInfo `json:"all_reactions,omitempty"`
|
||||
}
|
||||
|
||||
type ReactionInfo struct {
|
||||
Reaction string `json:"reaction"`
|
||||
}
|
||||
|
||||
type Attachments struct {
|
||||
Suggestions []Suggestion `json:"suggestions,omitempty"`
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ const (
|
||||
MessageUpdateWebhookType WebhookType = "message_updated"
|
||||
MessageDeleteWebhookType WebhookType = "message_deleted"
|
||||
MessageReadWebhookType WebhookType = "message_read"
|
||||
ReactionAddWebhookType WebhookType = "reaction_add"
|
||||
ReactionDeleteWebhookType WebhookType = "reaction_delete"
|
||||
TemplateCreateWebhookType WebhookType = "template_create"
|
||||
TemplateUpdateWebhookType WebhookType = "template_update"
|
||||
TemplateDeleteWebhookType WebhookType = "template_delete"
|
||||
@ -27,6 +29,11 @@ func (w WebhookRequest) IsMessageWebhook() bool {
|
||||
w.Type == MessageSendWebhookType || w.Type == MessageUpdateWebhookType
|
||||
}
|
||||
|
||||
// IsReactionWebhook returns true if current webhook contains data related to chat reactions.
|
||||
func (w WebhookRequest) IsReactionWebhook() bool {
|
||||
return w.Type == ReactionAddWebhookType || w.Type == ReactionDeleteWebhookType
|
||||
}
|
||||
|
||||
// IsTemplateWebhook returns true if current webhook contains data related to the templates changes.
|
||||
func (w WebhookRequest) IsTemplateWebhook() bool {
|
||||
return w.Type == TemplateCreateWebhookType ||
|
||||
@ -43,6 +50,15 @@ func (w WebhookRequest) MessageWebhookData() (wd MessageWebhookData) {
|
||||
return
|
||||
}
|
||||
|
||||
// ReactionWebhookData returns the reaction data from webhook contents.
|
||||
//
|
||||
// Note: this call will not fail even if underlying data is not related to the reactions.
|
||||
// Use IsReactionWebhook to mitigate this.
|
||||
func (w WebhookRequest) ReactionWebhookData() (wd ReactionWebhookData) {
|
||||
_ = json.Unmarshal(w.Data, &wd)
|
||||
return
|
||||
}
|
||||
|
||||
// TemplateCreateWebhookData returns new template data from webhook contents.
|
||||
// This method is used if current webhook was initiated because user created a template.
|
||||
//
|
||||
|
@ -15,6 +15,12 @@ func TestWebhookRequest_IsMessageWebhook(t *testing.T) {
|
||||
assert.False(t, WebhookRequest{}.IsMessageWebhook())
|
||||
}
|
||||
|
||||
func TestWebhookRequest_IsReactionWebhook(t *testing.T) {
|
||||
assert.True(t, WebhookRequest{Type: ReactionAddWebhookType}.IsReactionWebhook())
|
||||
assert.True(t, WebhookRequest{Type: ReactionDeleteWebhookType}.IsReactionWebhook())
|
||||
assert.False(t, WebhookRequest{}.IsReactionWebhook())
|
||||
}
|
||||
|
||||
func TestWebhookRequest_IsTemplateWebhook(t *testing.T) {
|
||||
assert.True(t, WebhookRequest{Type: TemplateCreateWebhookType}.IsTemplateWebhook())
|
||||
assert.True(t, WebhookRequest{Type: TemplateUpdateWebhookType}.IsTemplateWebhook())
|
||||
@ -37,6 +43,32 @@ func TestWebhookData_MessageWebhookData(t *testing.T) {
|
||||
assert.Equal(t, "test", wh.Content)
|
||||
}
|
||||
|
||||
func TestWebhookData_ReactionWebhookData(t *testing.T) {
|
||||
wh := WebhookRequest{
|
||||
Type: ReactionAddWebhookType,
|
||||
Data: mustMarshalJSON(ReactionWebhookData{
|
||||
ExternalUserID: "1",
|
||||
ExternalChatID: "1",
|
||||
ChannelID: 1,
|
||||
ExternalMessageID: "1",
|
||||
NewReaction: "👍",
|
||||
OldReaction: "🤔",
|
||||
AllReactions: []ReactionInfo{
|
||||
{
|
||||
Reaction: "👏",
|
||||
},
|
||||
{
|
||||
Reaction: "😱",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}.ReactionWebhookData()
|
||||
assert.Equal(t, "👍", wh.NewReaction)
|
||||
assert.Equal(t, "🤔", wh.OldReaction)
|
||||
assert.Equal(t, "👏", wh.AllReactions[0].Reaction)
|
||||
assert.Equal(t, "😱", wh.AllReactions[1].Reaction)
|
||||
}
|
||||
|
||||
func TestWebhookData_TemplateCreateWebhookData(t *testing.T) {
|
||||
wh := WebhookRequest{
|
||||
Type: TemplateCreateWebhookType,
|
||||
|
Loading…
x
Reference in New Issue
Block a user