Skip to content

Instantly share code, notes, and snippets.

@kbroughton
Created August 22, 2022 19:16
Show Gist options
  • Save kbroughton/e46edc3f6454c8dc33a09431b5685a6c to your computer and use it in GitHub Desktop.
Save kbroughton/e46edc3f6454c8dc33a09431b5685a6c to your computer and use it in GitHub Desktop.
Slack app demonstrating client.chat_postMessage using Block Kit
import json
import logging
import os
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
from slack_bolt import App, Ack
# WebClient instantiates a client that can call API methods
client = WebClient(token=os.environ.get("SLACK_BOT_TOKEN"))
logger = logging.getLogger(__name__)
# Initializes your app with your bot token and signing secret
app = App(
token=os.environ.get("SLACK_BOT_TOKEN"),
signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
)
def send_to_slack(message, channel_id):
try:
# Call the conversations.list method using the WebClient
if isinstance(message, dict) and 'blocks' in message:
message = message['blocks']
print('message', json.dumps(message))
result = client.chat_postMessage(
channel=channel_id,
text="dummy text if block fails",
blocks=message
#blocks=urllib.parse.quote(json.dumps(message))
)
else:
print('text', message)
result = client.chat_postMessage(
channel=channel_id,
text=message
)
# Print result, which includes information about the message (like TS)
print(result)
except SlackApiError as e:
print(f"Error: {e}")
# Listen for an action from a Block Kit element (buttons, select menus, date pickers, etc)
@app.action({"action_id": "my_bad"})
def action(ack: Ack, body, client):
print(ack, body, client)
print("my_bad")
ack()
if "container" in body and "message_ts" in body["container"]:
client.reactions_add(
name="white_check_mark",
channel=body["channel"]["id"],
timestamp=body["container"]["message_ts"]
)
return {"text": ":("}
@app.action({"action_id": "other_response_input_action"})
def other_response(ack: Ack, body, client):
print(ack, body, client)
print("other_response_input_action")
ack()
return {"text": ":)"}
def block_kit_view(alert):
return {
"type": "home",
"callback_id": "home_view",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"""
The following alert was attributed to you
{alert}"""
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "My bad, will fix",
"emoji": True
},
"value": "my_bad",
"action_id": "my_bad"
},
{
"type": "input",
"element": {
"type": "plain_text_input",
"multiline": True,
"action_id": "other_response_input_action"
},
"label": {
"type": "plain_text",
"text": "Other response / what button should we add?",
"emoji": True
},
"dispatch_action": True,
"block_id": "other_response"
}
]
}]
}
if __name__ == "__main__":
# ID of channel you want to post message to
channel_id = "<insert value>"
alert = "dummy"
message = block_kit_view(alert)
print(type(message), message)
send_to_slack(message, channel_id)
app.start(port=int(os.environ.get("PORT", 3000)))
@kbroughton
Copy link
Author

kbroughton commented Aug 22, 2022

The blocks can be built with Block Kit https://app.slack.com/block-kit-builder/
Unfortunately, the tool builds a "surface" with input blocks and it looks fine under "Message Preview" but
when run it errors out with

Error: The request to the Slack API failed. (url: https://www.slack.com/api/chat.postMessage)
The server responded with: {'ok': False, 'error': 'invalid_blocks', 'errors': ['unsupported type: input [json-pointer:/blocks/1/elements/1/type]'], 'response_metadata': {'messages': ['[ERROR] unsupported type: input [json-pointer:/blocks/1/elements/1/type]']}}

If you remove the lines 95 to 186 (and the preceding comma) then it works fine.

For this to work, you need to go to the slack UI for your app at https://api.slack.com/apps/
and in Oauth & Permissions chat:write and subscribe to events

And the request url on the https://api.slack.com/apps//event-subscriptions? page must point to your server
like https://XXX-YYY-140-102-115.ngrok.io/slack/events
The same is true of "Interactivity & Shortcuts" => https://api.slack.com/apps//interactive-messages?

If you are using ngrok as per the tutorial, note that each time you restart ngrok, you must replace these two values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment