unable to fetch json attribute in POST request - python

This Json is received as a POST request. Now
I want to get value of text key of each entry in actions array
I am using Python's Bottle to receive the request.
to fetch the value of required attribute, I did this
word = request.forms.get('[attachments][actions][0][text]')
But this doesn't print required value.
{
"attachments": [
{
"title": "XYZ",
"title_link": "EDWE",
"text": "dxjhvgebndm",
"fields": [
{
"title": "Food",
"value": "$20",
"short": true
}
],
"actions": [
{
"name": "chess",
"text": "Approve",
"type": "button",
"value": "chess",
"style": "primary"
},
{
"name": "maze",
"text": "Decline",
"style": "danger",
"type": "button",
"value": "maze"
},
{
"name": "war",
"text": "More details",
"style": "default",
"type": "button",
"value": "war",
"confirm": {
"title": "Are you sure?",
"text": "Would you like to see more details of your expense?",
"ok_text": "Yes",
"dismiss_text": "No"
}
}
],
"image_url": "",
"thumb_url": "https://i.imgsafe.org/cf40eef.png",
"footer": "fghj",
"footer_icon": "https://i.imgsafe.org/cf2e0eef.png",
"ts": 1475057533
}
]
}
Note: I am receiving complete JSON, the problem is in fetching correct attribute.
EDIT
Through this i am receiving POST request
import json
from bottle import route, run, request
import urllib
#route('/ocr_response', method='POST')
def ocr_response():
body = request.body.read()
word = request.forms.get('[attachments][actions][0][text]')
print word
print body
if __name__ == "__main__":
run(host='0.0.0.0', port=80, debug=True)

That's not how you access items in a dictionary at all.
Firstly, the JSON data is available via request.json. Secondly, I'm not sure what you're doing with that string you're passing to get, but you need to use normal dictionary/array syntax. And thirdly, attachments is a list just like actions, so you'd need to add an index there too.
request.json['attachments'][0]['actions'][0]['text']

Related

slack unfurling link with attachment blocks included

So my goal is to include an image, with buttons, in a message. However, the file is not public and files_upload method takes away the functionality of the buttons, issue similar to this https://github.com/slackapi/bolt-python/issues/411.
While working on the solution to 1. upload the file, 2. unfurl the permalink, I managed to make it work but the output is not what I would like:
I would like the unfurled link image to appear under the blocks while keeping the blocks in the attachment section. Is this achievable? Also, the only time I can unfurl is to include the link within the test section, can this be changed?
Sourcecode:
upload_resp = slack_client.files_upload(
initial_comment=uploadfiles["initial_comment"],
file=uploadfiles["file"],
filename=uploadfiles["filename"],
filetype=uploadfiles["filetype"],
title=uploadfiles["title"]
)
attachments = [
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Hi !*" ,
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Title*"
}
}
,{
"type": "actions",
"block_id": "actionblock",
"elements": [
{
"type": "button",
"action_id" : "rerun_action",
"text": {
"type": "plain_text",
"text": "Rerun",
"emoji": True
},
"style": "primary",
"value": "rerun"
},
{
"type": "button",
"action_id" : "launch_wizard",
"text": {
"type": "plain_text",
"text": "Launch Wizard",
"emoji": True
},
"style": "primary",
"value": "launch"
}
]
}
]
}
]
resp = slack_client.chat_postMessage(
channel=message["channel_id"],
text=upload_resp['file']['permalink'],
attachments = attachments,
blocks=[],
unfurl_links=True,
unfurl_media=True
)

Slack Application, pushing new modal based on selected option

I currently have my application to open a modal when a global shortcut is used. The modal opens and I am presented with 3 options. I was able to get it to push a new modal when any of the options were selected, but now I am stuck on how to open different modals based on the user response. Right now the code does not interpret which was selected, and just that an actionId-0 took place. I guess I am not really sure at the next steps. Do I need to utilize #app.view in order to read the submission payload?
Open on shortcut:
def open_modal(ack, shortcut, client):
# Acknowledge the shortcut request
ack()
# Call the views_open method using the built-in WebClient
client.views_open(
trigger_id=shortcut["trigger_id"],
# A simple view payload for a modal
view={
"title": {
"type": "plain_text",
"text": "#Tech Request"
},
"submit": {
"type": "plain_text",
"text": "Submit"
},
"type": "modal",
"close": {
"type": "plain_text",
"text": "Cancel"
},
"blocks": [
{
"type": "actions",
"elements": [
{
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Select an issue type"
},
"options": [
{
"text": {
"type": "plain_text",
"text": "Account Issues"
},
"value": "value-0"
},
{
"text": {
"type": "plain_text",
"text": "M1"
},
"value": "value-1"
},
{
"text": {
"type": "plain_text",
"text": "M2"
},
"value": "value-2"
}
],
"action_id": "actionId-0"
}
]
}
]
}
)
Open when any option is selected:
def update_modal(ack, body, client):
# Acknowledge the button request
ack()
# Call views_update with the built-in client
client.views_update(
# Pass the view_id
view_id=body["view"]["id"],
# String that represents view state to protect against race conditions
hash=body["view"]["hash"],
# View payload with updated blocks
view={
"title": {
"type": "plain_text",
"text": "Account Issue Request"
},
"submit": {
"type": "plain_text",
"text": "Submit"
},
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "This is a link to a confluence page"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Click Me",
},
"value": "click_me_123",
"url": "https://google.com",
"action_id": "button-action"
}
},
{
"type": "input",
"element": {
"type": "plain_text_input",
"action_id": "plain_text_input-action"
},
"label": {
"type": "plain_text",
"text": "SFDC Contact ID:",
}
},
{
"type": "input",
"element": {
"type": "plain_text_input",
"action_id": "plain_text_input-action"
},
"label": {
"type": "plain_text",
"text": "Describe the issue",
}
},
{
"type": "input",
"element": {
"type": "multi_users_select",
"placeholder": {
"type": "plain_text",
"text": "Tag related people",
},
"action_id": "multi_users_select-action"
},
"label": {
"type": "plain_text",
"text": "Tag related people",
}
}
],
"type": "modal"
}
)
This is something that you have to take care of on the backend. I found that the easiest way to do this is to parse the payload received and send back a modal based on that

Microsoft Teams bot Adaptive Cards Action is received in on_message_activity without data

My bot returns an adaptive card in 1:1 private chat with user, the adaptive card configuration is like this,
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": f"{jiradetail.summary}",
}
]
}
],
"actions": [
{
"type": "Action.ShowCard",
"title": "Comment",
"card": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Input.Text",
"id": "comment",
"isMultiline": True,
"placeholder": "Enter your comment"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "OK",
"data": "**jiraid**"
}
]
}
}
]
}
As you could see, there is a 'comment' textbox and a 'Ok' Action (type Action.Submit, and hidden data->jiraid), the card will be as shown below,
Now on click on this Ok button, I am receiving the activity in ,
on_message_activity, with the user entered value in the commentbox in the field,
turn_context.activity.value
but i couldnt get the hidden data which i mapped to the action button, the below picture shows the inspected value of 'turn_context.activity'.
How can i get the mapped data to this action?
Note: I was also expecting the callback to be, on_teams_messaging_extension_submit_action , but this callback is never called, instead only on_message_activity is called. I assume, its because its an 1:1 conversation and its not invoked via the messageextensions. Any experts please confirm.
Regarding "on_teams_messaging_extension_submit_action" - it's not because it's a 1-1, rather it's because it is NOT a "message extension", it's just a regular Adaptive Card action.
With regards the main issue, about the data not appearing, try to avoid having a direct string value as the "data" payload, and instead try with an object, like this:
...
"data": {"value": "**jiraid**"}
...
Got the answer here,
https://learn.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-actions#
For easy reference, this what we are supposed to do,
Adaptive Cards support three action types:
Action.OpenUrl
Action.Submit
Action.ShowCard
In addition to the
actions mentioned above, you can modify the Adaptive Card
Action.Submit payload to support existing Bot Framework actions using
a msteams property in the data object of Action.Submit. The below
sections detail how to use existing Bot Framework actions with
Adaptive Cards.
So the updated payload will be, refer the payload 'msteams' under action->data,
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": f"{jiradetail.summary}",
}
]
}
],
"actions": [
{
"type": "Action.ShowCard",
"title": "Comment",
"card": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Input.Text",
"id": "comment",
"isMultiline": True,
"placeholder": "Enter your comment"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "OK",
"data": {
"msteams": {
"type": "invoke",
"value": {"jiraid":f"{jiradetail.issueid}"}
}
}
]
}
}
]
}

I can't send layout blocks using python slack API

