Upload attachment failure Facebook Attachment Upload API - facebook-graph-api

I am trying to add an attachment to my message via facebook attachment upload API.
I am sending from a page (that I am an admin of) to a user that has sent message to my page.
Simple text messages are sent and also attachments as type 'file' is also working correctly. But when I put in 'image' or 'audio' as an attachment, the facebook sends response:
error: {
message: '(#100) Upload attachment failure.',
type: 'OAuthException',
code: 100,
error_subcode: 2018047,
fbtrace_id: 'AzfHWxf3AnikXiCCC-hYJOu'
}
Here is my code:
let messageData = {
message: {
attachment: {
**type: "image"**,
payload: {
is_reusable: true,
url: <url of the image>
}
}
}
}
let data = await axios.post(`https://graph.facebook.com/v8.0/me/message_attachments?access_token=${accessToken}`, messageData)

Upload attachment failure. A common way to trigger this error is that the provided media type does not match type of file provided int the URL
from official docs

Related

How do I make putObject request to presignedUrl using s3 AWS

I am working with AWS S3 Bucket, and trying to upload image from react native project managed by expo. I have express on the backend. I have created a s3 file on backend that handles getting the presigned url, and this works, and returns the url to the front end inside this thunk function from reduxjs toolkit. I used axios to send request to my server, this works. I have used axios and fetch to try the final put to the presigned url but when it reached the s3 bucket there is nothing in the file just an empty file with 200 bytes everytime. When I use the same presigned url from postman and upload and image in binary section then send the post request the image uploads to the bucket no problems. When I send binary or base64 to bucket from RN app it just uploads those values in text form. I attempted react-native-image-picker but was having problems with that too. Any ideas would be helpful thanks. I have included a snippet from redux slice. If you need more info let me know.
redux slice projects.js
// create a project
// fancy funtion here ......
export const createProject = createAsyncThunk(
"projects/createProject",
async (postData) => {
// sending image to s3 bucket and getting a url to store in d
const response = await axios.get("/s3")
// post image directly to s3 bucket
const s3Url = await fetch(response.data.data, {
method: "PUT",
body: postData.image
});
console.log(s3Url)
console.log(response.data.data)
// make another request to my server to store extra data
try {
const response = await axios.post('/works', postData)
return response.data.data;
} catch (err) {
console.log("Create projects failed: ", err)
}
}
)

Trying to upload video to vimeo via API, resumable approach, getting 412 response

