How to download media files in WhatsApp API which send users? - json

I am currently writing a chatbot for WhatsApp.
I use the 360dialog platform, which makes it possible to work with the WhatsApp Business API.
When the client sends a message, I see the following JSON object in the logs of my application:
{
"messages": [
{
"from": "77773336633",
"id": "ABGGd3c1cGY_Ago61ytHsZknvtLv",
"image": {
"id": "ffd23134-2dae-4fed-b5f8-0ce7867b6ddd",
"mime_type": "image/jpeg",
"sha256": "bd02100d961b5a1dbaae1dd645485ebbfeda77b44e82c015f1cf29b05654ccb9"
},
"timestamp": "1605703542",
"type": "image"
}
],
"contacts": [
{
"profile": {
"name": "Nurzhan Nogerbek"
},
"wa_id": "77773336633"
}
]
}
I can't find any information in the documentation about how to download this file.
In my case, I want to upload this image file that the client sends to my file storage.
Please tell me which URL method from the WhatsApp API is responsible for this mechanism?
P.S. At the same time, I can send files to clients. This information is available on the official documentation.

May be it will help, just try, take a look:-
const URL = `https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=1104480873777230&ext=1662705250&hash=ATuMx352sLrhKUegbQZSC8oLl3J5Vy3Z49lO4HwTUKWRYQ`;
const FROM = `video`;
const config = {
method: 'get',
url: URL, //PASS THE URL HERE, WHICH YOU RECEIVED WITH THE HELP OF MEDIA ID
headers: {
'Authorization': `Bearer ${token}`
},
responseType: 'arraybuffer'
};
axios(config)
.then(function (response) {
const ext = response.headers['content-type'].split("/")[1];
fs.writeFileSync(`${FROM}.${ext}`, response.data);
})
.catch(function (error) {
console.log(error);
});

It was very tricky because postman worked, but c# didn't work for me, and I spent two days trying to find the solution and finally did the following code, which works in C#:
using HttpClient _httpClient = new HttpClient();
Uri uri = new Uri(mediaUrl);
var fileName = $"{DateTime.Now.ToString("yyyyMMddhhmmss")}.jpeg";
string filePath = $"Files\\{fileName}";
// NOTE: to save bandwidth, request compressed content
_httpClient.DefaultRequestHeaders.AcceptEncoding.Clear();
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
_httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("br"));
// NOTE: accept all languages
_httpClient.DefaultRequestHeaders.AcceptLanguage.Clear();
_httpClient.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("*"));
// NOTE: accept all media types
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("image/jpeg"));
var productValue = new ProductInfoHeaderValue("ScraperBot", "1.0");
var commentValue = new ProductInfoHeaderValue("(+http://www.API.com/ScraperBot.html)");
_httpClient.DefaultRequestHeaders.UserAgent.Add(productValue);
_httpClient.DefaultRequestHeaders.UserAgent.Add(commentValue);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", {WhatsApp_Access_Token});
HttpResponseMessage response = await _httpClient.GetAsync(uri);
response.EnsureSuccessStatusCode();
var mediaType = response?.Content?.Headers?.ContentType?.MediaType ?? string.Empty;
var imageBytes = await response.Content.ReadAsByteArrayAsync();
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
fs.Write(imageBytes, 0, imageBytes.Length);
}
Here, {WhatsApp_Access_Token} is your Whatsapp API permanent token.
Ping me in a comment, please, if you have any issues or questions.

The official documentation has a session for this in https://developers.facebook.com/docs/whatsapp/api/media.
Basically you must make a GET request to download the media.
curl --request GET \
--url https://waba.360dialog.io/v1/media/{media id} \
--header 'D360-API-KEY: {your api token}'

Related

How to get media URL from cloudinary

I want to upload an image to cloudinary and then get the URL of the image in and store it (the url) in a database but don't have a clue on how to get started. I can upload to cloudinary, but I don't know how to programmatically get the url. I'm working with React and NodeJS. I need help guys
Next time you post a question, please include more context and show examples of what you have tried!
That being said, I would use the cloudinary npm package. https://www.npmjs.com/package/cloudinary
Uploading will return an object like this:
{
"public_id": "4srvcynxrf5j87niqcx6w",
"version": 1340625837,
"signature": "01234567890abcdef01234567890abcdef012345",
"width": 200,
"height": 200,
"format": "jpg",
"resource_type": "image",
"url": "http://res.cloudinary.com/demo/image/upload/v1340625837/4srvcynxrf5j87niqcx6w.jpg",
"secure_url": "https://res.cloudinary.com/demo/image/upload/v1340625837/4srvcynxrf5j87niqcx6w.jpg"
}
So to get the url after uploading, do this:
var cloudinary = require('cloudinary').v2;
const url = await new Promise((resolve, reject) => {
cloudinary.uploader.upload("my_picture.jpg", function (error, result) {
if(result){
resolve(result.url);
} else if(error){
reject(error)
}
});
})

Authentication error when attempting to fetch google analytics 4 with app script

