Capturing Twilio's outgoing call status on google appscript - flask

I am trying to get the status of my outgoing twilio calls and update them onto the spreadsheet. "Completed, Busy, No-Answer, Cancelled, Failed".
However, I do not know where to include the StatusCallBackEvent and how to access the retrieved status from Google Apps Script.
Here is the code which I have to initiate an outbound call.
function makeCall(to) {
var call_url = "https://api.twilio.com/2010-04-01/Accounts/" + TWILIO_ACCOUNT_SID + "/Calls.json";
var payload = {
"To": "+" + String(to),
"From" : TWILIO_NUMBER,
"Url": "http://a1fb888ec032.ngrok.io/" +"voice",
"Method": "GET"
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode(TWILIO_ACCOUNT_SID + ":" + TWILIO_AUTH_TOKEN)
};
var response = UrlFetchApp.fetch(call_url, options);
UrlFetchApp.fetch(call_url, options);
return JSON.parse(response);
}

Twilio developer evangelist here.
To receive the status of the call, you need to set a StatusCallback URL when you create the call. The URL should point towards a URL which you control that can update your spreadsheet when it receives an HTTP request from Twilio.
var payload = {
"To": "+" + String(to),
"From" : TWILIO_NUMBER,
"Url": "http://a1fb888ec032.ngrok.io/" +"voice",
"Method": "GET",
"StatusCallback": "https://SOME_URL"
};
You can use Google Sheets and App Script to set up a web application that can receive webhooks like this. Briefly, you need to create script that has a doPost method (Twilio webhooks are POST requests by defaults) and returns a successful response. Twilio statusCallback webhooks don't expect any content in the response, so you can use an empty text output.
Something like this might work:
function doPost(event) {
var callSid = event.parameter("CallSid");
var status = event.parameter("CallStatus");
// update spreadsheet with call status
return ContentService.createTextOutput('');
}
Check out the documentation on turning scripts into web apps and Twilio call status callbacks for more details.

Related

API Gateway integration response mapping: parse statusCode and body from Step Function output

