I am trying to build a Slack bot with interactive buttons. I have set up a Google Apps Script to handle the action performed on the Slack message. I want the payload of the request sent by the Slack. I have tried to get the request object by doing
function doPost(e) {
return processComment(e);
}
function processComment(e) {
Logger.log(e);
}
{postData=FileUpload, queryString=method=slack, parameter={method=slack, payload={"type":"block_actions","user":{"id":"U01835Mxxxx","username":"ravsamteam","name":"ravsamteam","team_id":"T0160UQZZZZ"},"api_app_id":"A018MPZ2xxx","token":"NTNRCTPDz8mxxxzxxxxxxxxx","container":{"channel_id":"C0190D8L2AU","is_ephemeral":false,"message_ts":"1597154895.001500","type":"message"},"trigger_id":"1281039280903.1204976558018.aa1055f6900d7884d9cd4ac34ffzzzzz","team":{"id":"T0160UQGE0J","domain":"ravsamhq"},"channel":{"id":"C0190D8L2AU","name":"blogs"},"message":{"type":"message","subtype":"bot_message","text":"This content can't be displayed.","ts":"1597154895.001500","bot_id":"B019BNL08BS","blocks":[{"type":"section","block_id":"mNavk","text":{"type":"mrkdwn","text":" New comment on RavSam's blog by hello","verbatim":false}},{"type":"section","block_id":"v3Ip","text":{"type":"mrkdwn","text":"*Blog:*\nhello\n\n*Comment:*\nravgeet errorCannot read property 'payload' of undefined","verbatim":false}},{"type":"actions","block_id":"1maVO","elements":[{"type":"button","action_id":"WSo=","text":{"type":"plain_text","text":"Approve","emoji":true},"style":"primary","value":"approved"},{"type":"button","action_id":"Vek\/","text":{"type":"plain_text","text":"Deny","emoji":true},"style":"danger","value":"denied"}]}]},"response_url":"https:\/\/hooks.slack.com\/actions\/T0160Uxxxxx\/1301968xxxxxx\/Q3gZhbeUCUIxxxxxxxxxxxxx","actions":[{"action_id":"WSo=","block_id":"1maVO","text":{"type":"plain_text","text":"Approve","emoji":true},"type":"button","value":"approved","action_ts":"1597213837.152704"}]}}, contentLength=2391.0, parameters={payload=[Ljava.lang.Object;#53f2e9fa, method=[Ljava.lang.Object;#5793298b}, contextPath=}
How do I get the payload? Once I have the payload JSON, I can use the actions to determine what action was taken by the user?
Yes. The payload contains all the information you need to identify the action. And it also contains a response_url to respond back.
Slack payload should look like this.
{
"actions": [
{
"name": "channels_list",
"selected_options": [
{
"value": "C012AB3CD"
}
]
}
],
"callback_id": "select_simple_1234",
"team": {
"id": "T012AB0A1",
"domain": "pocket-calculator"
},
"channel": {
"id": "C012AB3CD",
"name": "general"
},
"user": {
"id": "U012A1BCD",
"name": "musik"
},
"action_ts": "1481579588.685999",
"message_ts": "1481579582.000003",
"attachment_id": "1",
"token": "iUeRJkkRC9RMMvSRTd8gdq2m",
"response_url": "https://hooks.slack.com/actions/T012AB0A1/123456789/JpmK0yzoZDeRiqfeduTBYXWQ",
"trigger_id": "13345224609.738474920.8088930838d88f008e0"
}
You can learn more here.
Related
thank you for the time you will take to resolve my issue !
I am not sure that Google app script allows to do what I need.
Could you please tell me if it is possible?
If yes, do you have already a script code to do it?
I have created a file which I have shared it with others colleagues (in a shared drive), and it is used as a "template".
When a colleague creates a copy of it, I would like that the script to give me the new Google sheet id created from the model and saved this id in my Google sheet dashboard?
Is it possible with appscript?
Thanks a lot and have a good day !
Copy Spreadsheet and Save Id
function copySpreadsheetAndSaveId() {
const fileId = "fileid";
const ss = SpreadsheetApp.getActive():
const sh = ss.getSheetByName("Dashboard");
sh.getRange(sh.getLastRow() + 1, 1).setValue(DriveApp.getFileById(fileId).makeCopy().getId());//appends the id to the bottom of column one in the sheeet named Dashboard.
}
If you want users to be able to open the Spreadsheet then you can't restrict them copying it by script only
I can think of a couple of workarounds:
Workaround 1:
Make the Spreadsheet private, and create a web app which runs as you but is accessible by other users. On doGet(), create a copy of the Spreadsheet and share it with the email returned from Session.getActiveUser().getEmail():
function doGet() {
// Check if security policy gets email address:
const user = Session.getActiveUser()
if (!user.getEmail()) {
return ContentService.createTextOutput('Unable to retrieve user.')
}
const ss = DriveApp.getFileById("template-spreadsheet-id")
const newFile = ss.makeCopy().addEditor(user)
const html = `File copied, click here to open.`
return HtmlService.createHtmlOutput(html)
}
Pros:
Should work for anyone within the same domain as you
You can directly retrieve the ID on copy and save it to your database
Cons:
Security policy might stop you being able to get the user
What's to stop them from just copying the copy?
Workaround 2:
If you're an admin user, you could use the Drive Audit Activity API to check for domain-wide copy events of a given file ID. It's a bit more involved and assumes you have a client set up in GCP but will have a bigger catch-radius than the first workaround, and also doesn't involve restricting access to the template or creating a Web App:
function getAuditLog() {
const baseUrl = "https://admin.googleapis.com/admin/reports/v1/activity/users/all/applications/drive"
const apiKey = "api-key-obtained-from-gcp"
const params + `eventName=copy&key=${apiKey}`
const headers = {
"Authorization": `Bearer ${ScriptApp.getOAuthToken()}`,
"Accept": "application/json"
}
const response = UrlFetchApp.fetch(`${baseUrl}?${params}`, {
"method": "get",
"headers": headers"
})
const responseData = JSON.parse(response.getContentText())
}
You'll then have to process the response. responseData contains an items key which is an array of copy events in the audit report:
{
"kind": "admin#reports#activities",
"etag": "\"xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxx\"",
"items": [
{
"kind": "admin#reports#activity",
"id": {
"time": "2022-01-21T10:03:12.793Z",
"uniqueQualifier": "-XXXXXXXXXXXXXX",
"applicationName": "drive",
"customerId": "xxxxxxx"
},
"etag": "\"xxxxxxxxxxxxx/xxxxxxxxxxx\"",
"actor": {
"email": "user#example.com",
"profileId": "XXXXXXXXXXXX"
},
"ipAddress": "0000:0000:0000:0000:0000:0000:0000:0000",
"events": [
{
"type": "access",
"name": "copy",
"parameters": [
{
"name": "primary_event",
"boolValue": false
},
{
"name": "billable",
"boolValue": true
},
{
"name": "old_value",
"multiValue": [
"Spreadsheet Template File Name"
]
},
{
"name": "new_value",
"multiValue": [
"Copy of Spreadsheet Template File Name"
]
},
{
"name": "doc_id",
"value": "new-spreadsheet-id"
},
{
"name": "doc_type",
"value": "spreadsheet"
},
{
"name": "is_encrypted",
"boolValue": false
},
{
"name": "doc_title",
"value": "Copy of Spreadsheet Template File Name"
},
{
"name": "visibility",
"value": "private"
},
{
"name": "actor_is_collaborator_account",
"boolValue": false
},
{
"name": "owner",
"value": "user#example.com"
},
{
"name": "owner_is_shared_drive",
"boolValue": false
},
{
"name": "owner_is_team_drive",
"boolValue": false
}
]
}
]
}
]
...
}
You will have to filter out the reponse from here, however. For each element in the items array, the events key contains the information you will need to look for:
old_value is the original template spreadsheet's name
doc_id is the ID of the new spreadsheet
items.actor is the email of the person that completed the action.
References:
Example Audit request using the Try this API feature
I Try to create new converation and send proactive message with teams bot (botfreamwork).
I used this document to do that.
I POST to : SERVICE_URL/v3/conversations/
BODY:
{
"bot": {
"id": BOT_ID
},
"members": [
{
"id": USER_ID
}
],
"channelData": {
"tenant": {
"id": TENANT_ID
}
}
}
BOT_ID - I put the app id of the bot (with a prefix of "28:")
USERֹ_ID - I copied the USER_ID from a message I received from the user (not in a proactive message)
TENANT_ID - I took the tenant id from the link of the teams
I get this error:
{
"error": {
"code": "BadSyntax",
"message": "Invalid user identity in provided tenant"
}
}
I made several attempts to change the user ID: I changed to a user that appears in ADD, I changed with a prefix of 29: and without a prefix of 29: - nothing helped, this error continues to appear.
What am I missing?
I'm trying to perform a share with the beginShareFlow()function of the facebook MessengerExtensions. However, when performing the call, I get following error message:
Messenger Extensions unexpected error.
The code for this error is 2018154.
I'm using following code to start a share:
ajax.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
var message = JSON.parse(this.responseText);
MessengerExtensions.beginShareFlow(function(share_response) {
if(share_response.is_sent){
// close the window w/ requestCloseBrowser().
}
},
function(errorCode, errorMessage) {
console.log(errorCode+"-"+errorMessage);
},
message,
"current_thread");
}
}
You'll see that I'm using the response of an ajax call to fill up the actual message. This is generated by some backend php code, an example:
{"attachment":{"type":"template","payload":{"template_type":"generic","sharable":"true","elements":[{"title":"Kerk Poederlee","image_url":"https:\/\/www.wouterh.be\/pogo\/static\/images\/raid.jpg","subtitle":"joining at 1535629500","default_action":{"type":"web_url","url":"https:\/\/www.wouterh.be\/pogo"},"buttons":[{"type":"web_url","url":"https:\/\/www.wouterh.be\/pogo","title":"join raid"}]}]}}}
Messenger extension themselves have been loaded correctly, since I'm able to retrieve the PSID with following code:
window.extAsyncInit = function() {
MessengerExtensions.getContext('APPID',
function success(thread_context){
fb_user_id = thread_context.psid;
},
function error(err){}
);
};
This error occurs on a web client and on the most recent iOS messenger. When I send the exact same message through the Send API instead of the sharing messenger extensions, it works perfectly. Could somebody help me figure out what's causing the error?
I found the mistake, in the message you can pass a 'sharable' property. I passed the string value "true" to it, but this should be a boolean value.
This is the corrected content:
{
"attachment": {
"type": "template",
"payload": {
"template_type": "generic",
"sharable": true,
"elements": [{
"title": "Kerk Poederlee",
"image_url": "https:\/\/www.wouterh.be\/pogo\/static\/images\/raid.jpg",
"subtitle": "joining at 1535629500",
"default_action": {
"type": "web_url",
"url": "https:\/\/www.wouterh.be\/pogo"
},
"buttons": [{
"type": "web_url",
"url": "https:\/\/www.wouterh.be\/pogo",
"title": "join raid"
}]
}]
}
}
}
I'm trying to post fulfillment data on SubmitFeed using javascript in sapui5 and i have done the steps as,
1) I have created json object for fulfillment data and converted it into XML again XML converted into MD5.
JSON code:-
{
"AmazonEnvelope": {
"-xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"-xsi:noNamespaceSchemaLocation": "amznenvelope.xsd",
"Header": {
"DocumentVersion": "1.01",
"MerchantIdentifier": "Example"
},
"MessageType": "OrderFulfillment",
"Message": {
"MessageID": "1",
"OperationType": "Update",
"OrderFulfillment": {
"AmazonOrderID": "102-8289425-201934",
"FulfillmentDate": "2017-06-20T00:36:33-08:00",
"FulfillmentData": {
"CarrierName": "UPS",
"ShippingMethod": "Second Day",
"ShipperTrackingNumber": "1234567890"
},
"Item": {
"AmazonOrderItemCode": "1234567",
"MerchantFulfillmentItemID": "1234567",
"Quantity": "2"
}
}
}
}
};
2) Created signature as per the api documents.
3) Post the data on Feed/2009-01-01.
but i'm getting the error as:-
"<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/">
<Error>
<Type>Sender</Type>
<Code>InvalidAddress</Code>
<Message>Resource /$metadata is not found on this server. API Version is missing</Message>
</Error>
<RequestID>c00cb653-f53c-445f-9f24-82587144805d</RequestID>
</ErrorResponse>
"
Please help me to resolve this.
Thank you
The error you are getting is InvalidAddress, not a signature check error. It seems whatever you are doing in step 3 (Post the data on Feed/2009-01-01) does not work as expected. The MWS servers see a request for /$metadata instead of API name and version. Your question does not include the piece of code that does that.
This is similar to but it's a continuation to Parse geo-queries always empty
I have device installations working correctly, and i've created a customized class "test_users" that contains the location data. each instance in the "Installation" class holds a pointer to the "test_users" instance, with column name "test" below** you can see below, and when I clicked on the pointer value, it will go to that "test_user" instance.
and "test_users" class
I have the following javascript code to Query the channel and location to send push notification:
$http({
"url": "https://api.parse.com/1/push",
"method": "POST",
"data": {
"data": { "alert": "test!! ",
"sound": "beep.caf",
"badge": "Increment",
"uid":user_uid,
"date":date,
"time":time
},
"where": {
"channel": category,
"test": {
"$inQuery": {
"location": {
"$nearSphere": {
"__type": "GeoPoint",
"latitude": 37.7150 ,
"longitude": -117.1625
},
"$maxDistanceInMiles": 20
}
}
}
}
},
"headers": {
"X-Parse-Application-Id": "######",
"X-Parse-REST-API-Key": "#######",
"Content-Type": "application/json"
},
"params":
{
"uid" : user_uid,
"date": date,
"time": time
}
});
However, no push notification is created, and when i check the analytics, i see this
Any thoughts on where I made the query mistake? or anything wrong with "test_users" class? Update: On a different experiment, I also created a _User class just like the parse.com push notification doc did (and have "Installation" instance storing a pointer to the _User instance), and got same empty geo-query result.