2018-12-01 10:55:35 -08:00
|
|
|
package slack
|
|
|
|
|
2019-09-07 13:46:58 -07:00
|
|
|
import (
|
2019-12-07 13:54:36 -08:00
|
|
|
"bytes"
|
2019-09-07 13:46:58 -07:00
|
|
|
"encoding/json"
|
|
|
|
)
|
|
|
|
|
2018-12-01 10:55:35 -08:00
|
|
|
// InteractionType type of interactions
|
|
|
|
type InteractionType string
|
|
|
|
|
2019-09-07 13:46:58 -07:00
|
|
|
// ActionType type represents the type of action (attachment, block, etc.)
|
|
|
|
type actionType string
|
|
|
|
|
|
|
|
// action is an interface that should be implemented by all callback action types
|
|
|
|
type action interface {
|
|
|
|
actionType() actionType
|
|
|
|
}
|
|
|
|
|
2018-12-01 10:55:35 -08:00
|
|
|
// Types of interactions that can be received.
|
|
|
|
const (
|
2019-01-31 08:06:36 -08:00
|
|
|
InteractionTypeDialogCancellation = InteractionType("dialog_cancellation")
|
2018-12-01 10:55:35 -08:00
|
|
|
InteractionTypeDialogSubmission = InteractionType("dialog_submission")
|
|
|
|
InteractionTypeDialogSuggestion = InteractionType("dialog_suggestion")
|
|
|
|
InteractionTypeInteractionMessage = InteractionType("interactive_message")
|
|
|
|
InteractionTypeMessageAction = InteractionType("message_action")
|
2019-09-07 13:46:58 -07:00
|
|
|
InteractionTypeBlockActions = InteractionType("block_actions")
|
2018-12-01 10:55:35 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
// InteractionCallback is sent from slack when a user interactions with a button or dialog.
|
|
|
|
type InteractionCallback struct {
|
|
|
|
Type InteractionType `json:"type"`
|
|
|
|
Token string `json:"token"`
|
|
|
|
CallbackID string `json:"callback_id"`
|
|
|
|
ResponseURL string `json:"response_url"`
|
|
|
|
TriggerID string `json:"trigger_id"`
|
|
|
|
ActionTs string `json:"action_ts"`
|
|
|
|
Team Team `json:"team"`
|
|
|
|
Channel Channel `json:"channel"`
|
|
|
|
User User `json:"user"`
|
|
|
|
OriginalMessage Message `json:"original_message"`
|
|
|
|
Message Message `json:"message"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Value string `json:"value"`
|
2019-09-07 13:46:58 -07:00
|
|
|
MessageTs string `json:"message_ts"`
|
|
|
|
AttachmentID string `json:"attachment_id"`
|
|
|
|
ActionCallback ActionCallbacks `json:"actions"`
|
2020-03-01 11:59:19 -08:00
|
|
|
APIAppID string `json:"api_app_id"`
|
2018-12-01 10:55:35 -08:00
|
|
|
DialogSubmissionCallback
|
|
|
|
}
|
2019-09-07 13:46:58 -07:00
|
|
|
|
|
|
|
// ActionCallback is a convenience struct defined to allow dynamic unmarshalling of
|
|
|
|
// the "actions" value in Slack's JSON response, which varies depending on block type
|
|
|
|
type ActionCallbacks struct {
|
|
|
|
AttachmentActions []*AttachmentAction
|
|
|
|
BlockActions []*BlockAction
|
|
|
|
}
|
|
|
|
|
2019-12-07 13:54:36 -08:00
|
|
|
// MarshalJSON implements the Marshaller interface in order to combine both
|
|
|
|
// action callback types back into a single array, like how the api responds.
|
|
|
|
// This makes Marshaling and Unmarshaling an InteractionCallback symmetrical
|
|
|
|
func (a ActionCallbacks) MarshalJSON() ([]byte, error) {
|
|
|
|
count := 0
|
|
|
|
length := len(a.AttachmentActions) + len(a.BlockActions)
|
|
|
|
buffer := bytes.NewBufferString("[")
|
|
|
|
|
|
|
|
f := func(obj interface{}) error {
|
|
|
|
js, err := json.Marshal(obj)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = buffer.Write(js)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
count++
|
|
|
|
if count < length {
|
|
|
|
_, err = buffer.WriteString(",")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, act := range a.AttachmentActions {
|
|
|
|
err := f(act)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, blk := range a.BlockActions {
|
|
|
|
err := f(blk)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buffer.WriteString("]")
|
|
|
|
return buffer.Bytes(), nil
|
|
|
|
}
|
|
|
|
|
2019-09-07 13:46:58 -07:00
|
|
|
// UnmarshalJSON implements the Marshaller interface in order to delegate
|
|
|
|
// marshalling and allow for proper type assertion when decoding the response
|
|
|
|
func (a *ActionCallbacks) UnmarshalJSON(data []byte) error {
|
|
|
|
var raw []json.RawMessage
|
|
|
|
err := json.Unmarshal(data, &raw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range raw {
|
|
|
|
var obj map[string]interface{}
|
|
|
|
err := json.Unmarshal(r, &obj)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := obj["block_id"].(string); ok {
|
|
|
|
action, err := unmarshalAction(r, &BlockAction{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
a.BlockActions = append(a.BlockActions, action.(*BlockAction))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
action, err := unmarshalAction(r, &AttachmentAction{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
a.AttachmentActions = append(a.AttachmentActions, action.(*AttachmentAction))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unmarshalAction(r json.RawMessage, callbackAction action) (action, error) {
|
|
|
|
err := json.Unmarshal(r, callbackAction)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return callbackAction, nil
|
|
|
|
}
|