Slack Bot Framework

Overview

slacker Build Status Go Report Card GoDoc License: MIT Mentioned in Awesome Go

Built on top of the Slack API github.com/slack-go/slack with the idea to simplify the Real-Time Messaging feature to easily create Slack Bots, assign commands to them and extract parameters.

Features

  • Easy definitions of commands and their input
  • Available bot initialization, errors and default handlers
  • Simple parsing of String, Integer, Float and Boolean parameters
  • Contains support for context.Context
  • Built-in help command
  • Replies can be new messages or in threads
  • Supports authorization
  • Bot responds to mentions and direct messages
  • Handlers run concurrently via goroutines
  • Produces events for executed commands
  • Full access to the Slack API github.com/slack-go/slack

Dependencies

Install

go get github.com/shomali11/slacker

Examples

Example 1

Defining a command using slacker

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong")
		},
	}

	bot.Command("ping", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 2

Defining a command with an optional description and example. The handler replies to a thread.

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Ping!",
		Example:     "ping",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong", slacker.WithThreadReply(true))
		},
	}

	bot.Command("ping", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 3

Defining a command with a parameter

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Echo a word!",
		Example:     "echo hello",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")
			response.Reply(word)
		},
	}

	bot.Command("echo <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 4

Defining a command with two parameters. Parsing one as a string and the other as an integer. (The second parameter is the default value in case no parameter was passed or could not parse the value)

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Repeat a word a number of times!",
		Example:     "repeat hello 10",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.StringParam("word", "Hello!")
			number := request.IntegerParam("number", 1)
			for i := 0; i < number; i++ {
				response.Reply(word)
			}
		},
	}

	bot.Command("repeat <word> <number>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 5

Defines two commands that display sending errors to the Slack channel. One that replies as a new message. The other replies to the thread.

package main

import (
	"context"
	"errors"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	messageReplyDefinition := &slacker.CommandDefinition{
		Description: "Tests errors in new messages",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.ReportError(errors.New("Oops!"))
		},
	}

	threadReplyDefinition := &slacker.CommandDefinition{
		Description: "Tests errors in threads",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.ReportError(errors.New("Oops!"), slacker.WithThreadError(true))
		},
	}

	bot.Command("message", messageReplyDefinition)
	bot.Command("thread", threadReplyDefinition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 6

Send a "Typing" indicator

package main

import (
	"context"
	"log"
	"time"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Server time!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Typing()

			time.Sleep(time.Second)

			response.Reply(time.Now().Format(time.RFC1123))
		},
	}

	bot.Command("time", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 7

Showcasing the ability to access the github.com/slack-go/slack API and the Real-Time Messaging Protocol. In this example, we are sending a message using RTM and uploading a file using the Slack API.

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
	"github.com/slack-go/slack"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Upload a word!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")

			channel := botCtx.Event().Channel
			rtm := botCtx.RTM()
			client := botCtx.Client()

			rtm.SendMessage(rtm.NewOutgoingMessage("Uploading file ...", channel))
			client.UploadFile(slack.FileUploadParameters{Content: word, Channels: []string{channel}})
		},
	}

	bot.Command("upload <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 8

Showcasing the ability to leverage context.Context to add a timeout

package main

import (
	"context"
	"errors"
	"log"
	"time"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Process!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			timedContext, cancel := context.WithTimeout(botCtx.Context(), time.Second)
			defer cancel()

			select {
			case <-timedContext.Done():
				response.ReportError(errors.New("timed out"))
			case <-time.After(time.Minute):
				response.Reply("Processing done!")
			}
		},
	}

	bot.Command("process", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 9

Showcasing the ability to add attachments to a Reply

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
	"github.com/slack-go/slack"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Echo a word!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")

			attachments := []slack.Attachment{}
			attachments = append(attachments, slack.Attachment{
				Color:      "red",
				AuthorName: "Raed Shomali",
				Title:      "Attachment Title",
				Text:       "Attachment Text",
			})

			response.Reply(word, slacker.WithAttachments(attachments))
		},
	}

	bot.Command("echo <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 10

Showcasing the ability to add blocks to a Reply

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
	"github.com/slack-go/slack"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	definition := &slacker.CommandDefinition{
		Description: "Echo a word!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")

			attachments := []slack.Block{}
			attachments = append(attachments, slack.NewContextBlock("1",
				slack.NewTextBlockObject("mrkdwn", "Hi!", false, false)),
			)

			response.Reply(word, slacker.WithBlocks(attachments))
		},
	}

	bot.Command("echo <word>", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 11

Showcasing the ability to create custom responses via CustomResponse

package main

import (
	"log"

	"context"
	"errors"
	"fmt"

	"github.com/shomali11/slacker"
)

const (
	errorFormat = "> Custom Error: _%s_"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	bot.CustomResponse(NewCustomResponseWriter)

	definition := &slacker.CommandDefinition{
		Description: "Custom!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("custom")
			response.ReportError(errors.New("oops"))
		},
	}

	bot.Command("custom", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

// NewCustomResponseWriter creates a new ResponseWriter structure
func NewCustomResponseWriter(botCtx slacker.BotContext) slacker.ResponseWriter {
	return &MyCustomResponseWriter{botCtx: botCtx}
}

// MyCustomResponseWriter a custom response writer
type MyCustomResponseWriter struct {
	botCtx slacker.BotContext
}

// ReportError sends back a formatted error message to the channel where we received the event from
func (r *MyCustomResponseWriter) ReportError(err error, options ...slacker.ReportErrorOption) {
	rtm := r.botCtx.RTM()
	event := r.botCtx.Event()
	rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf(errorFormat, err.Error()), event.Channel))
}

