summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/nlopes/slack/chat.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/nlopes/slack/chat.go')
-rw-r--r--vendor/github.com/nlopes/slack/chat.go376
1 files changed, 376 insertions, 0 deletions
diff --git a/vendor/github.com/nlopes/slack/chat.go b/vendor/github.com/nlopes/slack/chat.go
new file mode 100644
index 00000000..0eb042df
--- /dev/null
+++ b/vendor/github.com/nlopes/slack/chat.go
@@ -0,0 +1,376 @@
+package slack
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "net/url"
+ "strings"
+)
+
+const (
+ DEFAULT_MESSAGE_USERNAME = ""
+ DEFAULT_MESSAGE_THREAD_TIMESTAMP = ""
+ DEFAULT_MESSAGE_REPLY_BROADCAST = false
+ DEFAULT_MESSAGE_ASUSER = false
+ DEFAULT_MESSAGE_PARSE = ""
+ DEFAULT_MESSAGE_LINK_NAMES = 0
+ DEFAULT_MESSAGE_UNFURL_LINKS = false
+ DEFAULT_MESSAGE_UNFURL_MEDIA = true
+ DEFAULT_MESSAGE_ICON_URL = ""
+ DEFAULT_MESSAGE_ICON_EMOJI = ""
+ DEFAULT_MESSAGE_MARKDOWN = true
+ DEFAULT_MESSAGE_ESCAPE_TEXT = true
+)
+
+type chatResponseFull struct {
+ Channel string `json:"channel"`
+ Timestamp string `json:"ts"`
+ Text string `json:"text"`
+ SlackResponse
+}
+
+// PostMessageParameters contains all the parameters necessary (including the optional ones) for a PostMessage() request
+type PostMessageParameters struct {
+ Text string `json:"text"`
+ Username string `json:"user_name"`
+ AsUser bool `json:"as_user"`
+ Parse string `json:"parse"`
+ ThreadTimestamp string `json:"thread_ts"`
+ ReplyBroadcast bool `json:"reply_broadcast"`
+ LinkNames int `json:"link_names"`
+ Attachments []Attachment `json:"attachments"`
+ UnfurlLinks bool `json:"unfurl_links"`
+ UnfurlMedia bool `json:"unfurl_media"`
+ IconURL string `json:"icon_url"`
+ IconEmoji string `json:"icon_emoji"`
+ Markdown bool `json:"mrkdwn,omitempty"`
+ EscapeText bool `json:"escape_text"`
+
+ // chat.postEphemeral support
+ Channel string `json:"channel"`
+ User string `json:"user"`
+}
+
+// NewPostMessageParameters provides an instance of PostMessageParameters with all the sane default values set
+func NewPostMessageParameters() PostMessageParameters {
+ return PostMessageParameters{
+ Username: DEFAULT_MESSAGE_USERNAME,
+ User: DEFAULT_MESSAGE_USERNAME,
+ AsUser: DEFAULT_MESSAGE_ASUSER,
+ Parse: DEFAULT_MESSAGE_PARSE,
+ LinkNames: DEFAULT_MESSAGE_LINK_NAMES,
+ Attachments: nil,
+ UnfurlLinks: DEFAULT_MESSAGE_UNFURL_LINKS,
+ UnfurlMedia: DEFAULT_MESSAGE_UNFURL_MEDIA,
+ IconURL: DEFAULT_MESSAGE_ICON_URL,
+ IconEmoji: DEFAULT_MESSAGE_ICON_EMOJI,
+ Markdown: DEFAULT_MESSAGE_MARKDOWN,
+ EscapeText: DEFAULT_MESSAGE_ESCAPE_TEXT,
+ }
+}
+
+// DeleteMessage deletes a message in a channel
+func (api *Client) DeleteMessage(channel, messageTimestamp string) (string, string, error) {
+ respChannel, respTimestamp, _, err := api.SendMessageContext(context.Background(), channel, MsgOptionDelete(messageTimestamp))
+ return respChannel, respTimestamp, err
+}
+
+// DeleteMessageContext deletes a message in a channel with a custom context
+func (api *Client) DeleteMessageContext(ctx context.Context, channel, messageTimestamp string) (string, string, error) {
+ respChannel, respTimestamp, _, err := api.SendMessageContext(ctx, channel, MsgOptionDelete(messageTimestamp))
+ return respChannel, respTimestamp, err
+}
+
+// PostMessage sends a message to a channel.
+// Message is escaped by default according to https://api.slack.com/docs/formatting
+// Use http://davestevens.github.io/slack-message-builder/ to help crafting your message.
+func (api *Client) PostMessage(channel, text string, params PostMessageParameters) (string, string, error) {
+ respChannel, respTimestamp, _, err := api.SendMessageContext(
+ context.Background(),
+ channel,
+ MsgOptionText(text, params.EscapeText),
+ MsgOptionAttachments(params.Attachments...),
+ MsgOptionPostMessageParameters(params),
+ )
+ return respChannel, respTimestamp, err
+}
+
+// PostMessageContext sends a message to a channel with a custom context
+// For more details, see PostMessage documentation
+func (api *Client) PostMessageContext(ctx context.Context, channel, text string, params PostMessageParameters) (string, string, error) {
+ respChannel, respTimestamp, _, err := api.SendMessageContext(
+ ctx,
+ channel,
+ MsgOptionText(text, params.EscapeText),
+ MsgOptionAttachments(params.Attachments...),
+ MsgOptionPostMessageParameters(params),
+ )
+ return respChannel, respTimestamp, err
+}
+
+// PostEphemeral sends an ephemeral message to a user in a channel.
+// Message is escaped by default according to https://api.slack.com/docs/formatting
+// Use http://davestevens.github.io/slack-message-builder/ to help crafting your message.
+func (api *Client) PostEphemeral(channel, userID string, options ...MsgOption) (string, error) {
+ options = append(options, MsgOptionPostEphemeral())
+ return api.PostEphemeralContext(
+ context.Background(),
+ channel,
+ userID,
+ options...,
+ )
+}
+
+// PostEphemeralContext sends an ephemeal message to a user in a channel with a custom context
+// For more details, see PostEphemeral documentation
+func (api *Client) PostEphemeralContext(ctx context.Context, channel, userID string, options ...MsgOption) (string, error) {
+ path, values, err := ApplyMsgOptions(api.config.token, channel, options...)
+ if err != nil {
+ return "", err
+ }
+
+ values.Add("user", userID)
+
+ response, err := chatRequest(ctx, path, values, api.debug)
+ if err != nil {
+ return "", err
+ }
+
+ return response.Timestamp, nil
+}
+
+// UpdateMessage updates a message in a channel
+func (api *Client) UpdateMessage(channel, timestamp, text string) (string, string, string, error) {
+ return api.UpdateMessageContext(context.Background(), channel, timestamp, text)
+}
+
+// UpdateMessage updates a message in a channel
+func (api *Client) UpdateMessageContext(ctx context.Context, channel, timestamp, text string) (string, string, string, error) {
+ return api.SendMessageContext(ctx, channel, MsgOptionUpdate(timestamp), MsgOptionText(text, true))
+}
+
+// SendMessage more flexible method for configuring messages.
+func (api *Client) SendMessage(channel string, options ...MsgOption) (string, string, string, error) {
+ return api.SendMessageContext(context.Background(), channel, options...)
+}
+
+// SendMessageContext more flexible method for configuring messages with a custom context.
+func (api *Client) SendMessageContext(ctx context.Context, channel string, options ...MsgOption) (string, string, string, error) {
+ channel, values, err := ApplyMsgOptions(api.config.token, channel, options...)
+ if err != nil {
+ return "", "", "", err
+ }
+
+ response, err := chatRequest(ctx, channel, values, api.debug)
+ if err != nil {
+ return "", "", "", err
+ }
+
+ return response.Channel, response.Timestamp, response.Text, nil
+}
+
+// ApplyMsgOptions utility function for debugging/testing chat requests.
+func ApplyMsgOptions(token, channel string, options ...MsgOption) (string, url.Values, error) {
+ config := sendConfig{
+ mode: chatPostMessage,
+ values: url.Values{
+ "token": {token},
+ "channel": {channel},
+ },
+ }
+
+ for _, opt := range options {
+ if err := opt(&config); err != nil {
+ return string(config.mode), config.values, err
+ }
+ }
+
+ return string(config.mode), config.values, nil
+}
+
+func escapeMessage(message string) string {
+ replacer := strings.NewReplacer("&", "&amp;", "<", "&lt;", ">", "&gt;")
+ return replacer.Replace(message)
+}
+
+func chatRequest(ctx context.Context, path string, values url.Values, debug bool) (*chatResponseFull, error) {
+ response := &chatResponseFull{}
+ err := post(ctx, path, values, response, debug)
+ if err != nil {
+ return nil, err
+ }
+ if !response.Ok {
+ return nil, errors.New(response.Error)
+ }
+ return response, nil
+}
+
+type sendMode string
+
+const (
+ chatUpdate sendMode = "chat.update"
+ chatPostMessage sendMode = "chat.postMessage"
+ chatDelete sendMode = "chat.delete"
+ chatPostEphemeral sendMode = "chat.postEphemeral"
+)
+
+type sendConfig struct {
+ mode sendMode
+ values url.Values
+}
+
+// MsgOption option provided when sending a message.
+type MsgOption func(*sendConfig) error
+
+// MsgOptionPost posts a messages, this is the default.
+func MsgOptionPost() MsgOption {
+ return func(config *sendConfig) error {
+ config.mode = chatPostMessage
+ config.values.Del("ts")
+ return nil
+ }
+}
+
+// MsgOptionPostEphemeral posts an ephemeral message
+func MsgOptionPostEphemeral() MsgOption {
+ return func(config *sendConfig) error {
+ config.mode = chatPostEphemeral
+ config.values.Del("ts")
+ return nil
+ }
+}
+
+// MsgOptionUpdate updates a message based on the timestamp.
+func MsgOptionUpdate(timestamp string) MsgOption {
+ return func(config *sendConfig) error {
+ config.mode = chatUpdate
+ config.values.Add("ts", timestamp)
+ return nil
+ }
+}
+
+// MsgOptionDelete deletes a message based on the timestamp.
+func MsgOptionDelete(timestamp string) MsgOption {
+ return func(config *sendConfig) error {
+ config.mode = chatDelete
+ config.values.Add("ts", timestamp)
+ return nil
+ }
+}
+
+// MsgOptionAsUser whether or not to send the message as the user.
+func MsgOptionAsUser(b bool) MsgOption {
+ return func(config *sendConfig) error {
+ if b != DEFAULT_MESSAGE_ASUSER {
+ config.values.Set("as_user", "true")
+ }
+ return nil
+ }
+}
+
+// MsgOptionText provide the text for the message, optionally escape the provided
+// text.
+func MsgOptionText(text string, escape bool) MsgOption {
+ return func(config *sendConfig) error {
+ if escape {
+ text = escapeMessage(text)
+ }
+ config.values.Add("text", text)
+ return nil
+ }
+}
+
+// MsgOptionAttachments provide attachments for the message.
+func MsgOptionAttachments(attachments ...Attachment) MsgOption {
+ return func(config *sendConfig) error {
+ if attachments == nil {
+ return nil
+ }
+
+ attachments, err := json.Marshal(attachments)
+ if err == nil {
+ config.values.Set("attachments", string(attachments))
+ }
+ return err
+ }
+}
+
+// MsgOptionEnableLinkUnfurl enables link unfurling
+func MsgOptionEnableLinkUnfurl() MsgOption {
+ return func(config *sendConfig) error {
+ config.values.Set("unfurl_links", "true")
+ return nil
+ }
+}
+
+// MsgOptionDisableMediaUnfurl disables media unfurling.
+func MsgOptionDisableMediaUnfurl() MsgOption {
+ return func(config *sendConfig) error {
+ config.values.Set("unfurl_media", "false")
+ return nil
+ }
+}
+
+// MsgOptionDisableMarkdown disables markdown.
+func MsgOptionDisableMarkdown() MsgOption {
+ return func(config *sendConfig) error {
+ config.values.Set("mrkdwn", "false")
+ return nil
+ }
+}
+
+// MsgOptionPostMessageParameters maintain backwards compatibility.
+func MsgOptionPostMessageParameters(params PostMessageParameters) MsgOption {
+ return func(config *sendConfig) error {
+ if params.Username != DEFAULT_MESSAGE_USERNAME {
+ config.values.Set("username", string(params.Username))
+ }
+
+ // chat.postEphemeral support
+ if params.User != DEFAULT_MESSAGE_USERNAME {
+ config.values.Set("user", params.User)
+ }
+
+ // never generates an error.
+ MsgOptionAsUser(params.AsUser)(config)
+
+ if params.Parse != DEFAULT_MESSAGE_PARSE {
+ config.values.Set("parse", string(params.Parse))
+ }
+ if params.LinkNames != DEFAULT_MESSAGE_LINK_NAMES {
+ config.values.Set("link_names", "1")
+ }
+
+ if params.UnfurlLinks != DEFAULT_MESSAGE_UNFURL_LINKS {
+ config.values.Set("unfurl_links", "true")
+ }
+
+ // I want to send a message with explicit `as_user` `true` and `unfurl_links` `false` in request.
+ // Because setting `as_user` to `true` will change the default value for `unfurl_links` to `true` on Slack API side.
+ if params.AsUser != DEFAULT_MESSAGE_ASUSER && params.UnfurlLinks == DEFAULT_MESSAGE_UNFURL_LINKS {
+ config.values.Set("unfurl_links", "false")
+ }
+ if params.UnfurlMedia != DEFAULT_MESSAGE_UNFURL_MEDIA {
+ config.values.Set("unfurl_media", "false")
+ }
+ if params.IconURL != DEFAULT_MESSAGE_ICON_URL {
+ config.values.Set("icon_url", params.IconURL)
+ }
+ if params.IconEmoji != DEFAULT_MESSAGE_ICON_EMOJI {
+ config.values.Set("icon_emoji", params.IconEmoji)
+ }
+ if params.Markdown != DEFAULT_MESSAGE_MARKDOWN {
+ config.values.Set("mrkdwn", "false")
+ }
+
+ if params.ThreadTimestamp != DEFAULT_MESSAGE_THREAD_TIMESTAMP {
+ config.values.Set("thread_ts", params.ThreadTimestamp)
+ }
+ if params.ReplyBroadcast != DEFAULT_MESSAGE_REPLY_BROADCAST {
+ config.values.Set("reply_broadcast", "true")
+ }
+
+ return nil
+ }
+}