utils

package module
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 23, 2020 License: MIT Imports: 13 Imported by: 0

README

slack-utils

Collection of utility methods/middleware I frequently use in slackbot projects.

Disclaimer

Until major release version 1.0.0, it is safe to expect some significant changes to existing functions.

Highlighted functionality

Easy verification

Easily verify incoming requests from slash commands/interactive callbacks using the provided verification middleware.

The simplest way to enable request verification is as follows:

r := chi.NewRouter()
r.Use(utils.VerifySlashCommand(env.SigningSecret, nil, nil))
r.Use(utils.VerifyInteractionCallback(env.SigningSecret, nil, nil))

The above will verify the authenticity of all incoming requests using your signing secret and embed the verified/unmarshalled request object into the context on success. Optionally configure additional actions to be taken on success/failure (e.g. logging) by passing in corresponding callback methods.

Retrieve the request from the context and use it in the following manner:

Slash command example

func Foo(w http.ResponseWriter, r *http.Request) {
  cmd, err := utils.SlashCommand(r.Context())
  if err != nil {
    // handle error
  }

  if err = doSomething(cmd.Text); err != nil {
    // handle error
  }
}

Interactive callback example

func Callback(w http.ResponseWriter, r *http.Request) {
  callback, err := utils.InteractionCallback(r.Context())
  if err != nil {
   // handle error
  }

  switch callback.Type {
  case slack.InteractionTypeBlockActions:
    // handle block action callback
  case slack.InteractionTypeMessageAction:
    // handle message action callback
  case slack.InteractionTypeDialogSubmission:
    // handle dialog submission callback
  }
}
Posting messages and using Blocks

Below is a pseudo-code example of how to post an interactive block message to Slack using some of the utilities offered by the library

client := slack.New(env.BotToken)

startDatePickerSectionBlock := utils.NewTextBlock("Please choose a *start date* for the new survey", nil)

startDatePickerElem := utils.NewDatePickerWithOpts(startDatePickerActionID, nil, time.Now())

startDatePickerActionBlock := slack.NewActionBlock(
    startDatePickerBlockID, 
    startDatePickerElem, 
    utils.CancelBtn,
)

startDatePickerMsg = utils.Msg{
	Blocks: []slack.Block{startDatePickerSectionBlock, startDatePickerActionBlock},
}
	
_, err := utils.PostMsg(client, startDatePickerMsg, channelID)

To post ephemerally, use PostEphemeralMsg and include the target user's ID.

Delete normal/ephemeral messages alike in the following manner:

utils.DeleteMsg(client, channelID, ts, responseURL)
Working with channels

Create a new channel, invite users, and post an init message with a single command

channelHandler := &utils.Channel{
	UserClient: slack.New(env.UserToken),
	BotClient: slack.New(env.BotToken),
}
err := channelHandler.CreateChannel(channelName, userIDs, utils.Msg{Body: initMsg})

Requires UserClient with channels:write scope. Include the BotClient as well if you wish to post the init message as the bot user and not as the user associated with the UserClient token

Get all channel members' Slack IDs or emails

client := slack.New(env.BotToken)
emails, err := utils.GetChannelMemberEmails(client, env.ChannelID)

Use GetChannelMembers for Slack IDs instead of emails

Leave or archive multiple channels

channelHandler := &utils.Channel{
	UserClient: slack.New(env.UserToken),
}
err := channelHandler.LeaveChannels(channelIDs)

User ArchiveChannels to archive channels instead (both methods require UserClient with channels:write scope)

Invite multiple users to a channel

channelHandler := &utils.Channel{
	UserClient: slack.New(env.UserToken),
}
err := channelHandler.InviteUsers(userIDs)

Requires UserClient with channels:write scope

Working with users

Convert emails to Slack IDs

client := slack.New(env.BotToken)
users, err := utils.EmailsToSlackIDs(client, userEmails)

Use EmailsToSlackIDsInclusive if you want to get back both the email and the Slack ID for each user

Working with files

Read and download CSV files shared in Slack

client := slack.New(env.BotToken)
rows, err := utils.DownloadAndReadCSV(h.client, urlPrivateDownload)

Per Slack API restrictions, requires the files:read scope on the UserClient and the user associated with the token must have access to the file


Suggestions/requests for new functionality are always welcome

Documentation

Index

Constants

View Source
const (
	CancelActionID = "cancel_action"
	CancelBlockID  = "cancel_block"
)
View Source
const ChannelNameMaxLen = 21

ChannelNameMaxLen is the max character length for a Slack channel name

Variables

View Source
var (
	DoneBtn   = NewButton(CancelActionID, "done", "Done", slack.StylePrimary)
	CancelBtn = NewButton(CancelActionID, "cancel", "Cancel", slack.StyleDanger)
)
View Source
var DivBlock = slack.NewDividerBlock()
View Source
var ErrInvalidCSV = errors.New("received invalid/empty CSV file")
View Source
var ErrNoUsersInWorkplace = errors.New("no users in workplace")

Functions

func DateOptToTime added in v0.3.0

func DateOptToTime(opt string) (time.Time, error)

DateOptToTime parses the selected date opt back to time.Time, but owing to its format will always initialize to zero time for everything more granular than a day. Add time.Duration as needed in downstream packages

func DeleteMsg added in v0.7.0

func DeleteMsg(client *slack.Client, channelID, timestamp, responseURL string) error

DeleteMsg deletes the provided message in the channel designated by channelID

func DownloadAndReadCSV added in v0.4.0

func DownloadAndReadCSV(userClient *slack.Client, urlPrivateDownload string) ([][]string, error)