I'm trying to upload a video via the presumable approach, I'm able to get the upload link through PHP curl and jQuery ajax
then I'm trying to upload the file but I receive 412 error.
Failed because: Error: Tus: unable to resume upload (new upload cannot be created without an endpoint), originated from request (method: HEAD, URL: https://asia-files.tus.vimeo.com/files/vimeo-prod-src-tus-asia/123456789, response code: 412, response text: , request id: n/a) (123456789 is just a dummy number here)
I tried to remove the headers but I get 404 error which seems worse to me, so I kept the headers.
I'm unable to upload the file via Postman (testing API software)which is also weird, PATCH with binary data in body, I get a response 204 that there is no content.
When I try the HEAD request for the upload link via Postman (testing API software), I get status 200.
Expected behavior
The file should have been uploaded to Vimeo in chunks...
Used Tus-JS-client version: [1.0.0]
CDN: ttps://cdn.jsdelivr.net/npm/tus-js-client#latest/dist/tus.min.js
function resumable(url) {
let file = $('#video')[0].files[0];
var chunkSize = 128;
// Create a new tus upload
const upload = new tus.Upload(file, {
uploadUrl: url,
headers:{
"Tus-Resumable": "1.0.0",
"Accept": "application/vnd.vimeo.*+json;version=3.4"
},
//endpoint: url,
chunkSize,
retryDelays: [0, 3000, 5000, 10000, 20000],
metadata: {
filename: file.name,
filetype: file.type,
},
uploadSize: file.size,
onError(error) {
console.log(`Failed because: ${error}`);
},
onProgress(bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log(bytesUploaded, bytesTotal, `${percentage}%`);
},
onSuccess() {
console.log('Download %s from %s', upload.file.name, upload.url);
},
})
// Check if there are any previous uploads to continue.
upload.findPreviousUploads().then(function (previousUploads) {
// Found previous uploads so we select the first one.
if (previousUploads.length) {
upload.resumeFromPreviousUpload(previousUploads[0])
}
// Start the upload
upload.start()
})
}
tus-js-client documentation has a Vimeo-specific example

Google.cloud.speech.v1.RecognizeRequest can't recognize bucket?

I follow community google cloud platform to connect to twilio to capture voice call and save to bucket. However, it can't translate the voice, due to the following error message. Does anyone know why
google.cloud.speech.v1.RecognizeRequest can't recognize bucket?
(url: https://cloud.google.com/community/tutorials/cloud-functions-twilio-voice-record)
"Error: .google.cloud.speech.v1.RecognizeRequest#bucket is not a field: undefined
at Error (native)
at MessagePrototype.set (/user_code/node_modules/#google-cloud/speech/node_modules/protobufjs/dist/protobuf.js:2490:35)
at MessagePrototype.set (/user_code/node_modules/#google-cloud/speech/node_modules/protobufjs/dist/protobuf.js:2483:38)
at Message (/user_code/node_modules/#google-cloud/speech/node_modules/protobufjs/dist/protobuf.js:2411:34)
at serialize (/user_code/node_modules/#google-cloud/speech/node_modules/grpc/src/node/src/protobuf_js_5_common.js:81:23)
at ServiceClient.Client.makeUnaryRequest (/user_code/node_modules/#google-cloud/speech/node_modules/grpc/src/node/src/client.js:530:17)
at apply (/user_code/node_modules/#google-cloud/speech/node_modules/lodash/lodash.js:499:17)
at ServiceClient.wrapper [as recognize] (/user_code/node_modules/#google-cloud/speech/node_modules/lodash/lodash.js:5356:16)
at /user_code/node_modules/#google-cloud/speech/src/v1/speech_client.js:111:41
at timeoutFunc (/user_code/node_modules/#google-cloud/speech/node_modules/google-gax/lib/api_callable.js:177:12)"
timestamp: "2017-08-07T17:27:02.601Z"
I solved this with the following code:
var config = {
sampleRateHertz: 8000,
encoding: 'LINEAR16',
languageCode: 'en-US'
};
var uri = `gs://${object.bucket}/${object.name}`;
var audio = {
uri : uri
};
var request = {
config: config,
audio: audio
};
// Transcribe the audio file
return speech.recognize(request)
By the way: I also had to comment out the 'annotate' function below to get it to work

Using pre-signed S3 URL using AFNetworking to upload from an iOS app

I am trying to upload an image from my iPhone app to S3 and then store the S3 url back into my rails app. I am not supposed to embed credentials in the iOS app so the approach i'm taking is to:
Step 1. iPhone app sends a request to my rails server to return a pre-signed S3 URL for uploading the image.
Step 2. Rails server uses aws-sdk gem to generate and return a pre-signed URL How to store data in S3 and allow user access in a secure way with rails API / iOS client?
Step 3. iPhone app uses AFNetworking to post the NSData of the image to S3.
I did my best to follow all the directions I found online but it's not working and the result of step 3 returns Error 401 forbidden. Since I am a newbie at this I don't even know what I am doing wrong.
In Step 2, my code looks like this:
def getS3Url
s3 = AWS::S3.new(
:access_key_id => "MY S3 KEY",
:secret_access_key => "MY SECRET ACCESS KEY"
)
object = s3.buckets[params["bucket"]].objects[params["path"]]
#s3url = object.url_for(:write, { :expires => 20.minutes.from_now, :secure => true }).to_s
end
The url returned from step2 looks something like this: https://s3.amazonaws.com/myapp-bucket-name/images/avatar/user1.png?AWSAccessKeyId=[access key id]&Expires=[expiration timestamp]&Signature=[Signature]
And once i get that URL i try to post to it by doing the following:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[responseObject valueForKey:#"s3url"] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:jpegData name:#"file" fileName:self.filename mimeType:#"image/png"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
In this code I extract the url out from the returned object with [responseObject valueForKey:#"s3url"], and then pass that as the URL to post. But it doesn't work. Here's the log when i run it in XCode:
Error: Error Domain=AFNetworkingErrorDomain Code=-1011 "Request failed: forbidden (403)" UserInfo=0x156daaf0 {NSErrorFailingURLKey=https://s3.amazonaws.com/myapp-bucket-name/images/avatar/user1.png?AWSAccessKeyId=[access key id]&Expires=[expiration timestamp]&Signature=[Signature], NSLocalizedDescription=Request failed: forbidden (403), NSUnderlyingError=0x156aef90 "Request failed: unacceptable content-type: application/xml", AFNetworkingOperationFailingURLResponseErrorKey= { URL: https://s3.amazonaws.com/myapp-bucket-name/images/avatar/user1.png?AWSAccessKeyId=[access key id]&Expires=[expiration timestamp]&Signature=[Signature] } { status code: 403, headers {
Connection = close;
"Content-Type" = "application/xml";
Date = "Mon, 30 Jun 2014 07:21:33 GMT";
Server = AmazonS3;
"Transfer-Encoding" = Identity;
"x-amz-id-2" = "FJwEeOjV1/osJKgKeHO+/OjXVBEbvW09XxNX2kn1UYIuHswU+LKh0mJODRJDNLXm";
"x-amz-request-id" = 46E84D0967B6D4CD;
} }}
At this point I don't even know what I am doing wrong. Maybe I'm not even posting to the correct URL. Maybe I need to do more than just POST. I spent the entire weekend trying to figure this out and failed. Could someone please help? Thanks.
I faced a similar "challenge". I had to upload with AFNetworking 2.0 an image to an S3 bucket with a pre-signed URL from my server. In one of my many try and error attempts of doing it I got the same 403 error, and what happened to me was that I had to put the right headers in the request:
Content-Type with the mime type of the image
x-amz-acl as public-read for my bucket configuration
The Content-Length seemed to be optional and note that I haven't uploaded the image in multipart.
So this is what I ended up doing:
+(void) uploadImage:(UIImage *)image atUrl:(NSString *)url withMimeType:(NSString *)mimeType withSuccess:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure {
NSData *imageData = UIImageJPEGRepresentation(image, 0.1);
NSURL *requestURL = [NSURL URLWithString:url];
AFHTTPSessionManager *client = [[AFHTTPSessionManager alloc] initWithBaseURL:requestURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"PUT"];
[request setValue:mimeType forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:imageData];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)[imageData length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"public-read" forHTTPHeaderField:#"x-amz-acl"];
[request setURL:requestURL];
NSURLSessionDataTask *task = [client dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error == nil) {
if (success) {
success(responseObject);
}
} else {
if (failure) {
failure(error);
}
}
}];
[task resume];
}
where url is the presigned url that I've got from my server. Check the JPEG compression that I have at 0.1 as you might want a different compression. In my case the image quality is not important.
Adding to josebama's answer above,
I didnt need to add "x-amz-acl" header field, but instead I added "x-amz-date" and "authorization" headers. Both these headers were returned, from the an API that handled communication with Amazon service, along with a signed URL. The upload to the URL was only successful when I added the two aforementioned header values.
Simply including the "x-amz-acl" header, in my case, would result in a failure to upload.
Perhaps some server side parameters differ or perhaps some setup parameters for amazon vary, needless to say that a solution that works for me might not work for others so it might be good a idea to look at your backend setup a bit..

Facebook Media Attachment - fallback URL for 'music' type?

I'm using Facebook's Legacy REST API to publish MP3 media attachments to users' streams (as the new Graph API does not yet support audio). This renders the audio in Facebook's own media player as expected. However, because the player is a Flash component, it doesn't render on iOS devices and prompts for a Flash upgrade. I'd like to provide a fallback URL instead so the user can click through to an external site with an HTML5 audio player instead.
Is there a way of doing this? Supplying the href parameter in either the attachment object:
access_token = 1234567890.....,
format = 'json',
privacy = {
value: 'EVERYONE'
},
message = 'Message goes here...',
attachment = {
href: 'http://www.google.com',
media:[{
type:'mp3',
src:'http://www.looptvandfilm.com/blog/Radiohead - In Rainbows/01 - Radiohead - 15 Step.MP3',
title:'15 Step',
artist:'Radiohead',
album:'In Rainbows'
}]
}
or in the post object itself:
access_token = 1234567890.....,
format = 'json',
privacy = {
value: 'EVERYONE'
},
message = 'Message goes here...',
href: 'http://www.google.com',
attachment = {
media:[{
type:'mp3',
src:'http://www.looptvandfilm.com/blog/Radiohead - In Rainbows/01 - Radiohead - 15 Step.MP3',
title:'15 Step',
artist:'Radiohead',
album:'In Rainbows'
}]
}
does not seem to have any effect...
Am I therefore restricted to using the flash media type, supplying my own SWF player and image?
You can try the action_links array property on the post object to add a custom link for the user.
action_links = [("text":"alternate site link text here","href":"alternate url here"}]
You could try something like YepNope to test for iOS and load a different script based on the test.
yepnope({
test: '<test for iOS here>',
yep: '/scripts/scriptDefiningUrl.js',
nope: '/scripts/scriptDefiningFallbackUrl.js',
callback: function (url, result, key) {
alert('scripts loaded!');
}
});