// Typing send a typing indicator
func (r *MyCustomResponseWriter) Typing() {
	rtm := r.botCtx.RTM()
	event := r.botCtx.Event()
	rtm.SendMessage(rtm.NewTypingMessage(event.Channel))
}

// Reply send a attachments to the current channel with a message
func (r *MyCustomResponseWriter) Reply(message string, options ...slacker.ReplyOption) {
	rtm := r.botCtx.RTM()
	event := r.botCtx.Event()
	rtm.SendMessage(rtm.NewOutgoingMessage(message, event.Channel))
}

Example 12

Showcasing the ability to toggle the slack Debug option via WithDebug

package main

import (
	"context"
	"github.com/shomali11/slacker"
	"log"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>", slacker.WithDebug(true))

	definition := &slacker.CommandDefinition{
		Description: "Ping!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong")
		},
	}

	bot.Command("ping", definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 13

Defining a command that can only be executed by authorized users

package main

import (
	"context"
	"log"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	authorizedUsers := []string{"<USER ID>"}

	authorizedDefinition := &slacker.CommandDefinition{
		Description: "Very secret stuff",
		AuthorizationFunc: func(botCtx slacker.BotContext, request slacker.Request) bool {
			return contains(authorizedUsers, botCtx.Event().User)
		},
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("You are authorized!")
		},
	}

	bot.Command("secret", authorizedDefinition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

func contains(list []string, element string) bool {
	for _, value := range list {
		if value == element {
			return true
		}
	}
	return false
}

Example 14

Adding handlers to when the bot is connected, encounters an error and a default for when none of the commands match

package main

import (
	"log"

	"context"
	"fmt"

	"github.com/shomali11/slacker"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	bot.Init(func() {
		log.Println("Connected!")
	})

	bot.Err(func(err string) {
		log.Println(err)
	})

	bot.DefaultCommand(func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
		response.Reply("Say what?")
	})

	bot.DefaultEvent(func(event interface{}) {
		fmt.Println(event)
	})

	definition := &slacker.CommandDefinition{
		Description: "help!",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("Your own help function...")
		},
	}

	bot.Help(definition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}

Example 15

Listening to the Commands Events being produced

package main

import (
	"fmt"
	"log"

	"context"

	"github.com/shomali11/slacker"
)

func printCommandEvents(analyticsChannel <-chan *slacker.CommandEvent) {
	for event := range analyticsChannel {
		fmt.Println("Command Events")
		fmt.Println(event.Timestamp)
		fmt.Println(event.Command)
		fmt.Println(event.Parameters)
		fmt.Println(event.Message)
		fmt.Println()
	}
}

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	go printCommandEvents(bot.CommandEvents())

	bot.Command("ping", &slacker.CommandDefinition{
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("pong")
		},
	})

	bot.Command("echo <word>", &slacker.CommandDefinition{
		Description: "Echo a word!",
		Example:     "echo hello",
		Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
			word := request.Param("word")
			response.Reply(word)
		},
	})

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}
Comments
  • Allow event handler to be configured

    Allow event handler to be configured

    Example of usage:

    
    handler := func(ctx context.Context, s *slacker.Slacker, msg slack.RTMEvent) error {
    	switch event := msg.Data.(type) {
    		case *slack.MessageEvent:
    			// do any special process, like filter messages by channel and process them.
    	}
    	return slacker.DefaultEventHandler(ctx,  s, msg)
    }
    bot := slacker..NewClient(token, slacker.WithEventHandler(handler))
    
    opened by smoya 20
  • my app only responds to the 1st message i post

    my app only responds to the 1st message i post

    i copy the example go file, and wrote @app run, it only responds to the 1st mention. while if i register new command it respond again to the very 1st one. Any reason for this? thanks

    opened by huaweiunity 18
  • Sanitize input for copypasted cmds

    Sanitize input for copypasted cmds

    When someone copies & pastes commands, they end up with a weird character \u00a0 so the command ends up being ignored.

    U+00A0 No-Break Space (NBSP) Unicode Character).

    e.g., The payload shows something like "text":"\u00a0my-command arg1 arg2"

    The payload can be visualized if we start Slacker in DEBUG mode:

                    bot = slacker.NewClient(slackBotToken, slackAppToken, slacker.WithDebug(true))
    

    This PR attempts to sanitize the input.

    opened by themarcelor 15
  • Expose the slack client in AuthorizedFunc

    Expose the slack client in AuthorizedFunc

    We'd like to be able to authenticate a Slack user with a backend database that has no concept of Slack User IDs, but to get the requesting users profile details we need access to the Slack client. Simple example:

    var myCommand = &slacker.CommandDefinition {
        ...
        AuthorizationFunc: func(request slacker.Request, client slack.Client) bool {
            ...
            userInfo, _ := client.GetUserInfo(request.Event().User)
            return AuthorizeFromDatabase("some-command", user.Profile.Email)
        },
        ...
    }
    
    opened by arusso 12
  • Use SocketMode for connections

    Use SocketMode for connections

    Updates Slacker to use the Events API over the SocketMode communication protocol, replacing calls to the deprecated RTM API.

    A few key functions have changed, notably the NewClient function now requires both an App and Bot token to be specified. In addition, the typing indicator is not supported in SocketMode and has been removed altogether.

    Fixes #63

    opened by arusso 11
  • This only works with

    This only works with "classic" slack apps

    I think the README should be updated to indicate it uses the RTM API which does not function with new slack apps that have granular oauth permissions.

    Took me 40 minutes to figure out what was going on by finally dropping the debug option in the config and seeing:

    slack-go/slack2020/07/18 13:56:31 websocket_managed_conn.go:177: Connecting to RTM
    slack-go/slack2020/07/18 13:56:32 rtm.go:71: Using URL:
    slack-go/slack2020/07/18 13:56:32 websocket_managed_conn.go:181: Failed to start or connect to RTM: not_allowed_token_type
    slack-go/slack2020/07/18 13:56:32 websocket_managed_conn.go:147: reconnection 1 failed: not_allowed_token_type reconnecting in 100ms
    ...
    

    It is possible to still create apps that use the old permissions scopes but they are pushing everything to the events API.

    More info in this thread https://github.com/slackapi/node-slack-sdk/issues/921#issuecomment-644317329

    opened by leetrout 11
  • Any sentence containing the word `help` anywhere will call the Help Command

    Any sentence containing the word `help` anywhere will call the Help Command

    Hi, I'm having some issues with the Help Command specification.

    Currently using in my code Slacker Git revision: 37d2f0fd93e4c63a1afaba092dc5bb548620fcb3

    Specifically I set a command to be something like:

    	// function tied to sentences sent to the Bot and starting with "open emergency" followed by some text
    	emergencyCmdDefinition := &slacker.CommandDefinition{
    		Description: "Open an EMERGENCY incident to Customer Support",
    		Handler: func(request slacker.Request, response slacker.ResponseWriter) {
    			if err := Emergency(request, response, config); err != nil {
    				Err(err.Error())
    				return
    			}
    		},
    	}
    	bot.Command("open emergency <msg>", emergencyCmdDefinition)
    

    and then added the Help function as:

    	// set the "help" message handling function
    	helpCmdDefinition := &slacker.CommandDefinition{
    		Description: "Help function",
    		Handler: func(request slacker.Request, response slacker.ResponseWriter) {
    			help(response, config)
    		},
    	}
    	bot.Help(helpCmdDefinition)
    

    But any sentence that contains the help word will trigger the Help Command (I guess because that's parsed earlier from what I read in your code).

    Say that you write open emergency my printer is on fire... I need some help! that would still just print the help instead of triggering the open emergency command as it normally would.

    I'd just want the help command to be triggered when the ONLY word is "help"... otherwise IMO the rest of the parsing should happen (go through normal commands parsing and then hit the DefaultCommand).

    You can see the full code here: https://github.com/gravitational/slackbot/blob/master/slackbot.go#L74

    opened by eldios 11
  • Debugging why a response isn't being shown in Slack

    Debugging why a response isn't being shown in Slack

    I have a situation where I can see that my command is reaching the slackbot, and it is responding, but the response is not showing up in Slack. It's hard for me to tell if this is something wrong with the bot/slacker, or if it's something else, and I'm wonder if there are good strategies for debugging this? I'm happy to try things out and then add some documentation here via PR with any helpful info I come up with.

    Here's what I have so far:

    I have put the "ping" command for testing, with a log line to show that the handler is getting executed -- it is:

    definition := &slacker.CommandDefinition{
         Handler: func(botCtx slacker.BotContext, request slacker.Request, response slacker.ResponseWriter) {
              fmt.Println("I've been asked to ping-pong!")
              response.Reply("pong")
         },
    }
    
    bot.Command("ping", definition)
    

    I've added debug(true) to the client: bot := slacker.NewClient(os.Getenv("SLACK_BOT_TOKEN"), os.Getenv("SLACK_APP_TOKEN"), slacker.WithDebug(true))

    When I start the bot, I see what I'd expect, although there is a message about unsupported Events API event received:

    Connecting to Slack with Socket Mode.
    slack-go/slack/socketmode2021/06/17 14:25:32 socket_mode_managed_conn.go:258: Starting SocketMode
    slack-go/slack2021/06/17 14:25:32 socket_mode.go:30: Using URL: wss://wss-primary.slack.com/link/?ticket=<etc>
    slack-go/slack/socketmode2021/06/17 14:25:32 socket_mode_managed_conn.go:266: Dialing to websocket on url wss://wss-primary.slack.com/link/?ticket=<etc>
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:91: WebSocket connection succeeded on try 0
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:439: Starting to receive message
    Connected to Slack with Socket Mode.
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:481: Incoming WebSocket message: {
      "type": "hello",
      "num_connections": 2,
      "debug_info": {
        "host": "applink-d85c5c684-wkb2x",
        "build_number": 18,
        "approximate_connection_time": 18060
      },
      "connection_info": {
        "app_id": "<id here>"
      }
    }
    
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:493: Finished to receive message
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:439: Starting to receive message
    slack-go/slack/socketmode2021/06/17 14:25:33 socket_mode_managed_conn.go:336: Received WebSocket message: {"type":"hello","num_connections":2,"debug_info":{"host":"applink-d85c5c684-wkb2x","build_number":18,"approximate_connection_time":18060},"connection_info":{"app_id":"<id here>"}}
    slack-go/slack/socketmode2021/06/17 14:25:33 slacker.go:185: unsupported Events API event received
    slack-go/slack/socketmode2021/06/17 14:25:38 socket_mode_managed_conn.go:561: WebSocket ping message received: Ping from applink-d85c5c684-wkb2x
    

    When I chat with the bot in Slack and say "ping", I get no response, but I see this logged:

    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:493: Finished to receive message
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:439: Starting to receive message
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:336: Received WebSocket message: {"envelope_id":"9159361e-b381-4801-85a5-eedad48bc59a","payload":{"token":"<token>","team_id":"<id>","api_app_id":"<id>","event":{"client_msg_id":"e7d533c4-9442-4fac-8b86-cef8181f93b7","type":"message","text":"ping","user":"<user>","ts":"1623965305.000200","team":"<team>","blocks":[{"type":"rich_text","block_id":"ckcY","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"ping"}]}]}],"channel":"<channel>","event_ts":"1623965305.000200","channel_type":"im"},"type":"event_callback","event_id":"Ev025MBNNNLC","event_time":1623965305,"authorizations":[{"enterprise_id":null,"team_id":"<team>","user_id":"<user>","is_bot":true,"is_enterprise_install":false}],"is_ext_shared_channel":false,"event_context":"2-message-T065FDZTQ-A02305WBY31-D024FNJ3953"},"type":"events_api","accepts_response_payload":false,"retry_attempt":0,"retry_reason":""}
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:430: Scheduling Socket Mode response for envelope ID 9159361e-b381-4801-85a5-eedad48bc59a: {"envelope_id":"9159361e-b381-4801-85a5-eedad48bc59a"}
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:312: Sending Socket Mode response with envelope ID "9159361e-b381-4801-85a5-eedad48bc59a": &{9159361e-b381-4801-85a5-eedad48bc59a <nil>}
    I've been asked to ping-pong!
    slack-go/slack/socketmode2021/06/17 14:28:25 socket_mode_managed_conn.go:321: Finished sending Socket Mode response with envelope ID "9159361e-b381-4801-85a5-eedad48bc59a"
    slack-go/slack2021/06/17 14:28:25 chat.go:233: Sending request: attachments=%5B%5D&blocks=%5B%5D&channel=<channel>&text=pong&token=<token>
    

    (I have obviously taken out anything potentially sensitive/security-related)

    Since I can see the response being sent, I'm not sure where to check next to see what the problem might be -- all of the connection, auth, etc seems fine. Any suggestions would be very much appreciated -- thanks for your help!

    opened by mason-jones-ck 10
  • Auth not working

    Auth not working

    Starting from your example, I'm testing a quick bot, but I'm getting an auth error. It's not clear from the code:

    bot := slacker.NewClient(os.Getenv("SLACK_BOT_TOKEN"), os.Getenv("SLACK_APP_TOKEN"))

    Whether this requires either a BOT token or an APP token, or if it needs both and what the difference is? For our Slack setup, I got an "API token" that should be a BOT token. When I set that and run it, I get:

    Connecting to Slack with Socket Mode. 2021/05/26 14:52:01 not_authed exit status 1

    Just to check, I used the token as SLACK_APP_TOKEN and then it just repeats:

    Connecting to Slack with Socket Mode. Connection failed. Retrying later...

    Over and over.

    It's not clear what the "not_authed" error means -- was the token refused, or did it fail to connect for authentication, or something else? Any hints on debugging this? Thank you!

    opened by mason-jones-ck 9
  • Enabling reply in thread

    Enabling reply in thread

    As the timestamp is needed to reply in thread, made some changes to be able to have this optional methods in ResponseWriter

    • Changed ResponseWriter interface to have replies methods with InThread version
    • Changed contructor to receive the events instead of only the channel
    • Adapted the whole code to comply to the new interface and constructor
    opened by batagliao 8
  • Add support for slash commands

    Add support for slash commands

    Add support for setting a slash command handler, much like the interactive event handler. I don't Ack the event (it's commented out) as the reference handler doesn't ack the event as well, but we can uncomment it if it makes sense to Ack the event here.

    opened by ctennis 7
  • Bump github.com/slack-go/slack from 0.11.2 to 0.12.1

    Bump github.com/slack-go/slack from 0.11.2 to 0.12.1

    Bumps github.com/slack-go/slack from 0.11.2 to 0.12.1.

    Release notes

    Sourced from github.com/slack-go/slack's releases.

    v0.12.1

    What's Changed

    Enhancements

    New Contributors

    Full Changelog: https://github.com/slack-go/slack/compare/v0.12.0...v0.12.1

    v0.12.0

    Thank you for all the contributions!

    What's Changed

    This release contains several backward incompatible changes.

    Fixes

    Enhancements

    New Contributors

    Full Changelog: https://github.com/slack-go/slack/compare/v0.11.4...v0.12.0

    v0.11.4

    What's Changed

    Enhancements

    ... (truncated)

    Commits
    • beca00a Merge pull request #1148 from slack-go/large-files-upload-timeout
    • bddec0a refactor FileUploadV2 implementation
    • c0676fc Merge pull request #1119 from stephenwan-opal/master
    • 617bdc1 Merge pull request #989 from Yohan460/include_num_members-support
    • 58dcbfd Merge pull request #1131 from yokishava/fix/rich-text-timestamp
    • acafae8 Merge pull request #1143 from johanmcos/add-GetOtherTeamInfoContext
    • d778e9e add GetOtherTeamInfoContext method
    • f50586f Merge pull request #1097 from MattDavisRV/CustomProfileField_Update
    • 5a47d3e Merge pull request #1095 from grimmy/expose-reactions
    • c857464 Merge pull request #1140 from ameliagapin/email_url_elements
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Retrieve Trigger ID from Slash Commands

    Retrieve Trigger ID from Slash Commands

    I am trying to retrieve the Trigger ID from a Slash Command so that I can open a Modal. I noticed in the message handler when an event matches slash command, the Data prop is given the req object instead of the evt obj like the other Message Events. This means I can no longer pull the trigger_id from the event.

    The slash command is the only type that uses request for the data prop instead of the evt

    opened by 0xArch3r 2
Releases(v1.3.0)
  • v1.3.0(Aug 28, 2022)

    Changelog

    Others

    • 287b5db Add ability to define a default inner event handler (#113)
    • b594c48 Bump github.com/slack-go/slack from 0.11.0 to 0.11.2
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Jul 26, 2022)

  • v0.1.1(Jul 16, 2022)

  • v0.1.0(Jul 4, 2022)

    Changelog

    Features

    • 947ccde feat: Allow custom bot command constructor
    • 106f32c feat: Allow custom bot context creation
    • bd2baec feat: Allow hiding of commands from help menu

    Bug fixes

    • a9669da fix: Do not set TimeStamps for SlashCommands
    • da1a1f5 fix: Slacker.Interactive is not honored
    • b3d6caf fix: Update example 19 to match bot command interface
    • 5ceecde fix: Use default event handler when set

    Others

    • 3318efb Bump slack-go/slack to v0.11.0
    • 6968614 refactor: Split MessageEvent into message_event.go
    Source code(tar.gz)
    Source code(zip)
Owner
Raed Shomali
A Software Engineer by Profession, a Photographer by Talent and a Joker by Nature.
Raed Shomali
This slack-bot collects all @gophers notifications into one slack channel

slack-bot Slack bot copying reference to a ping to notifications channel The bot is designed to listen on messages containing specific tag, copy refer

Kyma Incubator 2 Apr 11, 2022
Slack Bot Framework

slacker Built on top of the Slack API github.com/slack-go/slack with the idea to simplify the Real-Time Messaging feature to easily create Slack Bots,

Raed Shomali 717 Dec 25, 2022
Slack bot core/framework written in Go with support for reactions to message updates/deletes

Overview Requirements Features Demo The Name Concepts Create Your Own Slackscot Assembling the Parts and Bringing Your slackscot to Life Configuration

Alexandre Normand 54 Oct 28, 2022
Bot-template - A simple bot template for creating a bot which includes a config, postgresql database

bot-template This is a simple bot template for creating a bot which includes a c

Disgo 2 Sep 9, 2022
IRC, Slack, Telegram and RocketChat bot written in go

go-bot IRC, Slack & Telegram bot written in Go using go-ircevent for IRC connectivity, nlopes/slack for Slack and Syfaro/telegram-bot-api for Telegram

null 768 Dec 20, 2022
🦎 A slack bot for random gex quotes

?? A slack bot for random gex quotes

Matt Gleich 4 Jan 3, 2022
Golang bot that connects to slack using Socketclient to read and write messages.

?? (not)simple go project ?? Golang bot that connects to slack using Socketclient to read and write messages. ?? Use ?? @SquidBot : Mentions your name

Malin J. 1 Aug 23, 2022
Snitch - a Slack bot that fetches pending review PRs built in Go

Snitch Snitch is a Slack bot that fetches and publish PRs with pendings reviews

Eze Olea Figueroa 6 Nov 29, 2022
A serverless bot which periodically checks configured BigQuery capacity commitments, reservations and assignments against actual slot consumption of running jobs and reports findings to Slack/Google Chat.

Solution Guide This solution implements a ChatOps-like approach to monitoring slot utilization of Google Cloud BigQuery reservations. As an alternativ

Google Cloud Platform 10 Dec 7, 2022
CultureBot - A slack bot used to act as a companion to new people in tech

Culture Bot A slack bot used to act as a companion to new people in tech. Helps

Reginald Davis 2 Feb 6, 2022
Golang Framework for writing Slack bots

hanu - Go for Slack Bots! The Go framework hanu is your best friend to create Slack bots! hanu uses allot for easy command and request parsing (e.g. w

Sebastian Müller 142 Oct 24, 2022
A bot based on Telegram Bot API written in Golang allows users to download public Instagram photos, videos, and albums without receiving the user's credentials.

InstagramRobot InstagramRobot is a bot based on Telegram Bot API written in Golang that allows users to download public Instagram photos, videos, and

FTC Team 8 Dec 16, 2021
Dlercloud-telegram-bot - A Telegram bot for managing your Dler Cloud account

Dler Cloud Telegram Bot A Telegram bot for managing your Dler Cloud account. Usa

Beta Kuang 1 Dec 30, 2021
Quote-bot - Un bot utilisant l'API Twitter pour tweeter une citation par jour sur la programmation et les mathématiques.

Description Ceci est un simple bot programmé en Golang qui tweet une citation sur la programmation tout les jours. Ce bot est host sur le compte Twitt

Liam Cornu 0 Jan 1, 2022
Discord-bot - A Discord bot with golang

JS discord bots Install Clone repo git clone https://github.com/fu-js/discord-bo

JS Club 4 Aug 2, 2022
Bot - Telegram Music Bot in Go

Telegram Music Bot in Go An example bot using gotgcalls. Setup Install the serve

null 9 Jun 28, 2022
Pro-bot - A telegram bot to play around with the community telegram channels

pro-bot ?? Pro Bot A Telegram Bot to Play Around With The Community Telegram Cha

TechProber 1 Jan 24, 2022
Sex-bot - The sex bot and its uncreative responses

Sex Bot The sex bot, made with golang! The sex bot can't hear the word "sexo" he

Marcos Vas 3 Nov 11, 2022
Feline-bot - Feline Bot for Discord using Golang

Feline Bot for Discord Development This bot is implemented using Golang. Feature

null 0 Feb 10, 2022