I'm trying to add an attachment to a slack message via their API. I'm using the python wrapper they recommend. I can send and receive basic messages but when I try to add an attachment in the form of 2 buttons it fails. I have made a slack app and linked the bot as they state in their API. I've carefully reviewed the API and cannot figure out what is going on.
def process_message(message, channel):
intro_msg = json.loads('{
"text": "What would you like to do?",
"attachments": [
{
"text": "Choose an action",
"fallback": "You are unable to choose an option",
"callback_id": "lunch_intro",
"color": "#3AA3E3",
"attachment_type": "default",
"actions": [
{
"name": "enroll",
"text": "Enroll",
"type": "button",
"value": "enroll"
},
{
"name": "leave",
"text": "Leave",
"type": "button",
"value": "leave"
}
]
}
]
}')
r = sc.api_call("chat.postMessage", channel=channel, attachments=intro_msg)
The response is only {u'ok': False, u'error': u'no_text'}
I figured it out.
The python wrapper separates out the payload.
intro_msg = json.dumps([{"text":"Choose an action","fallback":"You are unable to choose an option","callback_id":"lunch_intro","color":"#3AA3E3","attachment_type":"default","actions":[{"name":"enroll","text":"Enroll","type":"button","value":"enroll"},{"name":"leave","text":"Leave","type":"button","value":"leave"}]}])
sc.api_call("chat.postMessage", channel=channel, text="What would you like to do?", attachments=intro_msg, as_user=True)
My payload was all in attachments since that is how they format it in their API docs. The attachments needs to just be the array after the attachments key.
I guess the basic simple example works.
Example:
from slackclient import SlackClient
slack_token = os.environ["SLACK_API_TOKEN"]
sc = SlackClient(slack_token)
sc.api_call(
"chat.postMessage",
channel="#python",
text="Hello from Python! :tada:"
)
According to https://api.slack.com/methods/chat.postMessage and https://api.slack.com/docs/message-buttons#readying_your_application_for_message_buttons the attachments has to be an array. How about sending it as array:
json.loads('[{"text":"What would you like to do?","attachments":[{"text":"Choose an action","fallback":"You are unable to choose an option","callback_id":"lunch_intro","color":"#3AA3E3","attachment_type":"default","actions":[{"name":"enroll","text":"Enroll","type":"button","value":"enroll"},{"name":"leave","text":"Leave","type":"button","value":"leave"}]}]}]')
As there is no further magic involved but the requests module https://github.com/slackapi/python-slackclient/blob/ddf9d8f5803040f0397d68439d3217d1e1340d0a/slackclient/_slackrequest.py I'd give it a try with the sending as array.
Related
I'm trying to create my first slack bot with python.
I need your help to explain how I can get the value of the datepicker.
This is my code :
import os
from slack import WebClient
from slack.errors import SlackApiError
import time
client = WebClient(token=os.environ['SLACK_KEY'])
message = "Hey ! Pourrais-tu saisir la date de tes congés ce mois-ci ?"
attachments = [{
"blocks": [
{
"type": "actions",
"elements": [
{
"type": "datepicker",
"initial_date": "1990-04-28",
"placeholder": {
"type": "plain_text",
"text": "Select a date",
}
},
{
"type": "datepicker",
"initial_date": "1990-04-28",
"placeholder": {
"type": "plain_text",
"text": "Select a date",
}
}
]
}
]
}]
def list_users():
users_call = client.api_call("users.list")
if users_call.get('ok'):
return users_call['members']
return None
def send_message(userid):
response = client.chat_postMessage(channel=userid, text=message, username='groupadamin', attachments=attachments)
if __name__ == '__main__':
users = list_users()
if users:
for u in users:
send_message(u['id'])
print("Success!")
My bot sends a private message to all users of the slack. I want to get every one of their answers of the datepicker.
If you want more details, ask me.
In general, you need to be listening to the action.
When the use clicks the datetimepicker, a so-called interaction-payload will be sent to your python slackbot.
That payload is documented here https://api.slack.com/reference/interaction-payloads/block-actions ; you can see you can get the picked date's value by accessing actions.value.
In particular for your use case, given your code sample, it seems you've just built a script that can send messages. This will not allow you to listen to actions. You need rather a python service (an API) that can send as well as receive messages.
For this, I suggest having a look at bolt which is a slack maintained library that will take care of a lot of the heavy lifting for you. Specifically, regarding actions you can check https://slack.dev/bolt-python/concepts#action-listening
So I have been playing around with python and Discord's webhook with Slacks message formatting which can be found here: Slack message formatting
However what I am trying to do is to have a multiply URL that can be sent to slack similar like:
and now when I have added all my URL to a list and trying to apply it to the formatting etc:
{
"username": "Google website",
"attachments": [
{
"author_name": "Google",
"color": "#00ff00",
"text": "^Press the link above!",
"title": "www.google.se",
"title_link": URLLIST
}
]
}
It tells me that "Must be str, not a list"
And I have been stuck on this since there is not pretty good documentation about this, Anyone that could know how to do this?
I am guessing you are getting the error, because your URLLIST is not a string.
Here are two solution that will work:
Either you do multiple attachments, where every attachment is one link. Then title_link must be a URL string, not a list.
Example:
{
"attachments": [
{
"fallback": "Required plain-text summary of the attachment.",
"title": "Slack API Documentation",
"title_link": "https://api.slack.com/"
},
{
"fallback": "Required plain-text summary of the attachment.",
"title": "Slack API Documentation",
"title_link": "https://api.slack.com/"
},
{
"fallback": "Required plain-text summary of the attachment.",
"title": "Slack API Documentation",
"title_link": "https://api.slack.com/"
}
]
}
Message Builder Example
Or you just explode your URL list into a text string (which I would do). Then you do not even need attachments.
Example:
{
"text": "<https://www.google.com|8>\n<https://www.google.com|9>\n<https://www.google.com|10>\n"
}
Message Builder Example
How to receive attachment actions using python SlackClient. How to get user's reply?
Code :
intro_msg = json.dumps([{"text": "Choose an action", "fallback": "You are unable to choose an option",
"callback_id": "lunch_intro", "color": "#3AA3E3", "attachment_type": "default",
"actions": [
{"name": "enroll", "text": "Enroll", "type": "button", "value": "enroll"},
{"name": "leave", "text": "Leave", "type": "button", "value": "leave"}]}])
result = self.sc.api_call("chat.postMessage", channel=channel, text="What would you like to do?",attachments=intro_msg,as_user=True)
https://api.slack.com/interactive-messages
Define a Slack app
Your app (Python script) needs to run on a public webserver that can be reached by Slack (can also by your local machine if you use tools like ngrok)
Put the URL for your app as "request URL" in your Slack app configuration under "Interactive messages"
Once the user clicks one of the button, Slack will call your app with a POST request which will contain the action that the use chose
Check out the documentation you linked for details like how the data structure of the Slack request looks like.
I'm trying to send an attachment using Slack's Python Client but whenever I do I fail. I tried sending it with the Tester too but it still didn't work. Either I get {"ok": false,"error": "no_text"} or if I have the text property only the text is going to be sent. This is how I do it. I searched too but didn't found anything.
attachment = json.dumps([{"attachments": [{"fallback": "Reddit Message","color": "#448aff","pretext":"You've got a new Message!","author_name": "Reddit","author_link": "https://reddit.com","author_icon": "imageurl","title": "Reddit Message","title_link": "https://reddit.com/message/inbox","text": "This is what I know about it.","fields": [{"title": "Author:","value": str(item.author),"short": "true"},{"title": "Subject: ","value": str(item.subject),"short": "true"},{"title": "Message:","value": str(item.body),"short": "false"}],"footer": "Reddit API","footer_icon": "anotherimageurl"}]})
sc.api_call("chat.postMessage",channel="U64KWRJAU",attachments=attachment,as_user=True)
Help would be appreciated. This should make sense but I don't get it why it doesn't work
From your reference, you need to pass attachment as a list. You won't need to have the attachments key in a dict containing the list.
attachment = json.dumps([
{
"fallback": "Reddit Message",
"color": "#448aff",
"pretext":"You've got a new Message!",
"author_name": "Reddit",
"author_link": "https://reddit.com",
....
}
])
sc.api_call(
"chat.postMessage", channel="U64KWRJAU",
attachments=attachment, as_user=True)
I met the same issue and found the solution.
The problem is that if only attachments field is added into the payload, it will report no_text error. But if text field is added, slack message will only show the text content.
The solution:
When we want to display attachments, we need to add a basic blocks field instead of text field. Something like
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "bar"
}
}
],
"attachments": [
{
"color": "#FF0000",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "foo"
}
}
]
}
]
}
If putting the above payload into the Slack build kit, it will be a misleading. That's also why I stuck with the issue.
I would recommend to use chat.postMessage test to debug the payload. It will work like a charm.
https://stackoverflow.com/a/72036841/3409400
I would like to add a share button for social media. I've got the Slack workflow buttons working, but I'd like those receiving the message payload to be able to share what they're receiving. Here's what I've got so far.
def post_summary_to_slack(self):
data = str(
{'text': self.summary_printout,
'attachments': [
{
"fallback": "Was this a good use of time and money?",
"title": "Was this a good use of time and money?",
"callback_id": "meetings_survey",
"color": "#800080",
"attachment_type": "default",
"actions": [
{
"name": "yes",
"text": "Yes",
"type": "button",
"value": "yes"
},
{
"name": "no",
"text": "No",
"type": "button",
"value": "no"
},
{
"name": "maybe",
"text": "I'm Not Sure",
"type": "button",
"value": "maybe"
},
/* maybe here:*/
{
"name": "twitter",
"text": "Tweet",
"type": "button",
"value": "Here are the results from the latest analysis"
}
]
}
]
}
)
url = self.SLACK_HOOK
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
f.close()
Has anybody tried something like this? Thanks for the help!
Sure you can do that. However, Slack does not provide a Twitter share button out-of-the-box, so your script will need to implement that functionality. So your Twitter share button will call your script (like any other message button) and your script will need to forward the message contents to Twitter by calling the correct Twitter APIs etc.