I want to parse 'statusCode' and 'body' values from API Gateway integration response using VTL and return those as a method response like this:
Request status: 201
Response body: {"firstName":"He","lastName":"Man","email":"he.man#eternia.com"}
My API Gateway Step Function integration is returning the following integration response body (this is before transformation, non-relevant attributes are removed from output):
{
"output": "{\"statusCode\":201,\"body\":{\"firstName\":\"He\",\"lastName\":\"Man\",\"email\":\"he.man#eternia.com\"}}"
}
I would assume this to work:
#set ($output = $util.parseJson($input.json('$.output')))
#set ($statusCode = $output.statusCode)
#set ($context.responseOverride.status = $statusCode)
$output.body
But status is not updated and body is empty
Request status: 200
Response body: <empty>
With this approach I can parse the body:
#set ($bodyObj = $util.parseJson($input.body))
#set ($output = $util.parseJson($bodyObj.output))
#set ($context.responseOverride.status = $output.statusCode)
$output.body
statusCode is updated but body is returned as object representation i.e. not JSON.
Request status: 201
Response body: {firstName=He, lastName=Man, email=he.man#eternia.com}
How to serialize $output.body correctly to JSON in above case? API Gateway doesn't seem to have $util.toJson function like AppSync does (https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-programming-guide.html)
I've confirmed parsing output-variable works correctly:
#set ($output = $util.parseJson($input.json('$.output')))
$output
Request status: 200
Response body: {"statusCode":201,"body":{"firstName":"He","lastName":"Man","email":"he.man#eternia.com"}}
Relevant reference documentation:
https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html#API_StartSyncExecution_ResponseSyntax
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
I ran into this exact issue. There indeed does not seem to be a way to convert to JSON directly, so I devised a way to write JSON to the API Gateway response using Apache VTL:
#set ($outputObj = $util.parseJson($input.path('$.output')))
#foreach ( $key in $outputObj.body.keySet() )
"$key": $outputObj.body[$key] #if ($foreach.hasNext),#end
#end
Hope this helps!
(This works for a simple use case like the one you described, but doesn't generalize to nested objects, etc.)
I ran into this same issue. This is how I solved it in the end. The solution provided by #noahtk7 was good for simple object, I have large nested object I needed.
For this to work you need to have your body returned as a base64 encoded string. This is easy to do in a step function. E.G:
"Pass": {
"Type": "Pass",
"Next": "Success",
"Parameters": {
"Base64.$": "States.Base64Encode(States.JsonToString($.Response.Body))"
},
"ResultPath": "$.Response.Body"
}
Then in the api response mapper:
#set($output = $util.parseJson($input.path('$.output')))
#set($context.responseOverride.status = $output.Response.Status)
$util.base64Decode($output.Response.Body.Base64)
Would give me a result of:
{
"foo": "bar",
"Id": "c2b2220c-00e3-4499-87c0-d06ea5e5f1f4"
}

Telegram bot sendMediaGroup() in Postman - JSON-serialized array?

I'm using Postman app to interact with a Telegram bot api. I've sent photos using the sendPhoto() method, like this:
https://api.telegram.org/botToken/sendPhoto?chat_id=00000000&photo=AgAC***rgehrehrhrn
But I don't understand the sendMediaGroup() method. Can someone post an example how to compose the https string to send two photos?
Thanks
You need to send a POST request at the url https://api.telegram.org/botToken/sendPhoto with a JSON body. You are using the url to specify all the parameters of the request but urls are only 2000 characters long. The body of a POST request, instead, has no limits in terms of size. The JSON body should look something like this:
{
"chat_id": 777000,
"media": [
{
"type": "photo",
"media": "https://example.com/first_photo_url.png",
"caption": "an optional description of the first photo",
"parse_mode": "optional (you can delete this parameter) the parse mode of the caption"
},
{
"type": "photo",
"media": "https://example.com/fsecond_photo_url.png",
"caption": "an optional description of the second photo",
"parse_mode": "optional (you can delete this parameter) the parse mode of the caption"
}
],
}
For more info see:
how to send JSON (raw) data with Postman
and
sendMediaGroup Telegram API's method.
You must send JSON as a string, or serialized JSON, to Telegram API. The format is as same as #GioIacca9's answer.
Note: only the caption in the first image will be showen.
Have a try this Python code.
def send_photos(api_key, chat_id, photo_paths):
params = {
'chat_id': chat_id,
'media': [],
}
for path in photo_paths:
params['media'].append({'type': 'photo', 'media': path})
params['media'] = json.dumps(params['media'])
url = f'https://api.telegram.org/bot{api_key}/sendMediaGroup'
return requests.post(url, data=params)
if __name__ == '__main__':
send_photos('your_key', '#yourchannel', ['http://your.image.one', 'http://your.image.two'])

Cannot login from Chrome extension to another site

I am trying to login into an online shopping site from Chrome extension, then scrape it.
There are three steps that happens when you do this from a browser.
Visit the site, the site gives you a cookie.
Go to the login page, send the aforementioned cookie, and username and password as params in POST. The site gives you 5 more cookies.
call GET to a path within the site, along with five + one = total six cookies.
Now that works well in browser. If I copy all the cookies from the browser into curl, the following call would work.
curl -X GET --header "Cookie: cookie1=value1; cookie2=value2; cookie3=value3; cookie4=value4; cookie5=value5; cookie6=value6" http://www.sitedomain.com/product_info.php?products_id=350799
However, how can I repeat this behavior in Google Chrome extension? Nothing I do seems to be working, yes I added the domain to the manifest.json and I've tried request, requestify (both browserified) and XMLHttpRequest. The requests seem fine (do include cookies) but the response I get seems to be the one I get when the site any receiving cookie.
manifest.json
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"cookies",
"https://sitedomain.com/*",
"http://sitedomain.com/*",
"https://www.sitedomain.com/*",
"http://www.sitedomain.com/*"
]
}
The code I use (request version):
var request = require('request');
request = request.defaults({jar: true});
var jar = request.jar();
var cookie1 = request.cookie('cookie1=value1');
var cookie2 = request.cookie('cookie2=value2');
var cookie3 = request.cookie('cookie3=value3');
var cookie4 = request.cookie('cookie4=value4');
var cookie5 = request.cookie('cookie5=value5');
var cookie6 = request.cookie('cookie6=value6');
var url = "http://www.sitedomain.com";
jar.setCookie(cookie1, url);
jar.setCookie(cookie2, url);
jar.setCookie(cookie3, url);
jar.setCookie(cookie4, url);
jar.setCookie(cookie5, url);
jar.setCookie(cookie6, url);
request({uri: http://www.sitedomain.com/product_info.php?products_id=350799, jar: jar}, function (error, response, html) {
if (!error && response.statusCode == 200) {
//breakpoint here and we did not receive the page after login
}
}
Any help would be appreciated.

Send email through OTRS API

I currently have the below that updates an OTRS ticket using by calling the link /otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket
It works great, but how can I get it to send an email to the customer when the ticket is updated as well?
var body = JSON.stringify ({
"Ticket":{
"StateID":params.state},
"Article":{
"ArticleTypeID":params.noteType,
"Subject":params.subject,
"Body":params.bodyText,
"ContentType":params.contentType
}
}
);
//Build the full URL for our webservice query.
var LoginURL = authenticate.URL + "/" +
TicketID +
"?UserLogin=" + authenticate.UserLogin +
"&Password=" + authenticate.Password;
//Perform the actual work. As well as the URL of the webservoce
var client = new apiclient.ApiClient({ serverid: this.serverid });
var resp = client.invoke( "formutils", "httpRequest", {
"url": LoginURL,
"method": "POST",
"headers": {
"ContentType":"application/json"},
"body": body
});
If you update a ticket via the web service API, by default this will NOT trigger sending an email to the customer, not even if you set the article type as 'email-external'.
If you do want this to happen, the best way is to create a new Notification (prior to OTRS 5 this would be an 'Event Based Notification') as described here: http://otrs.github.io/doc/manual/admin/stable/en/html/administration.html#adminarea-ticket-notifications
You can match on the ArticleCreate event, the user who created the ticket via the Web Service, and maybe other attributes as well.
https://github.com/OTRS/otrs/blob/6c87d2b1370b917629a99df7e080b8f87f051581/Kernel/GenericInterface/Operation/Ticket/TicketUpdate.pm#L1936 calls the internal API ArticleCreate() which never sends email whereas ArticleSend() does.
There is an extension published by Znuny which you could install on your OTRS system that exposes this functionality to the web service as well: https://github.com/znuny/Znuny4OTRS-GIArticleSend

google apps script ==> UrlFetchApp, method GET and cookie

I use the UrlFetchApp to send the user and pwd (method POST). After get the cookie, and use in other request (method GET). But this new request not working, I think that this cookie not has correct use in this new request. Can anyone help me?
var opt ={
"method":"post",
"User-Agent" : "Mozilla/5.0",
"Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language" : "en-US,en;q=0.5",
"payload": this.payload.toString(),
"followRedirects" : false
};
var response = UrlFetchApp.fetch("https://edas.info/addTopic.php?c=19349",opt);
var resp1=response.getContentText();
Logger.log(resp1);
response.getResponseCode();
var headers = response.getAllHeaders();
var cookies = headers['Set-Cookie'];
for (var i = 0; i < cookies.length; i++) {
cookies[i] = cookies[i].split( ';' )[0];
};
opt = {
"method" : "get",
"User-Agent" : "Mozilla/5.0",
"Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language" : "en-US,en;q=0.5",
"headers": {
"Cookie": cookies.join(';')
},
"followRedirects" : false
};
response = UrlFetchApp.fetch("https://edas.info/addTopic.php?c=19349", opt);
var resp1=response.getContentText();
Logger.log(resp1);
First off, thanks you for the snippet of code, this got me started with processing cookies in such script. I encountered an issue that was possibly your problem. Sometimes a Web page returns an array of cookies, and then your code works fine. Sometimes it returns a single string (instead of an array of one string). So I had to disambiguate with a test like:
if ( (cookies != null) && (cookies[0].length == 1) ) {
cookies = new Array(1);
cookies[0] = headers['Set-Cookie'];
}
I cannot give you specific help for your problem, one pointer though, as found here
Cookie handling in Google Apps Script - How to send cookies in header?
As https://stackoverflow.com/users/1435550/thierry-chevillard put it:
Be aware also that GAS uses Google IPs. It can happen that two consecutive fetch use different IPs. The server your are connecting to may be session-IP dependant.
Does your code run on the local development server and only fail once deployed to App Engine?
Or does it fail locally, as well?