How to send PDF file object from Facebook messaging API - node.js

I have developed a facebook messenger app in Node.js.
I am using PDFKit to generate a PDF and send it to the user from the messenger bot. The problem I am facing is I am not able to send the generated file object.
generatePDF.js
require('dotenv').config("./env");
const getStream = require('get-stream')
const PDFDocument = require('pdfkit');
const fs = require('fs');
async function createPDF(name) {
const doc = new PDFDocument({
layout: 'landscape',
size: 'A4',
});
doc.rect(0, 0, doc.page.width, doc.page.height).fill('#fff');
``
doc.fontSize(10);
doc.image('src/airtable/assets/corners.png', -1, 0, { scale: 0.585 }, { fit: [doc.page.width, doc.page.height], align: 'center' })
doc
.font('src/airtable/fonts/Pinyon Script 400.ttf')
.fontSize(65)
.fill('#125951')
.text(`${name}`, 240, 240, {
// width: 500,
// align: 'center'
});
doc.end();
return await getStream.buffer(doc)
}
module.exports = { createPDF}
Invoking the above function after receiving specific postback
main.js
const pdf= require('./generatePDF')
name = "John"
const generated_pdf = await pdf.createPDF(name)
sendMedia(sender_psid, generated_pdf )
async function sendMedia(sender_psid, file) {
try {
let response = {
"attachment": {
"type": "file",
"payload": file
}
}
}
callSendAPI(sender_psid, response);
}
catch (e) {
console.log("Error cert ", e)
}
}
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
};
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v7.0/me/messages",
"qs": { "access_token": process.env.FB_PAGE_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!!!');
} else {
console.error("Unable to send message:" + err);
}
});
}
How can I send the file object without a URL and without fetching locally?
any help or advice is appreciated!

There is no such type ("application/pdf"), for sending attachments like a PDF you'd use the file type. Also, as stated in the docs, there is no "filedata" parameter, instead you'd use "payload".
Docs can be found here by the way:
https://developers.facebook.com/docs/messenger-platform/reference/send-api/

Related

Image uploads in react native not reaching server

I am sending images to a nodeJs server using react native. I have noticed that when i make the request, there is an image file in the request but the response fails saying photos are needed for file upload. The request however works perfectly on postman.
Here is a sample of the code. I am using react native image crop picker to select the image.
const choosePhotoFromLibrary = () => {
ImagePicker.openPicker({
width: 300,
height: 400,
cropping: true,
// multiple: true,
multiple: false,
mediaType: 'photo'
}).then((image) => {
setPhotos(image.path)
}).catch(err => {
console.log(err);
})
}
getStoreId()
const createProduct = async () => {
console.log(typeof photos);
const data = new FormData()
data.append('name', productName)
data.append('description', description)
data.append('price', price)
data.append('category', productCategory)
data.append('sub-category', productSubCategory)
data.append('condition', productCondition)
data.append('photos', photos)
data.append('type', `Women's wear`)
console.log(data);
var config = {
method: 'post',
url:url,
headers: {
'token': token,
'Content-Type': 'multipart/form-data'
},
data: data
};
try {
const product = await axios(config)
console.log(product);
} catch (err) {
console.log(err.response);
}
Instead of
data.append('photos', photos)
write like this
data.append('photos', {
name: "Example.jpg",
uri: photos, // This should be something like 'file://...'
type: "image/jpg" // MIME type of file
})

Pusher - with Wix HTTP Functions

I am trying to integrate Pusher with the Wix HTTP Functions
For example:
A GET request is made to the Wix site ( path: '/findItems' ). After the request is made, I want to check for new insertion of items in the database. This, I found, I could do with the afterInsert hook. When the hook is hooked, I want to trigger the Pusher.
This is the code I am currently using http-functions.js:
import { ok, created, notFound, serverError } from 'wix-http-functions';
import wixData from 'wix-data';
import Pusher from "pusher";
const pusher = new Pusher({
appId: "xxxxx",
key: "xxxxxxxxxxxxxxx",
secret: "xxxxxxxxxxxx",
cluster: "xxxx",
useTLS: true
});
export function get_findItems(request) {
let options = {
"headers": {
"Content-Type": "application/json"
}
};
return wixData.query("users")
.eq("firstName", request.path[0])
.eq("lastName", request.path[1])
.find()
.then((results) => {
if (results.items.length > 0) {
options.body = {
"items": results.items
};
return ok(options);
}
options.body = {
"error": `'${request.path[0]} ${request.path[1]}' was not found`
};
return notFound(options);
})
.catch((error) => {
options.body = {
"error": error
};
return serverError(options);
});
}
export function post_newItem(request) {
let options = {
"headers": {
"Content-Type": "application/json"
}
};
return request.body.text()
.then( (body) => {
return wixData.insert("users", JSON.parse(body));
} )
.then( (results) => {
options.body = {
"inserted": results
};
return created(options);
} )
.catch( (error) => {
options.body = {
"error": error
};
return serverError(options);
} );
}
export function users_afterInsert(item, context) {
let hookContext = context;
pusher.trigger("channel", "action", {
firstName: item.firstName,
lastName: item.lastName
});
return item;
}
But unfortunately, Pusher does not get triggered. After Debugging, I found that the Pusher package is installed and working but not triggering only in the afterInsert hook!
Any help is greatly appreciated!
Thanks !
The code for the afterInsert hook needs to be in a backend file named data.js, not in the http-functions.js file as you have it now.

Microsoft Graph API outlook send attachments

How do you send attachments with the Microsoft graph outlook API? I understand everything for sending attachments up until the content bytes. The files that I need to send are a word document a pdf and a jpeg Is it asking me to turn the file into bytes, if so how would I do that? I am using node.js and I have the following code:
exports.send_mail = async function(req, res, next) {
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
//read test.html
//so you have to wait for the file to read then send it
message = fs.readFileSync('views/test.html', 'utf8');
console.log(rawImage.data.toString('utf8'))
try {
mailMess ={
message:{
subject: 'This is a test',
body:{
ContentType: 'HTML',
Content: message
},
ToRecipients:[
{
EmailAddress:{
Address: 'name#email.com'
}
}
],
"attachments": [
{
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "attachment.jpeg",
"contentBytes": "not sure what to put here"
}
]
}
}
//sendmail
const result = await client
.api('/me/sendmail')
.version('v1.0')
.post(mailMess);
res.status('202')
parms.messages = result.value;
res.redirect('/');
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
}
I found out that param takes the file encoded as base64

Show json url to messenger bot

I want to show data from JSON URL on my facebook messenger bot. I've tried with a lot of code approach. However, I couldn't still get it. I just could show the data the terminal with console.log.
This is the code I use to get data from JSON URL:
const ambilDataProfil = (sender_psid) => {
//sorry this url below is not valid I write intentionally for my privacy data.
request({
url: 'https://sorry-url-privately.firebaseio.com/server/saving-data/users.json',
method: "GET",
}, function(error, response, body){
let jsonBody = JSON.parse(response.body);
let resp = jsonBody.Ndus;
console.log(resp);
let respon = {"text": "resp"};
callSendAPI(sender_psid, respon);
}
// console.log(body.Ndus.goldar);
);
};
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!')
} else {
console.error("Unable to send message:" + err);
}
});
}