DownloadAndReadCSV downloads a CSV file from urlPrivateDownload and returns the CSV rows. Requires the files:read scope on the user client and the calling user must have access to the file.

func EmailsToSlackIDs added in v0.5.0

func EmailsToSlackIDs(client *slack.Client, emails []string) ([]string, error)

EmailsToSlackIDs takes in an array of email addresses and finds the IDs of any workplace members with those emails

func EmailsToSlackIDsInclusive added in v0.5.0

func EmailsToSlackIDsInclusive(client *slack.Client, emails []string) ([][]string, error)

EmailToSlackIDsInclusive takes in an array of email addresses, finds the IDs of any workplace members with those emails, and returns both values

func GetChannelMemberEmails added in v0.5.0

func GetChannelMemberEmails(client *slack.Client, channelID string) ([]string, error)

GetChannelMemberEmails returns a list of emails for members of a given channel

func GetChannelMembers added in v0.5.0

func GetChannelMembers(client *slack.Client, channelID string) ([]string, error)

GetChannelMembers returns a list of members for a given channel

func InteractionCallback added in v0.10.0

func InteractionCallback(ctx context.Context) (*slack.InteractionCallback, error)

InteractionCallback retrieves the verified interaction callback from the context. To utilize this functionality, you must use the VerifyInteractionCallback middleware.

func NewButton added in v0.8.0

func NewButton(actionID, value string, text string, style slack.Style) *slack.ButtonBlockElement

NewButton returns a new ButtonBlockElement set to the designated style

func NewDatePickerWithOpts added in v0.2.1

func NewDatePickerWithOpts(actionID string, placeholder *slack.TextBlockObject, initialDate time.Time) *slack.DatePickerBlockElement

NewDatePickerWithOpts returns a new DatePickerBlockElement initialized with its date/placeholder text set as specified by one of the two parameters

func NewTextBlock added in v0.8.0

func NewTextBlock(body string, accessory *slack.Accessory) *slack.SectionBlock

NewTextBlock returns a section block of common configuration.

func PostEphemeralMsg added in v0.7.0

func PostEphemeralMsg(client *slack.Client, msg Msg, channelID, userID string) error

PostEphemeralMsg sends an ephemeral message in the channel designated by channelID

func PostMsg

func PostMsg(client *slack.Client, msg Msg, channelID string) (string, error)

PostMsg sends the provided message to the channel designated by channelID

func PostThreadMsg

func PostThreadMsg(client *slack.Client, msg Msg, channelID string, threadTs string) error

PostThreadMsg posts a message response into an existing thread

func ReplaceOriginal

func ReplaceOriginal(w http.ResponseWriter, msg slack.Message) error

ReplaceOriginal replaces the original message with the newly encoded one NOTE: cannot be used in callback from block messages

func SendEmptyOK

func SendEmptyOK(w http.ResponseWriter)

SendEmptyOK responds with status 200

func SendOKAndDeleteOriginal

func SendOKAndDeleteOriginal(w http.ResponseWriter) error

SendOKAndDeleteOriginal responds with status 200 and deletes the original message NOTE: cannot be used in callback from block messages

func SendResp

func SendResp(w http.ResponseWriter, msg slack.Message) error

SendResp can be used to send simple callback responses NOTE: cannot be used in callback from block messages

func SlashCommand added in v0.10.0

func SlashCommand(ctx context.Context) (*slack.SlashCommand, error)

SlashCommand retrieves the verified slash command from the context. To utilize this functionality, you must use the VerifySlashCommand middleware.

func UpdateMsg

func UpdateMsg(client *slack.Client, msg Msg, channelID, timestamp string) error

UpdateMsg updates the provided message in the channel designated by channelID

func VerifyInteractionCallback added in v0.10.0

func VerifyInteractionCallback(signingSecret string, succeed verifySucceedCallback, fail verifyFail) func(next http.Handler) http.Handler

VerifyInteractionCallback is a middleware that will automatically verify the authenticity of the incoming request and embed the unmarshalled InteractionCallback in the context on success. Use the optional succeed/fail parameters to configure additional behavior on sucess/failure, or simply provide nil if no further action is required.

func VerifySlashCommand added in v0.10.0

func VerifySlashCommand(signingSecret string, succeed verifySucceedSlash, fail verifyFail) func(next http.Handler) http.Handler

VerifySlashCommand is a middleware that will automatically verify the authenticity of the incoming request and embed the unmarshalled SlashCommand in the context on success. Use the optional succeed/fail parameters to configure additional behavior on sucess/failure, or simply provide nil if no further action is required.

Types

type Channel

type Channel struct {
	UserClient *slack.Client
	BotClient  *slack.Client
	ChannelID  string
}

Channel is used in opening/interacting with a single Slack channel

func (*Channel) ArchiveChannels added in v0.5.0

func (c *Channel) ArchiveChannels(channelIDs []string) error

ArchiveChannels allows the user whose token was used to create the API client to archive multiple channels

func (*Channel) CreateChannel

func (c *Channel) CreateChannel(channelName string, userIDs []string, initMsg Msg) error

CreateChannel opens a new public channel and invites the provided list of member IDs, optionally posting an initial message

func (*Channel) InviteUsers

func (c *Channel) InviteUsers(userIDs []string) error

func (*Channel) LeaveChannels added in v0.5.0

func (c *Channel) LeaveChannels(channelIDs []string) error

LeaveChannels allows the user whose token was used to create the API client to leave multiple channels

type Msg

type Msg struct {
	Body        string
	Blocks      []slack.Block
	Attachments []slack.Attachment
	AsUser      bool
	IconURL     string // Incompatible with AsUser option
}

Msg is an intermediary struct used for posting messages

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL