I created an app on Azure and want to use it to subscribe to business emails of certain users. However, I cannot get it to work and I'm wondering if it is even possible this way. The code is as follows:
url = 'https://graph.microsoft.com/beta/subscriptions'
payload = {
'changeType': 'updated',
'notificationUrl': 'http://<server_ip>/webhook',
'resource': "users/<my_user>#<my_domain>/mailFolders('inbox')/messages",
'expirationDateTime': '2022-07-23T11:52:20',
}
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
print(response.status_code)
print(response.reason)
print(response.text)
400
Bad Request
{"error":{"code":"InvalidRequest","message":"Could not process subscription creation
payload. Are all property names spelled and camelCased properly? Also are the
dateTimeOffest properties in a valid internet Date and Time format?","innerError":
{"date":"2022-07-22T09:12:11","request-id":"317989f4-c921-44ce-a701-
c57a660aad3b","client-request-id":"317989f4-c921-44ce-a701-c57a660aad3b"}}}
I also want to subsribe to changes to our drive, for this I substitute the resource for f'drives/{drive_id}/root'. This gives the same error messsage.
I have read all the relevant docs and feel this this should be the correct approach, but the error message is not useful to me for find the issue.
Related
My company uses Twilio Flex as our phone system and I was recently tasked with setting up a feature that will let us edit a TwiML voice message that plays before our normal voice message. This TwiML message will be changed through a Twilio bot that I've published in our Microsoft Teams.
The reason for this is so that our support desk can add a short message in the lines of "We're currently experiencing issues with X" before our normal "Welcome to [Company] support" message.
If TwiML's can be edited using HTTP POST/PUT or Twilio's API this should be a trivial matter, but so far I've not been able to figure out how.
I couldn't find any reference to this in the API doc, so I decided that HTTP POST would be the way to go. Using this as a start off point, I'm able to retrieve my TwiML using HTTP GET:
https://support.twilio.com/hc/en-us/articles/223132187--Not-Authorized-error-when-trying-to-view-TwiML-Bin-URL
const axios = require('axios');
const crypto = require('crypto');
const accountSidFlex = process.env.accountSidFlex;
const authTokenFlex = process.env.authTokenFlex;
var URL = 'https://handler.twilio.com/twiml/EHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + '?AccountSid=' + accountSidFlex
var twilioSig = crypto.createHmac('sha1', authTokenFlex).update(new Buffer(URL, 'utf-8')).digest('Base64')
var config = {
headers:{
'X-TWILIO-SIGNATURE': twilioSig
}
}
axios.get(
URL,config
).catch(error => console.log(error))
.then(response => {
console.log(response.data)
})
response.data shows the TwiML's current XML content.
My attempts at a POST only gives the same output as the GET, while PUT gives 405 Method Not Allowed.
var URL = 'https://handler.twilio.com/twiml/EHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + '?AccountSid=' + accountSidFlex
var twilioSig = crypto.createHmac('sha1', authTokenFlex).update(new Buffer(URL, 'utf-8')).digest('Base64')
var config = {
headers:{
'X-TWILIO-SIGNATURE': twilioSig,
'Content-Type': 'text/xml'
}
}
var xml =
'<?xml version="1.0" encoding="UTF-8"?>\
<Response><Play digits="www"/>\
<Say voice="alice">"We are currently experiencing X related issues". </Say>\
</Response>';
axios.post(
URL,xml,config
)
.catch(error => console.log(error))
.then(response => {
console.log(response.data)
})
Ideally I'd like to be able to change a specific TwiML using either HTTP methods or the Twilio-API, so that we can use it in out Studio Flow. We'd just keep it silent until we need to add something to it and revert back to silent once the issues have passed.
Any help would be appreciated!
You cannot currently change the contents of TwiML Bins, Studio Flows, or Twilio Functions programatically. I believe the key functionality you are looking for is a way to dynamically update the messaging (Say/Play Widget) in a Studio flow based on some condition.
One way is to use a Function Widget to retrieve a Twilio Sync document for the message, returning the message as JSON and have the Say/Play widget play that message. You can find the Twilio Sync REST API examples for Add, Modify, and Retrieve in the associated document.
You can retrieve the parsed response using variable syntax detailed here, https://www.twilio.com/docs/studio/widget-library#run-function.
I am working on ionic app which will be used on android and iOS platforms. App uses one endpoint to post user data to the backend. Data posted on a backend is as follows:
{
"name": "Citizen Foo",
"emailAddress": "citizen.foo#gmail.com",
"role": "citizen"
}
For security purpose every request which is being sent is validated. In order to do this client sends authorization header with every request. Backend creates one for every request and matches it with one sent by client and then only responds otherwise throw an exception. For creating the authorization header, data sent over post request is also a part of the logic. I have simplified this logic becuase the actual problem is different but this part is important to understand the problem.
Following is the sample code on client side:
var sRequestBody = JSON.stringify(data);
var requestBodyBytes = this.getByteArray(unescape(encodeURIComponent(sRequestBody)));
var authHeader = md5.base64(requestBodyBytes);
var headers = {};
headers['Authorization'] = authHeader;
this.nativeHttp.setDataSerializer('json');
this.nativeHttp.clearCookies();
this.nativeHttp.setSSLCertMode('nocheck');
return Observable.fromPromise(this.nativeHttp.post(url, data, headers));
Then, backend which is asp.net web api, calculates authorization in the same way and matches it with one send by client and gives the response if it matches.
var rawContent = await content.ReadAsByteArrayAsync();
var stringContent = content.ReadAsStringAsync().Result;
var hash = md5.ComputeHash(rawContent);
var authorization = Convert.ToBase64String(hash);
if (authHeader != authorization)
throw;
When the above call is made from android,
value of dataString on client is
"{"name":"Citizen Foo","emailAddress":"citizen.foo#gmail.com","role":"citizen"}"
value of stringContent on server is
"{""name"":""Citizen Foo"",""emailAddress"":""citizen.foo#gmail.com"",""role"":""citizen""}"
and it allows request coming from android app.
When the same is run on iOS and the post user call is made,
Value of dataString on client is
"{"name":"Citizen Foo","emailAddress":"citizen.foo#gmail.com","role":"citizen"}"
Value of stringContent on server is
"{""name"":""Citizen Foo"",""role"":""citizen"",""emailAddress"":""citizen.foo#gmail.com""}"
and it does not allow requst coming from iOS app.
And the only reason it is happening is because of the way user object is serialized/received at the backend when request is made from iOS. Order of properties while sending is name,emailAddress,role. While it is received with order name,role,emailAddress. Thus, the authorization value calculated on server side is different than authHeader coming from client and the call is terminated.
stringContent was added on server side just to debug and understand what is being received at server. Order of the object properties on client is different than object properties received on server side. Is there a way to maintain the order of object properties when the request is made from iOS platform? Direction in any way to solve this problem is appreciated.
One solution that worked for us is this:
this.httpClient.setDataSerializer('utf8');
response = await this.httpClient.post(url, JSON.stringify(postBody), {'Content-Type': 'application/json'});
So key points here are:
utf8 as data serializer
body has to be stringified
header 'Content-Type': 'application/json' has to be set
I'm trying to write a http rest client for my webservice and i need to send some PATCH requestes with data in the body.
I'm using the JUST library for sending requests ( https://github.com/JustHTTP/Just )
My express application just doesn't see the request.
Here's some code (i'm testing in playground, and everything went fine with other kind of requests like put, post...)
headers = ["accept":"application/json","content-type":"application/json","authorization":"key"] //key is ok
var data = ["id":3, "quantity":6]
var r = Just.patch("http://api.marketcloud.it/v0/carts/1233", headers:headers, data:data) //1233 is a cart Id
print(r)
print(r.json)
The method Just.patch returns an HTTPResult Object.
this says 'OPTIONS http://api.marketcloud.it/v0/carts/13234 200'
Also this object should contain a json, but it's 'nil'.
On the server-side, my express applications doesn't receive the request (it just logs an 'OPTION', but nothing else).
Could this be a playground-related problem? Or a just-related one?
Thanks for any suggestion
I managed to contact the library's author via twitter and he fixed the bug and answered me in less than 24h!
Here's the new release of the library.
https://github.com/JustHTTP/Just/releases
I'm trying to use Google OAuth with Sign in & Sign Up for my Web Server Application.
This is the page : https://developers.google.com/identity/sign-in/web/backend-auth that I have referenced, but I am stuck in using the Google Client API, the TokenVerifier that is mentioned below in the document. I tried to find some examples, but I couldn't find one, as I am not sure how to handle the parameters in the methods that the sample shows.
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
...
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Arrays.asList(CLIENT_ID))
.build();
// (Receive idTokenString by HTTPS POST)
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
Payload payload = idToken.getPayload();
if (payload.getHostedDomain().equals(APPS_DOMAIN_NAME)
// If multiple clients access the backend server:
&& Arrays.asList(ANDROID_CLIENT_ID, IOS_CLIENT_ID).contains(payload.getAuthorizedParty())) {
System.out.println("User ID: " + payload.getSubject());
} else {
System.out.println("Invalid ID token.");
}
} else {
System.out.println("Invalid ID token.");
}
For example, I know what these CLIENT_ID, ANDROID_CLIENT_ID, IOS_CLIENT_ID parameters mean in the sample code(in the reference page), but the server only receives id_token, which is basically a String Text. (That was made by the google api in the client-side, the javascript)
So, I do not have these parameter values passed to the server from the client. I know that google shows another way: the tokeninfo endpoint, but they mentioned that it is for only 100user/month only. (If I translated it correctly) However, for the tokeninfo endpoint way, they return the JSON file of containing client ids, which I think that would be the values for the parameters that I mentioned before, but I do not want to use the token info endpoint method.
So, my question is, how do I get the right parameter values for the sample code that is showed in the google document page? I only receive id_token value from the client.
ANDROID_CLIENT_ID or IOS_CLIENT_ID should be hard coded (in a config file) in your server's code.
Essentially your server is getting an id_token in a request and you need to make sure if it is meant for your app or server by checking the audience in there and making sure it matches one of the values you are expecting.
Im trying to create a table on BigQuery - I have a single dataset and need to use the api to add a table and import data (json.tar.gz) from cloud storage. I need to be able to use the ruby client to automate the whole process. I have two questions:
I have read the docs and tried to get it to upload (code below) and have not been successful and have absolutely no idea what Im doing wrong. Could somebody please enlighten me or point me in the right direction?
Once I make the request, how do I know when the job has actually finished? From the API, I presume Im meant to use a jobs.get request? Having not completed the first part I have been unable to get to look at this aspect.
This is my code below.
config= {
'configuration'=> {
'load'=> {
'sourceUris'=> ["gs://person-bucket/person_json.tar.gz"],
'schema'=> {
'fields'=> [
{ 'name'=>'person_id', 'type'=>'integer' },
{ 'name'=> 'person_name', 'type'=>'string' },
{ 'name'=> 'logged_in_at', 'type'=>'timestamp' },
]
},
'destinationTable'=> {
'projectId'=> "XXXXXXXXX",
'datasetId'=> "personDataset",
'tableId'=> "person"
},
'createDisposition' => 'CREATE_IF_NEEDED',
'maxBadRecords'=> 10,
}
},
'jobReference'=>{'projectId'=>XXXXXXXXX}
}
multipart_boundary="xxx"
body = "--#{multipart_boundary}\n"
body += "Content-Type: application/json; charset=UTF-8\n\n"
body += "#{config.to_json}\n"
body += "--#{multipart_boundary}\n"
body +="Content-Type: application/octet-stream\n\n"
body += "--#{multipart_boundary}--\n"
param_hash = {:api_method=> bigquery.jobs.insert }
param_hash[:parameters] = {'projectId' => 'XXXXXXXX'}
param_hash[:body] = body
param_hash[:headers] = {'Content-Type' => "multipart/related; boundary=#{multipart_boundary}"}
result = #client.execute(param_hash)
puts JSON.parse(result.response.header)
I get the following error:
{"error"=>{"errors"=>[{"domain"=>"global", "reason"=>"wrongUrlForUpload", "message"=>"Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/bigquery/v2/projects/XXXXXXXX/jobs"}], "code"=>400, "message"=>"Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/bigquery/v2/projects/XXXXXXXX/jobs"}}
From the request header, it appears to be going to the same URI the error says it should go to, and I am quite at a loss for how to proceed. Any help would be much appreciated.
Thank you and have a great day!
Since this is a "media upload" request, there is a slightly different protocol for making the request. The ruby doc here http://rubydoc.info/github/google/google-api-ruby-client/file/README.md#Media_Upload describes it in more detail. I'd use resumable upload rather than multipart because it is simpler.
Yes, as you suspected, the way to know when it is done is to do a jobs.get() to look up the status of the running job. The job id will be returned in the response from jobs.insert(). If you want more control, you can pass your own job id, so that in the event that the jobs.insert() call returns an error you can find out whether the job actually started.
Thank you for that. Answer resolved. Please see here :
How to import a json from a file on cloud storage to Bigquery
I think that the line of code in the docs for the resumable uploads section (http://rubydoc.info/github/google/google-api-ruby-client/file/README.md#Media_Upload) should read:
result = client.execute(:api_method => drive.files.insert,
Otherwise, this line will throw an error with 'result' undefined:
upload = result.resumable_upload