I used the latest bot kit builder by slack to generate the following buttons for my message attachment. The message is getting sent without any problem and but I don't see the attachment. I have been trying to figure this out and appreciate some help. My attachment is a list as required by slack api.
attachment_json = [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Hello, Please select your environment"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "production"
},
"value": "production"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "staging"
},
"value": "staging"
},
{
"type": "button",
"text": {
"type": "plain_text",
"text": "demo"
},
"value": "demo"
}
]
}
]
I am using slackclient SDK to send the message.
slack_client.api_call("chat.postMessage", channel="D4KU1DGUB", text='Hello World',
attachments=json.dumps(attachment_json))
Currently I am not seeing any buttons. Any help will be appreciated. Thank you.
Even sending this attachment from the example is not working
{
"text": "Would you like to play a game?",
"attachments": [
{
"text": "Choose a game to play",
"fallback": "You are unable to choose a game",
"callback_id": "wopr_game",
"color": "#3AA3E3",
"attachment_type": "default",
"actions": [
{
"name": "game",
"text": "Chess",
"type": "button",
"value": "chess"
},
{
"name": "game",
"text": "Falken's Maze",
"type": "button",
"value": "maze"
},
{
"name": "game",
"text": "Thermonuclear War",
"style": "danger",
"type": "button",
"value": "war",
"confirm": {
"title": "Are you sure?",
"text": "Wouldn't you prefer a good game of chess?",
"ok_text": "Yes",
"dismiss_text": "No"
}
}
]
}
]
}
This attachment is working for me
attachment_json = [
{
"fallback": "Upgrade your Slack client to use messages like these.",
"color": "#CC0000",
"actions": [
{
"type": "button",
"text": ":red_circle: Complete Task: ",
"url": "https://roach.ngrok.io/workflow/",
}
]
}
]
But I am can't figure out why the first example is not working.
The reason the first example is not working is that you are mixing the syntax for attachments and layout blocks in your method call. Those are different features and therefore each have their own parameter in the call to chat.postMessage.
(Secondary) attachments are passed with the attachments parameter.
Layout blocks are passed with the blocks parameter.
So the corrected version of your code from the first example would be:
slack_client.api_call("chat.postMessage", channel="D4KU1DGUB", text='Hello World',
blocks=json.dumps(attachment_json))
You may also want to rename the variable to blocks_json to avoid any confusion.

Best way to parse sections of json in python3 to separate items in list

First off, I'm having trouble Googling this question since I don't know all of the terminology (so really, giving me the proper terms to use in my Google search would be just as useful in this question).
I have some JSON that I need to parse in python, put each JSON string in a list after its been parsed(List, not array for Python correct?) and then I am going to go through that list to push the JSON content back to my source.
So as of now, I can parse out a section of JSON that I want, but I am not sure how to then get down to just printing the section between brackets. For example, I want to get each section (brackets) in this block of code to be in a separate JSON line:
{
"components": [
{
"self": "MY URL",
"id": "ID",
"name": "NAME",
"description": "THIS IS DESC",
"isAssigneeTypeValid": false
},
{
"self": "MY URL 2",
"id": "ID",
"name": "name",
"isAssigneeTypeValid": false
},
{
"self": "URL 3",
"id": "ID",
"name": "NAME 3",
"description": "DESC",
"isAssigneeTypeValid": false
}
]
}
There is a lot more JSON in my file, but using this, I can get it down to just returning the text above.
datas = json.loads(data)
print(datas['components'])
So my question is how would I just print one block? Or access the first 'self' section?
Here's how you can iterate over that data, converting each dict in the "components" list back into JSON strings:
import json
data = '''
{
"components": [
{
"self": "MY URL",
"id": "ID",
"name": "NAME",
"description": "THIS IS DESC",
"isAssigneeTypeValid": false
},
{
"self": "MY URL 2",
"id": "ID",
"name": "name",
"isAssigneeTypeValid": false
},
{
"self": "URL 3",
"id": "ID",
"name": "NAME 3",
"description": "DESC",
"isAssigneeTypeValid": false
}
]
}
'''
datas = json.loads(data)
for d in datas['components']:
print(json.dumps(d))
output
{"self": "MY URL", "description": "THIS IS DESC", "id": "ID", "isAssigneeTypeValid": false, "name": "NAME"}
{"self": "MY URL 2", "id": "ID", "isAssigneeTypeValid": false, "name": "name"}
{"self": "URL 3", "description": "DESC", "id": "ID", "isAssigneeTypeValid": false, "name": "NAME 3"}
If you have a valid json document then you can simply iterate over the list of components. Assuming you name the file <id>.json then you can simply do:
datas = json.loads(data)
for component in datas['components']:
with open("{}.json".format(component['id']), 'w') as f:
json.dump(component, f)
When you read it in, a JSON is a Python dictionary, so you can use all functions that are valid for dictionaries.
In your case "components" is the key of the dictionary, whose value is a list. Each item in the list is an another dictionary.

Categories