Skip to content

Support Card v2 callback #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ r.POST("/", func(c *gin.Context) {
})
```

#### Card Callback
#### Card Callback v1

We may also setup callback for card actions (e.g. button). The URL challenge part is the same.

Expand All @@ -267,6 +267,24 @@ r.POST("/callback", func(c *gin.Context) {
})
```

#### Card Callback v2

Card Callback v2 content is same as Event v2. When handling card callback v2 requests, you can use the processing logic of Event 2.0.

```go
r.Use(middleware.LarkEventHandler())
r.Post("/callback", func(c *gin.Context)) {
if evt, ok := middleware.GetEvent(c); ok { // => GetEvent instead of GetMessage
if evt.Header.EventType == lark.EventTypeCardV2Callback {
if msg, err := evt.GetCardV2Callback(); err == nil { // note: use `GetCardV2Callback()` function to parse callback content
fmt.Println(msg)
}
// you may have to parse other events
}
}
}
```

#### Receiving Message (Event V1)

For older bots, please use v1:
Expand Down
20 changes: 19 additions & 1 deletion README_zhCN.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ r.POST("/", func(c *gin.Context) {
})
```

#### 卡片回调
#### 卡片回调v1

我们可以使用卡片回调接受卡片的用户操作(如:按钮点击),URL 挑战部分同步上。

Expand All @@ -259,6 +259,24 @@ r.POST("/callback", func(c *gin.Context) {
})
```

#### 卡片回调v2

卡片回调v2使用事件2.0的请求结构,在处理卡片回调请求时,可以使用事件2.0的处理逻辑。

```go
r.Use(middleware.LarkEventHandler())
r.Post("/callback", func(c *gin.Context)) {
if evt, ok := middleware.GetEvent(c); ok { // => GetEvent instead of GetMessage
if evt.Header.EventType == lark.EventTypeCardV2Callback {
if msg, err := evt.GetCardV2Callback(); err == nil { // 需要注意这里,使用`GetCardV2Callback()`函数解析回调内容
fmt.Println(msg)
}
// you may have to parse other events
}
}
}
```

#### 接收消息(事件 1.0)

对于较早常见的机器人,我们需要使用 v1 版本:
Expand Down
30 changes: 30 additions & 0 deletions event_cardcallback_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lark

type CardV2CallbackEvent struct {
Operator struct {
TenantKey string `json:"tenant_key,omitempty"`
UserID string `json:"user_id,omitempty"`
UnionID string `json:"union_id,omitempty"`
OpenID string `json:"open_id,omitempty"`
} `json:"operator,omitempty"`
Token string `json:"token,omitempty"`
Action struct {
Value interface{} `json:"value,omitempty"`
Tag string `json:"tag,omitempty"`
Timezone string `json:"timezone,omitempty"`
Name string `json:"name,omitempty"`
FormValue string `json:"form_value,omitempty"`
InputValue string `json:"input_value,omitempty"`
Option string `json:"option,omitempty"`
Options []string `json:"options,omitempty"`
Checked bool `json:"checked,omitempty"`
} `json:"action,omitempty"`
Host string `json:"host,omitempty"`
DeliveryType string `json:"delivery_type,omitempty"`
Context struct {
Url string `json:"url,omitempty"`
PreviewToken string `json:"preview_token,omitempty"`
OpenMessageID string `json:"open_message_id,omitempty"`
OpenChatID string `json:"open_chat_id,omitempty"`
} `json:"context,omitempty"`
}
6 changes: 6 additions & 0 deletions event_message_received.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ func (e EventV2) GetMessageReceived() (*EventV2MessageReceived, error) {
err := e.GetEvent(EventTypeMessageReceived, &body)
return &body, err
}

func (e EventV2) GetCardV2Callback() (*CardV2CallbackEvent, error) {
var body CardV2CallbackEvent
err := e.GetEvent(EventTypeCardV2Callback, &body)
return &body, err
}
1 change: 1 addition & 0 deletions event_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
EventTypeUserDeleted = "im.chat.member.user.deleted_v1"
EventTypeBotAdded = "im.chat.member.bot.added_v1"
EventTypeBotDeleted = "im.chat.member.bot.deleted_v1"
EventTypeCardV2Callback = "card.action.trigger"
// not supported yet
EventTypeChatUpdated = "im.chat.updated_v1"
EventTypeUserWithdrawn = "im.chat.member.user.withdrawn_v1"
Expand Down
26 changes: 26 additions & 0 deletions event_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,32 @@ func TestEventTypes(t *testing.T) {
m, e = event.GetMessageReceived()
assert.NoError(t, e)
assert.Equal(t, "p2p", m.Message.ChatType)

event = EventV2{
Header: EventV2Header{
EventType: EventTypeCardV2Callback,
},
EventRaw: json.RawMessage(`{"operator":{"tenant_key":"73658260f175d","user_id":"2a91f9","union_id":"on_fcc3539c08b49244f3f4d4106d2e","open_id":"ou_6bfe63b8001cb8a2cae0555b79ecd"},"token":"c-7f23aeca4f5cd726c2b70bfa616da2","action":{"value":"confirm","tag":"button","timezone":"","name":"","form_value":"","input_value":"","option":"","options":null,"checked":false},"host":"im_message","delivery_type":"","context":{"url":"","preview_token":"","open_message_id":"om_227c08473975fa87dfcb777e39322","open_chat_id":"oc_5d2f53edc7eadc731f4a984b171"}}`),
}
callbackReq, err := event.GetCardV2Callback()
assert.NoError(t, err)
val, ok := callbackReq.Action.Value.(string)
assert.Equal(t, true, ok)
assert.Equal(t, "confirm", val)

event = EventV2{
Header: EventV2Header{
EventType: EventTypeCardV2Callback,
},
EventRaw: json.RawMessage(`{"operator":{"tenant_key":"73658260f175d","user_id":"2a91f9","union_id":"on_fcc3539c08b49244f3f4d4106d2e","open_id":"ou_6bfe63b8001cb8a2cae0555b79ecd"},"token":"c-7f23aeca4f5cd726c2b70bfa616da2","action":{"value":{"confirm":"true"},"tag":"button","timezone":"","name":"","form_value":"","input_value":"","option":"","options":null,"checked":false},"host":"im_message","delivery_type":"","context":{"url":"","preview_token":"","open_message_id":"om_227c08473975fa87dfcb777e39322","open_chat_id":"oc_5d2f53edc7eadc731f4a984b171"}}`),
}
callbackReq, err = event.GetCardV2Callback()
assert.NoError(t, err)

valObj, ok := callbackReq.Action.Value.(map[string]interface{})
assert.Equal(t, true, ok)
assert.Equal(t, "true", valObj["confirm"])

}

func TestGetEvent(t *testing.T) {
Expand Down