I would like to connect a community connector to a google analytics 4 account so that I can easily modify the data and send it to data studio. However, My code is returning an authentication error:
{ error:
{ code: 401,
message: 'Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.',
status: 'UNAUTHENTICATED' } }
I have included the token, but I am unsure if I am making the correct url call or if there is some other issue that I am unaware of. I don't believe I need an API key to connect from community connector to a google API, but I may be wrong. I did create an API key but the result was the same.
function testFetch(){
var url = "https://analyticsdata.googleapis.com/v1alpha:runReport"
var token = ScriptApp.getOAuthToken();
var options = {
"method" : 'POST',
"entity": { "propertyId": "263290444" },
"dateRanges": [{ "startDate": "2020-12-01", "endDate": "2021-03-01" }],
"dimensions": [{ "name": "country" }],
"metrics": [{ "name": "activeUsers" }],
'muteHttpExceptions': true,
headers: {
Authorization: 'Bearer' + token,
},
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
}
Here is a small guide on how to do what you are trying to achieve:
Set explicit OAuth scopes (see documentation) to your Apps Script project manifest (appsscript.json). In this case you need to add the following:
{
...
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/analytics.readonly"
}
}
Then you need to separate the method parameters from the fetch options. The fetch options need to be stringified and added to payload. You also need to set the contentType to JSON.
const options = {
entry: { propertyId: "263290444"},
// etc.
}
const response = UrlFetchApp.fetch(
'https://analyticsdata.googleapis.com/v1alpha:runReport',
{
method: 'POST',
muteHttpExceptions: true,
headers: {
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
},
contentType: 'application/json; charset=utf-8',
payload: JSON.stringify(options)
}
)
After that, you may use the response as you were doing before.
Note that Bearer and the token need to be separated by a space, which your code does not have. It's hard to see because of the concatenation and that why I usually use template literals (see documentation).
References
Authorization scopes | Set explicit scopes (Google Apps Script Guides)
UrlFetchApp.fetch(url, params) (Google Apps Script Reference)
Template literals (MDN)

uploading image using file_picker flutter to a nodejs server

I have an api which gives the following data as response:
{
"status": 200,
"msg": "Data Found",
"data": {
"id": 104,
"firstName": "aaa",
"lastName": "aaa",
"surname": "aaa",
"email": "email#email.care",
"phone": "090909090",
"age": "23",
"gender": "M",
"height": "163",
"bloodGroup": null,
"weight": "72",
"status": null,
"fileId": 228,
"password": "pass",
"file": {
"id": 228,
"filename": "images.jpg",
"path": "user/images1613558976577.jpg",
"alt": "shafa care"
}
},
"success": true,
"token": "some token",
"userAccess": "some data"
}
The "file" parameter in the response is used to hold the image that the user uploads. For my update method, the user needs to pass their token as header for the update api. For updating the file parameter i have tried many different ways just to update the user image. The below code is using multipart form data to update the existing file image.
Future<AuthModel> updateImage(File imageFile, AuthModel authModel) async{
final String _accessToken = '${authModel.token}';
final String url =
'${GlobalConfiguration().getString('api_base_url')}auth/user/update';
var stream = new http.ByteStream(imageFile.openRead());
var length = await imageFile.length();
var uri = Uri.parse(url);
var request = new http.MultipartRequest("POST", uri);
request.headers['Authorization'] = _accessToken;
// request.headers['Content-Type'] = 'multipart/form-data';
var multipartFile = new http.MultipartFile('file', stream, length, filename: basename(imageFile.path));
request.files.add(multipartFile);
var response = await request.send();
print("updating: " + response.statusCode.toString());
response.stream.transform(utf8.decoder).listen((event) {
currentUser = authModelFromJson(event);
print("updating img: " + event);
});
return currentUser;
}
The above function does not update my file parameter even when the data is found. I just get the same old response. filepicker is also sending the correct image path that the user chooses from the gallery. I have also tried using http.client.post method using a token as the header and 'file' parameter as the body but then data is not found as the api only accepts form-data when an image is being uploaded.
It works in postman using form-data post method.
I am new to flutter and still learning. I have been stuck here for days without any solution. How can i update the file parameter from my flutter application? Any help is appreciated.
This is sample code. I hope this may help you !
static Future<bool> uploadFileAsFormData(
String url, File file) async {
try {
var uri = Uri.parse(_buildUrl(url));
var request = http.MultipartRequest('POST', uri);
request.files.add(await http.MultipartFile.fromPath('file', file.path));
var res = await request.send();
if (res.statusCode == 200) {
return true;
} else {
return false;
}
} catch (err) {
return false;
}
}
You can use this Dio to upload the image as shown by the following code:
Dio dio = Dio();
var formData = FormData();
for (var file in filePath) {
formData.files.addAll([MapEntry("files", await MultipartFile.fromFile(file)),]);
print(formData.length);
}
var response = await dio.post(url
data: formData,
options: Options(headers: {
'Authorization': _accessToken
}));
if(response.statusCode == 200){
print(response.data.toString();
}

Send data to Influxdb using Google app script

I'm trying to send the data to Influxdb using Google app script with the below code but I always run into Bad Request error. The same works when I send the data using the Influxdb API. Unable to figure out what am I missing here. Any suggestions would be appreciated.
function dataentry() {
var response;
var tags = {
"PROGRAM":"Migration"
}
var fields = {
"TESTED_BY": "Peter",
"RESULT":1,
"STATUS":"Fail"
}
var data = {"measurement":"testing","tags":tags,"time":,"fields":fields};
Logger.log(JSON.stringify(data));
var options = {
"method" : "post",
"muteHttpExceptions" : true,
"contentType": "application/json",
"payload" : JSON.stringify(data)
//"payload" : data
};
try {
response = UrlFetchApp.fetch('http://xx.xx.xx.xx:8086/write?db=mydbb', options);
Logger.log(response.getContentText());
}
catch(err) {
Logger.log(err);
}
}
Output: Exception: Bad request: http://xx.xx.xx.xx:8086/write?db=mydbb
Example of the Influxdb http write API -
curl -i -XPOST http://xx.xx.xx.xx:8086/write?db=mydbb --data-binary "testing,PROGRAM=Migration TESTED_BY=\"Peter\",STATUS=\"Fail\",RESULT=1"

Autodesk Forge: Translation Failed - File to bucket data: fileContent

I've been following this viewer walkthrough tutorial (node.js), for uploading and showing a file in the forge viewer.
I've been using angular to recreate the example, except instead of a user uploading a file, the file is hardcoded into the app from my assets folder for testing purposes.
The issue comes to when i try and translate the revit file into svf.
I know there isn't an issue with the revit file as i have used models.autodesk.io to check if all is good.
I can successfully create a bucket and post a job, but when calling the translation status to check if translation is completed, i receive this:
{
"type": "manifest",
"hasThumbnail": "false",
"status": "failed",
"progress": "complete",
"region": "US",
"urn": "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6OTA0ZmZmYmMtODI1Ni00OWY2LWI3YzYtNDI3MmM1ZDlmNDljL2RyYXBlLnJ2dA",
"version": "1.0",
"derivatives": [
{
"name": "drape.rvt",
"hasThumbnail": "false",
"status": "failed",
"progress": "complete",
"messages": [
{
"type": "error",
"code": "Revit-UnsupportedFileType",
"message": "<message>The file is not a Revit file or is not a supported version.</message>"
},
{
"type": "error",
"message": "Possibly recoverable warning exit code from extractor: -536870935",
"code": "TranslationWorker-RecoverableInternalFailure"
}
],
"outputType": "svf"
}
]
}
I'm pretty sure my code for translating a project is correct, i think the issue is coming from uploading the file to my bucket.
The body structure for the PUT request must contain the contents of the file.
Here is my code for loading and reading a file using XMLHttpRequest and FileReader
loadFile(bucketKey, accessToken) {
const reader: XMLHttpRequest = new XMLHttpRequest();
reader.open('GET', './assets/drape.rvt', true);
reader.responseType = 'blob';
reader.onloadend = (request) => {
const blob: Blob = reader.response;
console.log(blob); //returns BlobĀ {size: 372736, type: "text/xml"}
// Create file from blob
const modelFile: File = new File([blob], 'drape.rvt');
this.readFile(bucketKey, accessToken, modelFile);
};
reader.send();
}
readFile(bucketKey, accessToken, modelFile) {
const myReader: FileReader = new FileReader();
myReader.readAsArrayBuffer(modelFile);
myReader.onloadend = (e) => {
const arrayBuffer: ArrayBuffer = myReader.result as ArrayBuffer;
this.fileToBucket(bucketKey, accessToken, arrayBuffer);
};
}
And the put request:
fileToBucket(bucketKey, accessToken, fileContent) {
const encodedBucketKey = encodeURIComponent(bucketKey);
const encodedFileName = encodeURIComponent('drape.rvt');
const uploadURI = `https://developer.api.autodesk.com/oss/v2/buckets/${encodedBucketKey}/objects/${encodedFileName}`;
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/octet-stream',
Authorization: 'Bearer ' + accessToken
})
};
const body = {
data: fileContent
};
this.http.put(uploadURI, body, options)
.subscribe(
success => {
// URL safe base64 encoding
const urn = btoa(success.objectId);
this.translateObject(accessToken, urn);
}, error => {
console.log('fileToBucket');
console.log(error);
});
}
I'm assuming that the file content is the issue, here is the equivalent using node.js for the tutorial: PUT request read file.
You can use a utility web app like https://oss-manager.autodesk.io/ to check if the file you previously uploaded is correct (by downloading it or trying to translate it to SVF through the app's UI) and upload the file using this utility and then try to translate it with your app. It can also be used to delete all the derivatives for a given file in your bucket.
That could help narrow down the issue.
It's also possible that the file was not correctly uploaded the first time (at a certain point when you were still testing things) and so the translation failed back then and now it won't try to translate the file again. You can force the translation to take place by adding x-ads-force to the POST Job request with value "true" - see https://forge.autodesk.com/en/docs/model-derivative/v2/reference/http/job-POST/