You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
7.9 KiB
233 lines
7.9 KiB
package slack
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"rodleyserverbot/slack-bot/config"
|
|
"github.com/slack-go/slack"
|
|
"github.com/slack-go/slack/slackevents"
|
|
"github.com/slack-go/slack/socketmode"
|
|
)
|
|
|
|
func Start() {
|
|
// Create a new client to slack by giving token
|
|
// Set debug to true while developing
|
|
// Also add a ApplicationToken option to the client
|
|
client := slack.New(
|
|
config.Config.SlackAuthToken,
|
|
slack.OptionDebug(false),
|
|
slack.OptionAppLevelToken(config.Config.SlackAppToken))
|
|
// go-slack comes with a SocketMode package that we need to use that accepts a Slack client and outputs a Socket mode client instead
|
|
socketClient := socketmode.New(
|
|
client,
|
|
socketmode.OptionDebug(false),
|
|
// Option to set a custom logger
|
|
socketmode.OptionLog(log.New(os.Stdout, "socketmode: ", log.Lshortfile|log.LstdFlags)),
|
|
)
|
|
|
|
// Create a context that can be used to cancel goroutine
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
// Make this cancel called properly in a real program , graceful shutdown etc
|
|
defer cancel()
|
|
|
|
go func(ctx context.Context, client *slack.Client, socketClient *socketmode.Client) {
|
|
// Create a for loop that selects either the context cancellation or the events incomming
|
|
for {
|
|
select {
|
|
// inscase context cancel is called exit the goroutine
|
|
case <-ctx.Done():
|
|
log.Println("Shutting down socketmode listener")
|
|
return
|
|
case event := <-socketClient.Events:
|
|
// We have a new Events, let's type switch the event
|
|
// Add more use cases here if you want to listen to other events.
|
|
switch event.Type {
|
|
// handle EventInteractive events
|
|
case socketmode.EventTypeInteractive:
|
|
//fmt.Println("Recivimos un Interactive!", event)
|
|
|
|
callback, ok := event.Data.(slack.InteractionCallback)
|
|
|
|
if !ok {
|
|
log.Printf("Could not type cast the event to the MessageAction: %v\n", event)
|
|
continue
|
|
}
|
|
socketClient.Ack(*event.Request)
|
|
switch callback.Type {
|
|
case slack.InteractionTypeInteractionMessage:
|
|
//fmt.Println("type:", callback.Type, "callBackId:", callback.CallbackID, "aactions[0]", *callback.ActionCallback.AttachmentActions[0])
|
|
action := *callback.ActionCallback.AttachmentActions[0]
|
|
//fmt.Println("Value:", action.Value)
|
|
var output string
|
|
var err error
|
|
output, err = executeAction(action.Value)
|
|
if err == nil {
|
|
finalMessage := fmt.Sprintf("Chi chi chi chi amo!\n*Output*\n```\n%s\n```", output)
|
|
replyToAction(callback.Channel.ID, finalMessage, client)
|
|
}
|
|
case slack.InteractionTypeMessageAction:
|
|
//fmt.Println("is a message action?")
|
|
|
|
case slack.InteractionTypeBlockActions:
|
|
// See https://api.slack.com/apis/connections/socket-implement#button
|
|
|
|
//fmt.Println("button clicked!")
|
|
case slack.InteractionTypeShortcut:
|
|
case slack.InteractionTypeViewSubmission:
|
|
// See https://api.slack.com/apis/connections/socket-implement#modal
|
|
case slack.InteractionTypeDialogSubmission:
|
|
default:
|
|
//fmt.Println("Don't know what type it is")
|
|
}
|
|
// handle EventAPI events
|
|
case socketmode.EventTypeEventsAPI:
|
|
// The Event sent on the channel is not the same as the EventAPI events so we need to type cast it
|
|
eventsAPIEvent, ok := event.Data.(slackevents.EventsAPIEvent)
|
|
if !ok {
|
|
// log.Printf("Could not type cast the event to the EventsAPIEvent: %v\n", event)
|
|
continue
|
|
}
|
|
// We need to send an Acknowledge to the slack server
|
|
socketClient.Ack(*event.Request)
|
|
// Now we have an Events API event, but this event type can in turn be many types, so we actually need another type switch
|
|
// log.Println("EventsAPIEvent:", eventsAPIEvent)
|
|
err := handleEventMessage(eventsAPIEvent, client)
|
|
if err != nil {
|
|
// Replace with actual err handeling
|
|
// log.Fatal(err)
|
|
}
|
|
default:
|
|
//fmt.Println("Event received no matching TYPE:", event.Type, "event:", event)
|
|
}
|
|
|
|
}
|
|
}
|
|
}(ctx, client, socketClient)
|
|
|
|
socketClient.Run()
|
|
}
|
|
|
|
// handleEventMessage will take an event and handle it properly based on the type of event
|
|
func handleEventMessage(event slackevents.EventsAPIEvent, client *slack.Client) error {
|
|
switch event.Type {
|
|
// First we check if this is an CallbackEvent
|
|
case slackevents.CallbackEvent:
|
|
|
|
innerEvent := event.InnerEvent
|
|
// fmt.Println("We received an event!", innerEvent)
|
|
// Yet Another Type switch on the actual Data to see if its an AppMentionEvent
|
|
switch ev := innerEvent.Data.(type) {
|
|
case *slackevents.AppMentionEvent:
|
|
// The application has been mentioned since this Event is a Mention event
|
|
//log.Println("App Mentioned!", ev)
|
|
handleAppMentionEvent(ev, client)
|
|
case *slackevents.MessageEvent:
|
|
//log.Println("MessageEvent!", ev)
|
|
handleAppMessagedEvent(ev, client)
|
|
default:
|
|
//fmt.Println("Not handled EventMessage!:", ev)
|
|
}
|
|
default:
|
|
return errors.New("unsupported event type")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func executeAction(actionName string) (string, error) {
|
|
fmt.Println("executeAction actionName:", actionName, "actions:", config.Config.Actions)
|
|
var output_str string
|
|
for _, action := range config.Config.Actions {
|
|
if action.Name == actionName {
|
|
cmd := exec.Command("/bin/bash", action.Path)
|
|
output, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
fmt.Printf("error %s", err)
|
|
return "", err
|
|
}
|
|
output_str = string(output)
|
|
}
|
|
}
|
|
return output_str, nil
|
|
}
|
|
|
|
func replyToAction(channelName string, message string, client *slack.Client) error {
|
|
//fmt.Println("replyToAction channel:", channelName, "Message:", message)
|
|
attachment := slack.Attachment{}
|
|
attachment.Text = message
|
|
attachment.Color = "#4af030"
|
|
_, _, err := client.PostMessage(channelName, slack.MsgOptionAttachments(attachment))
|
|
if err != nil {
|
|
//fmt.Println("failed to post message:", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getAttachmentButtons() []slack.AttachmentAction{
|
|
var actions []slack.AttachmentAction
|
|
for _, action := range config.Config.Actions {
|
|
slackAction := slack.AttachmentAction{}
|
|
slackAction.Name = action.Name
|
|
slackAction.Value = action.Name
|
|
slackAction.Text = action.DisplayName
|
|
slackAction.Type = "button"
|
|
actions=append(actions, slackAction)
|
|
}
|
|
return actions
|
|
}
|
|
|
|
func handleAppMessagedEvent(event *slackevents.MessageEvent, client *slack.Client) error {
|
|
//fmt.Println("handleAppMessagedEvent event:", event, "BotID:", event.BotID)
|
|
if event.BotID != "" {
|
|
// We're not interested in messages from ourselves or other bots
|
|
return nil
|
|
}
|
|
attachment := slack.Attachment{}
|
|
var err error
|
|
attachment.CallbackID = "server_action"
|
|
// Send a message to the user
|
|
attachment.Text = "Por el momento esto es lo que se hacer"
|
|
attachment.Pretext = fmt.Sprintf("Como te puedo ayudar?")
|
|
attachment.Color = "#3d3d3d"
|
|
actions := getAttachmentButtons()
|
|
attachment.Actions = actions
|
|
|
|
// Send the message to the channel
|
|
// The Channel is available in the event message
|
|
_, _, err = client.PostMessage(event.Channel, slack.MsgOptionAttachments(attachment))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to post message: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// handleAppMentionEvent is used to take care of the AppMentionEvent when the bot is mentioned
|
|
func handleAppMentionEvent(event *slackevents.AppMentionEvent, client *slack.Client) error {
|
|
// fmt.Println("handleAppMentionEvent event:", event)
|
|
|
|
var err error
|
|
// Create the attachment and assigned based on the message
|
|
attachment := slack.Attachment{}
|
|
attachment.CallbackID = "server_action"
|
|
|
|
// Send a message to the user
|
|
attachment.Text = "Por el momento esto es lo que se hacer"
|
|
attachment.Pretext = fmt.Sprintf("Como te puedo ayudar?")
|
|
attachment.Color = "#3d3d3d"
|
|
actions := getAttachmentButtons()
|
|
//fmt.Println(actions)
|
|
attachment.Actions = actions
|
|
|
|
// Send the message to the channel
|
|
// The Channel is available in the event message
|
|
_, _, err = client.PostMessage(event.Channel, slack.MsgOptionAttachments(attachment))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to post message: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|