Adding 'typing_on' sender action bubble before each response from Wit.ai chatbot

I've built a flow-base chat bot using FB messenger, Wit.ai and node.js. It's working well, but in order to make the interaction seem more natural I want my bot to pause for a short while and appear to be typing each of its responses.
I want the 'typing' bubble to be displayed briefly before each response my bot sends, ideally being able to define the time the bubble is visible for before the response is sent. At the moment there are sections of my conversation where the bot sends consecutive messages and they are all sent too quickly at once.
The FB Messenger Send API says that either the 'message' or 'sender_action' property must be set. I've tried setting both like so:
const fbMessage = (id, text) => {
if(fruits.apples.indexOf(text) >= 0 || fruits.oranges.indexOf(text) >= 0) {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on",
message: {
attachment: {
"type": "image",
"payload": {
"url": text
}
}
},
});
} else {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on",
message: { text },
});
}
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
But I get the following error:
I'm not sure what I need to do - I'm assuming I've got to set up some sort of 'sender_action' bot response that's triggered before each conversational response but I don't know how I'd do this.
To display the typing bubble you simply send a sender action of typing_on. This displays the typing indicator for up to 20 seconds, during which time you will send the actual message you want to send.
The JSON for this would be:
{
"recipient":{
"id":"USER_ID"
},
"sender_action":"typing_on"
}
The call is documented here
Got it working, can't work out how to control bubble timing but it's fine for now. The code below will make the typing bubble display briefly before each of my bot's responses without mucking up the flow of my conversation.
FB Messenger code:
const typingBubble = (id, text) => {
var body = JSON.stringify({
recipient: { id },
"sender_action":"typing_on"
});
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
const fbMessage = (id, text) => {
if(scenarioCombos.trends.indexOf(text) >= 0 || scenarioCombos.disruptions.indexOf(text) >= 0) {
var body = JSON.stringify({
recipient: { id },
message: {
attachment: {
"type": "image",
"payload": {
"url": text
}
}
},
});
} else {
var body = JSON.stringify({
recipient: { id },
message: { text },
});
}
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
Wit.ai send action code (within 'actions'):
send({sessionId}, {text}) {
const recipientId = sessions[sessionId].fbid;
if (recipientId) {
return typingBubble(recipientId, text), fbMessage(recipientId, text)
.then(() => null)
.catch((err) => {
console.error(
'Oops! An error occurred while forwarding the response to',
recipientId,
':',
err.stack || err
);
});
} else {
console.error('Oops! Couldn\'t find user for session:', sessionId);
return Promise.resolve()
}
},

Resources