diff options
Diffstat (limited to 'vendor/github.com/nlopes/slack')
-rw-r--r-- | vendor/github.com/nlopes/slack/CHANGELOG.md | 12 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/Gopkg.lock | 8 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/Gopkg.toml | 17 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/chat.go | 50 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/conversation.go | 44 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/dialog.go | 104 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/dialog_select.go | 125 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/dialog_text.go | 50 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/files.go | 20 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/security.go | 47 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/slackutilsx/slackutilsx.go | 57 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/usergroups.go | 53 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/webhooks.go | 11 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/websocket_managed_conn.go | 5 | ||||
-rw-r--r-- | vendor/github.com/nlopes/slack/websocket_subteam.go | 35 |
15 files changed, 554 insertions, 84 deletions
diff --git a/vendor/github.com/nlopes/slack/CHANGELOG.md b/vendor/github.com/nlopes/slack/CHANGELOG.md index a79ea50c..cf0fc2cc 100644 --- a/vendor/github.com/nlopes/slack/CHANGELOG.md +++ b/vendor/github.com/nlopes/slack/CHANGELOG.md @@ -1,3 +1,15 @@ +### v0.4.0 - October 06, 2018
+full differences can be viewed using `git log --oneline --decorate --color v0.3.0..v0.4.0`
+- Breaking Change: renamed ApplyMessageOption, to mark it as unsafe,
+this means it may break without warning in the future.
+- Breaking: Msg structure files field changed to an array.
+- General: implementation for new security headers.
+- RTM: deadlock fix between connect/disconnect.
+- Events: various new fields added.
+- Web: various fixes, new fields exposed, new methods added.
+- Interactions: minor additions expect breaking changes in next release for dialogs/button clicks.
+- Utils: new methods added.
+
### v0.3.0 - July 30, 2018
full differences can be viewed using `git log --oneline --decorate --color v0.2.0..v0.3.0`
- slack events initial support added. (still considered experimental and undergoing changes, stability not promised)
diff --git a/vendor/github.com/nlopes/slack/Gopkg.lock b/vendor/github.com/nlopes/slack/Gopkg.lock index 5cc0520e..9c33d0dc 100644 --- a/vendor/github.com/nlopes/slack/Gopkg.lock +++ b/vendor/github.com/nlopes/slack/Gopkg.lock @@ -14,6 +14,12 @@ version = "v1.2.0" [[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] name = "github.com/pmezard/go-difflib" packages = ["difflib"] revision = "792786c7400a136282c1664665ae0a8db921c6c2" @@ -28,6 +34,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "888307bf47ee004aaaa4c45e6139929b4984f2253e48e382246bfb8c66f3cd65" + inputs-digest = "596fa546322c2a1e9708a10c9f39aca2e04792b477fab86fb2899fbaab776070" solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/github.com/nlopes/slack/Gopkg.toml b/vendor/github.com/nlopes/slack/Gopkg.toml new file mode 100644 index 00000000..257870d6 --- /dev/null +++ b/vendor/github.com/nlopes/slack/Gopkg.toml @@ -0,0 +1,17 @@ +ignored = ["github.com/lusis/slack-test"] + +[[constraint]] + name = "github.com/gorilla/websocket" + version = "1.2.0" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.1" + +[[constraint]] + name = "github.com/pkg/errors" + version = "0.8.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/nlopes/slack/chat.go b/vendor/github.com/nlopes/slack/chat.go index 2b89a44c..8cc6bdef 100644 --- a/vendor/github.com/nlopes/slack/chat.go +++ b/vendor/github.com/nlopes/slack/chat.go @@ -4,7 +4,8 @@ import ( "context" "encoding/json" "net/url" - "strings" + + "github.com/nlopes/slack/slackutilsx" ) const ( @@ -164,22 +165,24 @@ func (api *Client) SendMessageContext(ctx context.Context, channelID string, opt return "", "", "", err } - if err = postSlackMethod(ctx, api.httpclient, string(config.mode), config.values, &response, api.debug); err != nil { + if err = postForm(ctx, api.httpclient, config.endpoint, config.values, &response, api.debug); err != nil { return "", "", "", err } return response.Channel, response.getMessageTimestamp(), response.Text, response.Err() } -// ApplyMsgOptions utility function for debugging/testing chat requests. -func ApplyMsgOptions(token, channel string, options ...MsgOption) (string, url.Values, error) { +// UnsafeApplyMsgOptions utility function for debugging/testing chat requests. +// NOTE: USE AT YOUR OWN RISK: No issues relating to the use of this function +// will be supported by the library. +func UnsafeApplyMsgOptions(token, channel string, options ...MsgOption) (string, url.Values, error) { config, err := applyMsgOptions(token, channel, options...) - return string(config.mode), config.values, err + return config.endpoint, config.values, err } func applyMsgOptions(token, channel string, options ...MsgOption) (sendConfig, error) { config := sendConfig{ - mode: chatPostMessage, + endpoint: SLACK_API + string(chatPostMessage), values: url.Values{ "token": {token}, "channel": {channel}, @@ -195,11 +198,6 @@ func applyMsgOptions(token, channel string, options ...MsgOption) (sendConfig, e return config, nil } -func escapeMessage(message string) string { - replacer := strings.NewReplacer("&", "&", "<", "<", ">", ">") - return replacer.Replace(message) -} - type sendMode string const ( @@ -211,8 +209,8 @@ const ( ) type sendConfig struct { - mode sendMode - values url.Values + endpoint string + values url.Values } // MsgOption option provided when sending a message. @@ -221,7 +219,7 @@ 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.endpoint = SLACK_API + string(chatPostMessage) config.values.Del("ts") return nil } @@ -231,7 +229,7 @@ func MsgOptionPost() MsgOption { // posts an ephemeral message. func MsgOptionPostEphemeral() MsgOption { return func(config *sendConfig) error { - config.mode = chatPostEphemeral + config.endpoint = SLACK_API + string(chatPostEphemeral) config.values.Del("ts") return nil } @@ -240,7 +238,7 @@ func MsgOptionPostEphemeral() MsgOption { // MsgOptionPostEphemeral2 - posts an ephemeral message to the provided user. func MsgOptionPostEphemeral2(userID string) MsgOption { return func(config *sendConfig) error { - config.mode = chatPostEphemeral + config.endpoint = SLACK_API + string(chatPostEphemeral) MsgOptionUser(userID)(config) config.values.Del("ts") @@ -251,7 +249,7 @@ func MsgOptionPostEphemeral2(userID string) MsgOption { // MsgOptionMeMessage posts a "me message" type from the calling user func MsgOptionMeMessage() MsgOption { return func(config *sendConfig) error { - config.mode = chatMeMessage + config.endpoint = SLACK_API + string(chatMeMessage) return nil } } @@ -259,7 +257,7 @@ func MsgOptionMeMessage() MsgOption { // MsgOptionUpdate updates a message based on the timestamp. func MsgOptionUpdate(timestamp string) MsgOption { return func(config *sendConfig) error { - config.mode = chatUpdate + config.endpoint = SLACK_API + string(chatUpdate) config.values.Add("ts", timestamp) return nil } @@ -268,7 +266,7 @@ func MsgOptionUpdate(timestamp string) MsgOption { // MsgOptionDelete deletes a message based on the timestamp. func MsgOptionDelete(timestamp string) MsgOption { return func(config *sendConfig) error { - config.mode = chatDelete + config.endpoint = SLACK_API + string(chatDelete) config.values.Add("ts", timestamp) return nil } @@ -297,7 +295,7 @@ func MsgOptionUser(userID string) MsgOption { func MsgOptionText(text string, escape bool) MsgOption { return func(config *sendConfig) error { if escape { - text = escapeMessage(text) + text = slackutilsx.EscapeMessage(text) } config.values.Add("text", text) return nil @@ -392,6 +390,18 @@ func MsgOptionParse(b bool) MsgOption { } } +// UnsafeMsgOptionEndpoint deliver the message to the specified endpoint. +// NOTE: USE AT YOUR OWN RISK: No issues relating to the use of this Option +// will be supported by the library, it is subject to change without notice that +// may result in compilation errors or runtime behaviour changes. +func UnsafeMsgOptionEndpoint(endpoint string, update func(url.Values)) MsgOption { + return func(config *sendConfig) error { + config.endpoint = endpoint + update(config.values) + return nil + } +} + // MsgOptionPostMessageParameters maintain backwards compatibility. func MsgOptionPostMessageParameters(params PostMessageParameters) MsgOption { return func(config *sendConfig) error { diff --git a/vendor/github.com/nlopes/slack/conversation.go b/vendor/github.com/nlopes/slack/conversation.go index edde87a2..1c64116e 100644 --- a/vendor/github.com/nlopes/slack/conversation.go +++ b/vendor/github.com/nlopes/slack/conversation.go @@ -29,6 +29,8 @@ type conversation struct { NameNormalized string `json:"name_normalized"` NumMembers int `json:"num_members"` Priority float64 `json:"priority"` + User string `json:"user"` + // TODO support pending_shared // TODO support previous_names } @@ -64,6 +66,13 @@ type GetUsersInConversationParameters struct { Limit int } +type GetConversationsForUserParameters struct { + UserID string + Cursor string + Types []string + Limit int +} + type responseMetaData struct { NextCursor string `json:"next_cursor"` } @@ -100,6 +109,41 @@ func (api *Client) GetUsersInConversationContext(ctx context.Context, params *Ge return response.Members, response.ResponseMetaData.NextCursor, nil } +// GetConversationsForUser returns the list conversations for a given user +func (api *Client) GetConversationsForUser(params *GetConversationsForUserParameters) (channels []Channel, nextCursor string, err error) { + return api.GetConversationsForUserContext(context.Background(), params) +} + +// GetConversationsForUserContext returns the list conversations for a given user with a custom context +func (api *Client) GetConversationsForUserContext(ctx context.Context, params *GetConversationsForUserParameters) (channels []Channel, nextCursor string, err error) { + values := url.Values{ + "token": {api.token}, + "user": {params.UserID}, + } + if params.Cursor != "" { + values.Add("cursor", params.Cursor) + } + if params.Limit != 0 { + values.Add("limit", strconv.Itoa(params.Limit)) + } + if params.Types != nil { + values.Add("types", strings.Join(params.Types, ",")) + } + response := struct { + Channels []Channel `json:"channels"` + ResponseMetaData responseMetaData `json:"response_metadata"` + SlackResponse + }{} + err = postSlackMethod(ctx, api.httpclient, "users.conversations", values, &response, api.debug) + if err != nil { + return nil, "", err + } + if !response.Ok { + return nil, "", errors.New(response.Error) + } + return response.Channels, response.ResponseMetaData.NextCursor, nil +} + // ArchiveConversation archives a conversation func (api *Client) ArchiveConversation(channelID string) error { return api.ArchiveConversationContext(context.Background(), channelID) diff --git a/vendor/github.com/nlopes/slack/dialog.go b/vendor/github.com/nlopes/slack/dialog.go index a13e53da..d1435d54 100644 --- a/vendor/github.com/nlopes/slack/dialog.go +++ b/vendor/github.com/nlopes/slack/dialog.go @@ -6,52 +6,47 @@ import ( "errors" ) +// InputType is the type of the dialog input type +type InputType string + +const ( + // InputTypeText textfield input + InputTypeText InputType = "text" + // InputTypeTextArea textarea input + InputTypeTextArea InputType = "textarea" + // InputTypeSelect textfield input + InputTypeSelect InputType = "select" +) + +// DialogInput for dialogs input type text or menu +type DialogInput struct { + Type InputType `json:"type"` + Label string `json:"label"` + Name string `json:"name"` + Placeholder string `json:"placeholder"` + Optional bool `json:"optional"` +} + +// DialogTrigger ... type DialogTrigger struct { - TriggerId string `json:"trigger_id"` //Required. Must respond within 3 seconds. + TriggerID string `json:"trigger_id"` //Required. Must respond within 3 seconds. Dialog Dialog `json:"dialog"` //Required. } +// Dialog as in Slack dialogs +// https://api.slack.com/dialogs#option_element_attributes#top-level_dialog_attributes type Dialog struct { - CallbackId string `json:"callback_id"` //Required. - Title string `json:"title"` //Required. - SubmitLabel string `json:"submit_label,omitempty"` //Optional. Default value is 'Submit' - NotifyOnCancel bool `json:"notify_on_cancel,omitempty"` //Optional. Default value is false - Elements []DialogElement `json:"elements"` //Required. + TriggerID string `json:"trigger_id"` //Required + CallbackID string `json:"callback_id"` //Required + Title string `json:"title"` + SubmitLabel string `json:"submit_label,omitempty"` + NotifyOnCancel bool `json:"notify_on_cancel"` + Elements []DialogElement `json:"elements"` } +// DialogElement abstract type for dialogs. type DialogElement interface{} -type DialogTextElement struct { - Label string `json:"label"` //Required. - Name string `json:"name"` //Required. - Type string `json:"type"` //Required. Allowed values: "text", "textarea", "select". - Placeholder string `json:"placeholder,omitempty"` //Optional. - Optional bool `json:"optional,omitempty"` //Optional. Default value is false - Value string `json:"value,omitempty"` //Optional. - MaxLength int `json:"max_length,omitempty"` //Optional. - MinLength int `json:"min_length,omitempty"` //Optional,. Default value is 0 - Hint string `json:"hint,omitempty"` //Optional. - Subtype string `json:"subtype,omitempty"` //Optional. Allowed values: "email", "number", "tel", "url". -} - -type DialogSelectElement struct { - Label string `json:"label"` //Required. - Name string `json:"name"` //Required. - Type string `json:"type"` //Required. Allowed values: "text", "textarea", "select". - Placeholder string `json:"placeholder,omitempty"` //Optional. - Optional bool `json:"optional,omitempty"` //Optional. Default value is false - Value string `json:"value,omitempty"` //Optional. - DataSource string `json:"data_source,omitempty"` //Optional. Allowed values: "users", "channels", "conversations", "external". - SelectedOptions string `json:"selected_options,omitempty"` //Optional. Default value for "external" only - Options []DialogElementOption `json:"options,omitempty"` //One of options or option_groups is required. - OptionGroups []DialogElementOption `json:"option_groups,omitempty"` //Provide up to 100 options. -} - -type DialogElementOption struct { - Label string `json:"label"` //Required. - Value string `json:"value"` //Required. -} - // DialogCallback is sent from Slack when a user submits a form from within a dialog type DialogCallback struct { Type string `json:"type"` @@ -78,28 +73,43 @@ type DialogSuggestionCallback struct { CallbackID string `json:"callback_id"` } -// OpenDialog opens a dialog window where the triggerId originated from -func (api *Client) OpenDialog(triggerId string, dialog Dialog) (err error) { - return api.OpenDialogContext(context.Background(), triggerId, dialog) +// DialogOpenResponse response from `dialog.open` +type DialogOpenResponse struct { + SlackResponse + DialogResponseMetadata DialogResponseMetadata `json:"response_metadata"` +} + +// DialogResponseMetadata lists the error messages +type DialogResponseMetadata struct { + Messages []string `json:"messages"` +} + +// OpenDialog opens a dialog window where the triggerID originated from. +// EXPERIMENTAL: dialog functionality is currently experimental, api is not considered stable. +func (api *Client) OpenDialog(triggerID string, dialog Dialog) (err error) { + return api.OpenDialogContext(context.Background(), triggerID, dialog) } // OpenDialogContext opens a dialog window where the triggerId originated from with a custom context -func (api *Client) OpenDialogContext(ctx context.Context, triggerId string, dialog Dialog) (err error) { - if triggerId == "" { +// EXPERIMENTAL: dialog functionality is currently experimental, api is not considered stable. +func (api *Client) OpenDialogContext(ctx context.Context, triggerID string, dialog Dialog) (err error) { + if triggerID == "" { return errors.New("received empty parameters") } - resp := DialogTrigger{ - TriggerId: triggerId, + req := DialogTrigger{ + TriggerID: triggerID, Dialog: dialog, } - jsonResp, err := json.Marshal(resp) + + encoded, err := json.Marshal(req) if err != nil { return err } - response := &SlackResponse{} + + response := &DialogOpenResponse{} endpoint := SLACK_API + "dialog.open" - if err := postJSON(ctx, api.httpclient, endpoint, api.token, jsonResp, response, api.debug); err != nil { + if err := postJSON(ctx, api.httpclient, endpoint, api.token, encoded, response, api.debug); err != nil { return err } diff --git a/vendor/github.com/nlopes/slack/dialog_select.go b/vendor/github.com/nlopes/slack/dialog_select.go new file mode 100644 index 00000000..cff35479 --- /dev/null +++ b/vendor/github.com/nlopes/slack/dialog_select.go @@ -0,0 +1,125 @@ +package slack + +// SelectDataSource types of select datasource +type SelectDataSource string + +const ( + // DialogDataSourceStatic menu with static Options/OptionGroups + DialogDataSourceStatic SelectDataSource = "static" + // DialogDataSourceExternal dynamic datasource + DialogDataSourceExternal SelectDataSource = "external" + // DialogDataSourceConversations provides a list of conversations + DialogDataSourceConversations SelectDataSource = "conversations" + // DialogDataSourceChannels provides a list of channels + DialogDataSourceChannels SelectDataSource = "channels" + // DialogDataSourceUsers provides a list of users + DialogDataSourceUsers SelectDataSource = "users" +) + +// DialogInputSelect dialog support for select boxes. +type DialogInputSelect struct { + DialogInput + Value string `json:"value,omitempty"` //Optional. + DataSource SelectDataSource `json:"data_source,omitempty"` //Optional. Allowed values: "users", "channels", "conversations", "external". + SelectedOptions string `json:"selected_options,omitempty"` //Optional. Default value for "external" only + Options []DialogSelectOption `json:"options,omitempty"` //One of options or option_groups is required. + OptionGroups []DialogOptionGroup `json:"option_groups,omitempty"` //Provide up to 100 options. +} + +// DialogSelectOption is an option for the user to select from the menu +type DialogSelectOption struct { + Label string `json:"label"` + Value string `json:"value"` +} + +// DialogOptionGroup is a collection of options for creating a segmented table +type DialogOptionGroup struct { + Label string `json:"label"` + Options []DialogSelectOption `json:"options"` +} + +// NewStaticSelectDialogInput constructor for a `static` datasource menu input +func NewStaticSelectDialogInput(name, label string, options []DialogSelectOption) *DialogInputSelect { + return &DialogInputSelect{ + DialogInput: DialogInput{ + Type: InputTypeSelect, + Name: name, + Label: label, + Optional: true, + }, + DataSource: DialogDataSourceStatic, + Options: options, + } +} + +// NewGroupedSelectDialogInput creates grouped options select input for Dialogs. +func NewGroupedSelectDialogInput(name, label string, groups map[string]map[string]string) *DialogInputSelect { + optionGroups := []DialogOptionGroup{} + for groupName, options := range groups { + optionGroups = append(optionGroups, DialogOptionGroup{ + Label: groupName, + Options: optionsFromMap(options), + }) + } + return &DialogInputSelect{ + DialogInput: DialogInput{ + Type: InputTypeSelect, + Name: name, + Label: label, + }, + DataSource: DialogDataSourceStatic, + OptionGroups: optionGroups, + } +} + +func optionsFromArray(options []string) []DialogSelectOption { + selectOptions := make([]DialogSelectOption, len(options)) + for idx, value := range options { + selectOptions[idx] = DialogSelectOption{ + Label: value, + Value: value, + } + } + return selectOptions +} + +func optionsFromMap(options map[string]string) []DialogSelectOption { + selectOptions := make([]DialogSelectOption, len(options)) + idx := 0 + var option DialogSelectOption + for key, value := range options { + option = DialogSelectOption{ + Label: key, + Value: value, + } + selectOptions[idx] = option + idx++ + } + return selectOptions +} + +// NewConversationsSelect returns a `Conversations` select +func NewConversationsSelect(name, label string) *DialogInputSelect { + return newPresetSelect(name, label, DialogDataSourceConversations) +} + +// NewChannelsSelect returns a `Channels` select +func NewChannelsSelect(name, label string) *DialogInputSelect { + return newPresetSelect(name, label, DialogDataSourceChannels) +} + +// NewUsersSelect returns a `Users` select +func NewUsersSelect(name, label string) *DialogInputSelect { + return newPresetSelect(name, label, DialogDataSourceUsers) +} + +func newPresetSelect(name, label string, dataSourceType SelectDataSource) *DialogInputSelect { + return &DialogInputSelect{ + DialogInput: DialogInput{ + Type: InputTypeSelect, + Label: label, + Name: name, + }, + DataSource: dataSourceType, + } +} diff --git a/vendor/github.com/nlopes/slack/dialog_text.go b/vendor/github.com/nlopes/slack/dialog_text.go new file mode 100644 index 00000000..bf9602cc --- /dev/null +++ b/vendor/github.com/nlopes/slack/dialog_text.go @@ -0,0 +1,50 @@ +package slack + +// TextInputSubtype Accepts email, number, tel, or url. In some form factors, optimized input is provided for this subtype. +type TextInputSubtype string + +const ( + // InputSubtypeEmail email keyboard + InputSubtypeEmail TextInputSubtype = "email" + // InputSubtypeNumber numeric keyboard + InputSubtypeNumber TextInputSubtype = "number" + // InputSubtypeTel Phone keyboard + InputSubtypeTel TextInputSubtype = "tel" + // InputSubtypeURL Phone keyboard + InputSubtypeURL TextInputSubtype = "url" +) + +// TextInputElement subtype of DialogInput +// https://api.slack.com/dialogs#option_element_attributes#text_element_attributes +type TextInputElement struct { + DialogInput + MaxLength int `json:"max_length,omitempty"` + MinLength int `json:"min_length,omitempty"` + Hint string `json:"hint,omitempty"` + Subtype TextInputSubtype `json:"subtype"` + Value string `json:"value"` +} + +// NewTextInput constructor for a `text` input +func NewTextInput(name, label, text string) *TextInputElement { + return &TextInputElement{ + DialogInput: DialogInput{ + Type: InputTypeText, + Name: name, + Label: label, + }, + Value: text, + } +} + +// NewTextAreaInput constructor for a `textarea` input +func NewTextAreaInput(name, label, text string) *TextInputElement { + return &TextInputElement{ + DialogInput: DialogInput{ + Type: InputTypeTextArea, + Name: name, + Label: label, + }, + Value: text, + } +} diff --git a/vendor/github.com/nlopes/slack/files.go b/vendor/github.com/nlopes/slack/files.go index 2381ec3c..0550c9fb 100644 --- a/vendor/github.com/nlopes/slack/files.go +++ b/vendor/github.com/nlopes/slack/files.go @@ -93,14 +93,15 @@ type File struct { // There are three ways to upload a file. You can either set Content if file is small, set Reader if file is large, // or provide a local file path in File to upload it from your filesystem. type FileUploadParameters struct { - File string - Content string - Reader io.Reader - Filetype string - Filename string - Title string - InitialComment string - Channels []string + File string + Content string + Reader io.Reader + Filetype string + Filename string + Title string + InitialComment string + Channels []string + ThreadTimestamp string } // GetFilesParameters contains all the parameters necessary (including the optional ones) for a GetFiles() request @@ -237,6 +238,9 @@ func (api *Client) UploadFileContext(ctx context.Context, params FileUploadParam if params.InitialComment != "" { values.Add("initial_comment", params.InitialComment) } + if params.ThreadTimestamp != "" { + values.Add("thread_ts", params.ThreadTimestamp) + } if len(params.Channels) != 0 { values.Add("channels", strings.Join(params.Channels, ",")) } diff --git a/vendor/github.com/nlopes/slack/security.go b/vendor/github.com/nlopes/slack/security.go new file mode 100644 index 00000000..50201d99 --- /dev/null +++ b/vendor/github.com/nlopes/slack/security.go @@ -0,0 +1,47 @@ +package slack
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "hash"
+ "net/http"
+)
+
+// SecretsVerifier contains the information needed to verify that the request comes from Slack
+type SecretsVerifier struct {
+ slackSig string
+ timeStamp string
+ hmac hash.Hash
+}
+
+// NewSecretsVerifier returns a SecretsVerifier object in exchange for an http.Header object and signing secret
+func NewSecretsVerifier(header http.Header, signingSecret string) (SecretsVerifier, error) {
+ if header["X-Slack-Signature"][0] == "" || header["X-Slack-Request-Timestamp"][0] == "" {
+ return SecretsVerifier{}, errors.New("Headers are empty, cannot create SecretsVerifier")
+ }
+
+ hash := hmac.New(sha256.New, []byte(signingSecret))
+ hash.Write([]byte(fmt.Sprintf("v0:%s:", header["X-Slack-Request-Timestamp"][0])))
+ return SecretsVerifier{
+ slackSig: header["X-Slack-Signature"][0],
+ timeStamp: header["X-Slack-Request-Timestamp"][0],
+ hmac: hash,
+ }, nil
+}
+
+func (v *SecretsVerifier) Write(body []byte) (n int, err error) {
+ return v.hmac.Write(body)
+}
+
+// Ensure compares the signature sent from Slack with the actual computed hash to judge validity
+func (v SecretsVerifier) Ensure() error {
+ computed := "v0=" + string(hex.EncodeToString(v.hmac.Sum(nil)))
+ if computed == v.slackSig {
+ return nil
+ }
+
+ return fmt.Errorf("Expected signing signature: %s, but computed: %s", v.slackSig, computed)
+}
diff --git a/vendor/github.com/nlopes/slack/slackutilsx/slackutilsx.go b/vendor/github.com/nlopes/slack/slackutilsx/slackutilsx.go new file mode 100644 index 00000000..ccf5372b --- /dev/null +++ b/vendor/github.com/nlopes/slack/slackutilsx/slackutilsx.go @@ -0,0 +1,57 @@ +// Package slackutilsx is a utility package that doesn't promise API stability. +// its for experimental functionality and utilities. +package slackutilsx + +import ( + "strings" + "unicode/utf8" +) + +// ChannelType the type of channel based on the channelID +type ChannelType int + +func (t ChannelType) String() string { + switch t { + case CTypeDM: + return "Direct" + case CTypeGroup: + return "Group" + case CTypeChannel: + return "Channel" + default: + return "Unknown" + } +} + +const ( + // CTypeUnknown represents channels we cannot properly detect. + CTypeUnknown ChannelType = iota + // CTypeDM is a private channel between two slack users. + CTypeDM + // CTypeGroup is a group channel. + CTypeGroup + // CTypeChannel is a public channel. + CTypeChannel +) + +// DetectChannelType converts a channelID to a ChannelType. +// channelID must not be empty. However, if it is empty, the channel type will default to Unknown. +func DetectChannelType(channelID string) ChannelType { + // intentionally ignore the error and just default to CTypeUnknown + switch r, _ := utf8.DecodeRuneInString(channelID); r { + case 'C': + return CTypeChannel + case 'G': + return CTypeGroup + case 'D': + return CTypeDM + default: + return CTypeUnknown + } +} + +// EscapeMessage text +func EscapeMessage(message string) string { + replacer := strings.NewReplacer("&", "&", "<", "<", ">", ">") + return replacer.Replace(message) +} diff --git a/vendor/github.com/nlopes/slack/usergroups.go b/vendor/github.com/nlopes/slack/usergroups.go index 1e2b6442..cc9bc4ca 100644 --- a/vendor/github.com/nlopes/slack/usergroups.go +++ b/vendor/github.com/nlopes/slack/usergroups.go @@ -25,6 +25,7 @@ type UserGroup struct { DeletedBy string `json:"deleted_by"` Prefs UserGroupPrefs `json:"prefs"` UserCount int `json:"user_count"` + Users []string `json:"users"` } // UserGroupPrefs contains default channels and groups (private channels) @@ -121,16 +122,62 @@ func (api *Client) EnableUserGroupContext(ctx context.Context, userGroup string) return response.UserGroup, nil } +// GetUserGroupsOption options for the GetUserGroups method call. +type GetUserGroupsOption func(*GetUserGroupsParams) + +// GetUserGroupsOptionIncludeCount include the number of users in each User Group (default: false) +func GetUserGroupsOptionIncludeCount(b bool) GetUserGroupsOption { + return func(params *GetUserGroupsParams) { + params.IncludeCount = b + } +} + +// GetUserGroupsOptionIncludeDisabled include disabled User Groups (default: false) +func GetUserGroupsOptionIncludeDisabled(b bool) GetUserGroupsOption { + return func(params *GetUserGroupsParams) { + params.IncludeDisabled = b + } +} + +// GetUserGroupsOptionIncludeUsers include the list of users for each User Group (default: false) +func GetUserGroupsOptionIncludeUsers(b bool) GetUserGroupsOption { + return func(params *GetUserGroupsParams) { + params.IncludeUsers = b + } +} + +// GetUserGroupsParams contains arguments for GetUserGroups method call +type GetUserGroupsParams struct { + IncludeCount bool + IncludeDisabled bool + IncludeUsers bool +} + // GetUserGroups returns a list of user groups for the team -func (api *Client) GetUserGroups() ([]UserGroup, error) { - return api.GetUserGroupsContext(context.Background()) +func (api *Client) GetUserGroups(options ...GetUserGroupsOption) ([]UserGroup, error) { + return api.GetUserGroupsContext(context.Background(), options...) } // GetUserGroupsContext returns a list of user groups for the team with a custom context -func (api *Client) GetUserGroupsContext(ctx context.Context) ([]UserGroup, error) { +func (api *Client) GetUserGroupsContext(ctx context.Context, options ...GetUserGroupsOption) ([]UserGroup, error) { + params := GetUserGroupsParams{} + + for _, opt := range options { + opt(¶ms) + } + values := url.Values{ "token": {api.token}, } + if params.IncludeCount { + values.Add("include_count", "true") + } + if params.IncludeDisabled { + values.Add("include_disabled", "true") + } + if params.IncludeUsers { + values.Add("include_users", "true") + } response, err := userGroupRequest(ctx, api.httpclient, "usergroups.list", values, api.debug) if err != nil { diff --git a/vendor/github.com/nlopes/slack/webhooks.go b/vendor/github.com/nlopes/slack/webhooks.go index 870a8d8b..3ea69ffe 100644 --- a/vendor/github.com/nlopes/slack/webhooks.go +++ b/vendor/github.com/nlopes/slack/webhooks.go @@ -1,15 +1,16 @@ package slack import ( - "github.com/pkg/errors" - "net/http" "bytes" "encoding/json" + "net/http" + + "github.com/pkg/errors" ) type WebhookMessage struct { - Text string `json:"text,omitempty"` - Attachments []Attachment `json:"attachments,omitempty"` + Text string `json:"text,omitempty"` + Attachments []Attachment `json:"attachments,omitempty"` } func PostWebhook(url string, msg *WebhookMessage) error { @@ -19,7 +20,7 @@ func PostWebhook(url string, msg *WebhookMessage) error { return errors.Wrap(err, "marshal failed") } - response, err := http.Post(url, "application/json", bytes.NewReader(raw)); + response, err := http.Post(url, "application/json", bytes.NewReader(raw)) if err != nil { return errors.Wrap(err, "failed to post webhook") diff --git a/vendor/github.com/nlopes/slack/websocket_managed_conn.go b/vendor/github.com/nlopes/slack/websocket_managed_conn.go index b6d1bfc8..e8ab65a1 100644 --- a/vendor/github.com/nlopes/slack/websocket_managed_conn.go +++ b/vendor/github.com/nlopes/slack/websocket_managed_conn.go @@ -524,4 +524,9 @@ var EventMapping = map[string]interface{}{ "member_joined_channel": MemberJoinedChannelEvent{}, "member_left_channel": MemberLeftChannelEvent{}, + + "subteam_created": SubteamCreatedEvent{}, + "subteam_self_added": SubteamSelfAddedEvent{}, + "subteam_self_removed": SubteamSelfRemovedEvent{}, + "subteam_updated": SubteamUpdatedEvent{}, } diff --git a/vendor/github.com/nlopes/slack/websocket_subteam.go b/vendor/github.com/nlopes/slack/websocket_subteam.go new file mode 100644 index 00000000..a23b274c --- /dev/null +++ b/vendor/github.com/nlopes/slack/websocket_subteam.go @@ -0,0 +1,35 @@ +package slack + +// SubteamCreatedEvent represents the Subteam created event +type SubteamCreatedEvent struct { + Type string `json:"type"` + Subteam UserGroup `json:"subteam"` +} + +// SubteamCreatedEvent represents the membership of an existing User Group has changed event +type SubteamMembersChangedEvent struct { + Type string `json:"type"` + SubteamID string `json:"subteam_id"` + TeamID string `json:"team_id"` + DatePreviousUpdate JSONTime `json:"date_previous_update"` + DateUpdate JSONTime `json:"date_update"` + AddedUsers []string `json:"added_users"` + AddedUsersCount string `json:"added_users_count"` + RemovedUsers []string `json:"removed_users"` + RemovedUsersCount string `json:"removed_users_count"` +} + +// SubteamSelfAddedEvent represents an event of you have been added to a User Group +type SubteamSelfAddedEvent struct { + Type string `json:"type"` + SubteamID string `json:"subteam_id"` +} + +// SubteamSelfRemovedEvent represents an event of you have been removed from a User Group +type SubteamSelfRemovedEvent SubteamSelfAddedEvent + +// SubteamUpdatedEvent represents an event of an existing User Group has been updated or its members changed +type SubteamUpdatedEvent struct { + Type string `json:"type"` + Subteam UserGroup `json:"subteam"` +} |