diff --git a/examples/interaction-view/main.go b/examples/interaction-view/main.go new file mode 100644 index 0000000..abe699b --- /dev/null +++ b/examples/interaction-view/main.go @@ -0,0 +1,111 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/shomali11/slacker/v2" + "github.com/slack-go/slack" +) + +var moodSurveyView = slack.ModalViewRequest{ + Type: "modal", + CallbackID: "mood-survey-callback-id", + Title: &slack.TextBlockObject{ + Type: "plain_text", + Text: "Which mood are you in?", + }, + Submit: &slack.TextBlockObject{ + Type: "plain_text", + Text: "Submit", + }, + NotifyOnClose: true, + Blocks: slack.Blocks{ + BlockSet: []slack.Block{ + &slack.InputBlock{ + Type: slack.MBTInput, + BlockID: "mood", + Label: &slack.TextBlockObject{ + Type: "plain_text", + Text: "Mood", + }, + Element: &slack.SelectBlockElement{ + Type: slack.OptTypeStatic, + ActionID: "mood", + Options: []*slack.OptionBlockObject{ + { + Text: &slack.TextBlockObject{ + Type: "plain_text", + Text: "Happy", + }, + Value: "Happy", + }, + { + Text: &slack.TextBlockObject{ + Type: "plain_text", + Text: "Sad", + }, + Value: "Sad", + }, + }, + }, + }, + }, + }, +} + +// Implements a basic interactive command with modal view. +func main() { + bot := slacker.NewClient( + os.Getenv("SLACK_BOT_TOKEN"), + os.Getenv("SLACK_APP_TOKEN"), + slacker.WithDebug(false), + ) + + bot.AddCommand(&slacker.CommandDefinition{ + Command: "mood", + Handler: moodCmdHandler, + }) + + bot.AddInteraction(&slacker.InteractionDefinition{ + CallbackID: "mood-survey-callback-id", + Handler: moodViewHandler, + }) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + err := bot.Listen(ctx) + if err != nil { + log.Fatal(err) + } +} + +func moodCmdHandler(ctx *slacker.CommandContext) { + _, err := ctx.SlackClient().OpenView( + ctx.Event().Data.(*slack.SlashCommand).TriggerID, + moodSurveyView, + ) + if err != nil { + log.Printf("ERROR openEscalationModal: %v", err) + } +} + +func moodViewHandler(ctx *slacker.InteractionContext) { + switch ctx.Callback().Type { + case slack.InteractionTypeViewSubmission: + { + viewState := ctx.Callback().View.State.Values + fmt.Printf( + "Mood view submitted.\nMood: %s\n", + viewState["mood"]["mood"].SelectedOption.Value, + ) + } + case slack.InteractionTypeViewClosed: + { + fmt.Print("Mood view closed.\n") + } + } +} diff --git a/interaction.go b/interaction.go index bc96a00..2485e1e 100644 --- a/interaction.go +++ b/interaction.go @@ -3,6 +3,7 @@ package slacker // InteractionDefinition structure contains definition of the bot interaction type InteractionDefinition struct { BlockID string + CallbackID string Middlewares []InteractionMiddlewareHandler Handler InteractionHandler } diff --git a/slacker.go b/slacker.go index 290426c..a071a04 100644 --- a/slacker.go +++ b/slacker.go @@ -77,7 +77,7 @@ func (s *Slacker) GetCommandGroups() []*CommandGroup { return s.commandGroups } -// GetInteractions returns Groups +// GetInteractions returns Interactions func (s *Slacker) GetInteractions() []*Interaction { return s.interactions } @@ -174,8 +174,12 @@ func (s *Slacker) AddCommandGroup(prefix string) *CommandGroup { // AddInteraction define a new interaction and append it to the list of interactions func (s *Slacker) AddInteraction(definition *InteractionDefinition) { - if len(definition.BlockID) == 0 { - s.logger.Error("missing `BlockID`") + if len(definition.BlockID) == 0 && len(definition.CallbackID) == 0 { + s.logger.Error("missing `BlockID` or `CallbackID`") + return + } + if len(definition.BlockID) != 0 && len(definition.CallbackID) != 0 { + s.logger.Error("`BlockID` or `CallbackID` should not be set at the same time") return } s.interactions = append(s.interactions, newInteraction(definition)) @@ -437,21 +441,35 @@ func (s *Slacker) handleInteractionEvent(ctx context.Context, callback *slack.In middlewares := make([]InteractionMiddlewareHandler, 0) middlewares = append(middlewares, s.interactionMiddlewares...) - for _, interaction := range s.interactions { - for _, action := range callback.ActionCallback.BlockActions { + switch callback.Type { + case slack.InteractionTypeBlockActions: + for _, interaction := range s.interactions { definition := interaction.Definition() - if action.BlockID != definition.BlockID { - continue + for _, action := range callback.ActionCallback.BlockActions { + if action.BlockID == definition.BlockID { + interactionCtx := newInteractionContext(ctx, s.logger, s.slackClient, callback, definition) + middlewares = append(middlewares, definition.Middlewares...) + executeInteraction(interactionCtx, definition.Handler, middlewares...) + return + } } - - interactionCtx := newInteractionContext(ctx, s.logger, s.slackClient, callback, definition) - - middlewares = append(middlewares, definition.Middlewares...) - executeInteraction(interactionCtx, definition.Handler, middlewares...) - return } + s.logger.Debugf("unsupported block actions interaction type received %+v\n", callback) + case slack.InteractionTypeViewSubmission, + slack.InteractionTypeViewClosed: + for _, interaction := range s.interactions { + definition := interaction.Definition() + if definition.CallbackID == callback.View.CallbackID { + interactionCtx := newInteractionContext(ctx, s.logger, s.slackClient, callback, definition) + middlewares = append(middlewares, definition.Middlewares...) + executeInteraction(interactionCtx, definition.Handler, middlewares...) + return + } + } + s.logger.Debugf("unsupported interaction type received %+v\n", callback) + default: + s.logger.Debugf("unsupported interaction type received %+v\n", callback) } - if s.unsupportedInteractionHandler != nil { interactionCtx := newInteractionContext(ctx, s.logger, s.slackClient, callback, nil) executeInteraction(interactionCtx, s.unsupportedInteractionHandler, middlewares...)