-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add functions.completeError and functions.completeSuccess #1301
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/slack-go/slack" | ||
"github.com/slack-go/slack/slackevents" | ||
"github.com/slack-go/slack/socketmode" | ||
"os" | ||
) | ||
|
||
func main() { | ||
api := slack.New( | ||
os.Getenv("SLACK_BOT_TOKEN"), | ||
slack.OptionDebug(true), | ||
slack.OptionAppLevelToken(os.Getenv("SLACK_APP_TOKEN")), | ||
) | ||
client := socketmode.New(api, socketmode.OptionDebug(true)) | ||
|
||
go func() { | ||
for evt := range client.Events { | ||
switch evt.Type { | ||
case socketmode.EventTypeEventsAPI: | ||
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent) | ||
if !ok { | ||
fmt.Printf("Ignored %+v\n", evt) | ||
continue | ||
} | ||
|
||
fmt.Printf("Event received: %+v\n", eventsAPIEvent) | ||
client.Ack(*evt.Request) | ||
|
||
switch eventsAPIEvent.Type { | ||
case slackevents.CallbackEvent: | ||
innerEvent := eventsAPIEvent.InnerEvent | ||
switch ev := innerEvent.Data.(type) { | ||
case *slackevents.FunctionExecutedEvent: | ||
callbackID := ev.Function.CallbackID | ||
if callbackID == "sample_function" { | ||
userId := ev.Inputs["user_id"] | ||
payload := map[string]string{ | ||
"user_id": userId, | ||
} | ||
|
||
err := api.FunctionCompleteSuccess(ev.FunctionExecutionID, slack.FunctionCompleteSuccessRequestOptionOutput(payload)) | ||
if err != nil { | ||
fmt.Printf("failed posting message: %v \n", err) | ||
} | ||
} | ||
} | ||
default: | ||
client.Debugf("unsupported Events API event received\n") | ||
} | ||
|
||
default: | ||
fmt.Fprintf(os.Stderr, "Unexpected event type received: %s\n", evt.Type) | ||
} | ||
} | ||
}() | ||
client.Run() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ | ||
"display_information": { | ||
"name": "Function Example" | ||
}, | ||
"features": { | ||
"app_home": { | ||
"home_tab_enabled": false, | ||
"messages_tab_enabled": true, | ||
"messages_tab_read_only_enabled": true | ||
}, | ||
"bot_user": { | ||
"display_name": "Function Example", | ||
"always_online": true | ||
} | ||
}, | ||
"oauth_config": { | ||
"scopes": { | ||
"bot": [ | ||
"chat:write" | ||
] | ||
} | ||
}, | ||
"settings": { | ||
"interactivity": { | ||
"is_enabled": true | ||
}, | ||
"org_deploy_enabled": true, | ||
"socket_mode_enabled": true, | ||
"token_rotation_enabled": false | ||
}, | ||
"functions": { | ||
"sample_function": { | ||
"title": "Sample function", | ||
"description": "Runs sample function", | ||
"input_parameters": { | ||
"user_id": { | ||
"type": "slack#/types/user_id", | ||
"title": "User", | ||
"description": "Message recipient", | ||
"is_required": true, | ||
"hint": "Select a user in the workspace", | ||
"name": "user_id" | ||
} | ||
}, | ||
"output_parameters": { | ||
"user_id": { | ||
"type": "slack#/types/user_id", | ||
"title": "User", | ||
"description": "User that completed the function", | ||
"is_required": true, | ||
"name": "user_id" | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package slack | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
) | ||
|
||
type ( | ||
FunctionCompleteSuccessRequest struct { | ||
FunctionExecutionID string `json:"function_execution_id"` | ||
Outputs map[string]string `json:"outputs"` | ||
} | ||
|
||
FunctionCompleteErrorRequest struct { | ||
FunctionExecutionID string `json:"function_execution_id"` | ||
Error string `json:"error"` | ||
} | ||
) | ||
|
||
type FunctionCompleteSuccessRequestOption func(opt *FunctionCompleteSuccessRequest) error | ||
|
||
func FunctionCompleteSuccessRequestOptionOutput(outputs map[string]string) FunctionCompleteSuccessRequestOption { | ||
return func(opt *FunctionCompleteSuccessRequest) error { | ||
if len(outputs) > 0 { | ||
opt.Outputs = outputs | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
// FunctionCompleteSuccess indicates function is completed | ||
func (api *Client) FunctionCompleteSuccess(functionExecutionId string, options ...FunctionCompleteSuccessRequestOption) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe the API method returns a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
// More information: https://api.slack.com/methods/functions.completeSuccess | ||
r := &FunctionCompleteSuccessRequest{ | ||
FunctionExecutionID: functionExecutionId, | ||
} | ||
for _, option := range options { | ||
option(r) | ||
} | ||
|
||
endpoint := api.endpoint + "functions.completeSuccess" | ||
jsonData, err := json.Marshal(r) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
response := &SlackResponse{} | ||
if err := postJSON(context.Background(), api.httpclient, endpoint, api.token, jsonData, response, api); err != nil { | ||
return err | ||
} | ||
|
||
if !response.Ok { | ||
return response.Err() | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// FunctionCompleteError indicates function is completed with error | ||
func (api *Client) FunctionCompleteError(functionExecutionID string, errorMessage string) error { | ||
// More information: https://api.slack.com/methods/functions.completeError | ||
r := FunctionCompleteErrorRequest{ | ||
FunctionExecutionID: functionExecutionID, | ||
} | ||
r.Error = errorMessage | ||
|
||
endpoint := api.endpoint + "functions.completeError" | ||
jsonData, err := json.Marshal(r) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
response := &SlackResponse{} | ||
if err := postJSON(context.Background(), api.httpclient, endpoint, api.token, jsonData, response, api); err != nil { | ||
return err | ||
} | ||
|
||
if !response.Ok { | ||
return response.Err() | ||
} | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -649,6 +649,51 @@ type SharedInvite struct { | |
IsExternalLimited bool `json:"is_external_limited,omitempty"` | ||
} | ||
|
||
// FunctionExecutedEvent is sent if a function was executed - https://api.slack.com/events/function_executed | ||
type FunctionExecutedEvent struct { | ||
Type string `json:"type"` | ||
Function Function `json:"function"` | ||
Inputs map[string]string `json:"inputs"` | ||
FunctionExecutionID string `json:"function_execution_id"` | ||
WorkflowExecutionID string `json:"workflow_execution_id"` | ||
EventTs string `json:"event_ts"` | ||
BotAccessToken string `json:"bot_access_token"` | ||
} | ||
|
||
// Function is a struct for functions in FunctionExecuted events | ||
type Function struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where did you find the documentation for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I got it from the debug mode of the slack-go socket mode, because before that I had not found the official documentation |
||
Id string `json:"id"` | ||
CallbackID string `json:"callback_id"` | ||
Title string `json:"title"` | ||
Description string `json:"description"` | ||
Type string `json:"type"` | ||
InputParameters []InputParameters `json:"input_parameters"` | ||
OutputParameters []OutputParameters `json:"output_parameters"` | ||
AppId string `json:"app_id"` | ||
DateCreated int `json:"date_created"` | ||
DateReleased int `json:"date_released"` | ||
DateUpdated int `json:"date_updated"` | ||
DateDeleted int `json:"date_deleted"` | ||
FormEnabled bool `json:"form_enabled"` | ||
} | ||
|
||
// InputParameters is a struct for input parameters in Function events | ||
type InputParameters struct { | ||
Type string `json:"type"` | ||
Name string `json:"name"` | ||
Description string `json:"description"` | ||
Title string `json:"title"` | ||
IsRequired bool `json:"is_required"` | ||
} | ||
|
||
// OutputParameters is a struct for output parameters in Function events | ||
type OutputParameters struct { | ||
Type string `json:"type"` | ||
Name string `json:"name"` | ||
Description string `json:"description"` | ||
Title string `json:"title"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe there is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i will update it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but why when I activate debug mode this value is not there? |
||
} | ||
|
||
type EventsAPIType string | ||
|
||
const ( | ||
|
@@ -738,6 +783,8 @@ const ( | |
TeamAccessRevoked = EventsAPIType("team_access_revoked") | ||
// UserProfileChanged is sent if a user's profile information has changed. | ||
UserProfileChanged = EventsAPIType("user_profile_changed") | ||
// FunctionExecuted is sent if a function was executed | ||
FunctionExecuted = EventsAPIType("function_executed") | ||
) | ||
|
||
// EventsAPIInnerEventMapping maps INNER Event API events to their corresponding struct | ||
|
@@ -787,4 +834,5 @@ var EventsAPIInnerEventMapping = map[EventsAPIType]interface{}{ | |
TeamAccessGranted: TeamAccessGrantedEvent{}, | ||
TeamAccessRevoked: TeamAccessRevokedEvent{}, | ||
UserProfileChanged: UserProfileChangedEvent{}, | ||
FunctionExecuted: FunctionExecutedEvent{}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please ensure that the WebAPI functions accept a context as the first function parameter and rename this
FunctionCompleteErrorContext
. You can create a second function calledFunctionCompleteError
that explicitly setscontact.Background()
if you'd like.You can look at ListEventAuthorizationsContext and ListEventAuthorizations for an example of how to implement it.