@onboardmobility/whatsapp
Version:
Utility class to connect to WhatsApp APIs
322 lines (286 loc) • 9.57 kB
JavaScript
;
const axios = require("axios");
const fs = require('fs');
let TOKEN = '';
let TOKEN_EXP = '';
/**
* Envs vars
*/
const { WA_BASE_URL, WA_TOKEN, WA_CHECK } = process.env;
/**
* Process the incoming message from WhatsApp
* @param {Object} message the message object
* @return {Object} the return data: body, author, fromMe, senderName, type, result, attachments
*/
async function processIncomingMessages(message) {
try {
const { contacts, messages } = message;
if (!contacts) {
return { result: false };
}
const profile = contacts[0];
const { text, type, image, document, voice, interactive, video } = messages[0];
const attachments = [];
let body;
// Find token
const token = await authorize();
if (interactive) {
if (interactive.type === 'list_reply') {
return {
body: interactive.list_reply.id, author: profile.wa_id, fromMe: false,
senderName: profile.profile.name, type: interactive.type, result: true, attachments
};
} else {
return {
body: interactive.button_reply.id, author: profile.wa_id, fromMe: false,
senderName: profile.profile.name, type: interactive.type, result: true, attachments
};
}
} else if (image) {
body = image.caption;
attachments.push({
authorization: `Bearer ${token}`,
contentUrl: `${WA_BASE_URL}/v1/media/${image.id}`,
name: image.id + '.' + image.mime_type.split('/')[1],
contentType: image.mime_type
});
} else if (text) {
body = text.body;
} else if (document) {
body = document.caption;
attachments.push({
authorization: `Bearer ${token}`,
contentUrl: `${WA_BASE_URL}/v1/media/${document.id}`,
name: document.filename,
contentType: document.mime_type
});
} else if (voice) {
body = 'áudio';
attachments.push({
authorization: `Bearer ${token}`,
contentUrl: `${WA_BASE_URL}/v1/media/${voice.id}`,
name: 'áudio',
contentType: voice.mime_type
});
} else if (video) {
body = 'vídeo';
attachments.push({
authorization: `Bearer ${token}`,
contentUrl: `${WA_BASE_URL}/v1/media/${video.id}`,
name: video.id + '.' + video.mime_type.split('/')[1],
contentType: video.mime_type
});
}
return {
body, author: profile.wa_id, fromMe: false,
senderName: profile.profile.name, type, result: true, attachments
};
} catch (e) {
return { result: false };
}
}
/**
* Send message to the WhatsApp
* @param {Object} the params:
* - {String} text: the text to send
* - {String} to: to number to send
* @return {Object} the post return or false if failed
*/
async function sendMessage({ text, to }) {
try {
fs.writeFileSync('token.txt', TOKEN);
console.log('sendMessage');
console.log(TOKEN);
if (!to || !text) {
return;
}
// Find token
const token = await authorize();
// Verify user before sending
const verification = await validateUser({to, token});
const {contacts} = verification.data;
const status = contacts[0].status;
if (status === 'valid') {
return axios.post(`${WA_BASE_URL}/v1/messages`, {
'to': to,
'type': 'text',
'recipient_type': 'individual',
'text': {
'body': text
}
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}});
}
return false;
} catch (e) {
console.log(e);
return false;
}
}
/**
* Send file to the WhatsApp
* @param {Object} the params:
* - {String} url: the url of the document
* - {String} filename: the name of the document
* - {String} to: to number to send
* - {String} caption: the image caption
* @return {Object} the post return or false if failed
*/
async function sendFile({ to, url, filename, caption }) {
try {
if(!to) {
return;
}
// Find token
const token = await authorize();
// Verify user before sending
const verification = await validateUser({to, token});
const {contacts} = verification.data;
const status = contacts[0].status;
if (status === 'valid') {
const body = {
'to': to,
'recipient_type': 'individual',
};
let image = filename && (filename.includes('jpg') || filename.includes('png') || filename.includes('jpeg'));
let document = !image;
if (image) {
body.type = 'image';
body.image = {};
body.image.link = url;
body.image.caption = caption ? caption : filename;
} else if (document) {
body.type = 'document';
body.document = {};
body.document.link = url;
body.document.caption = filename;
body.document.filename = filename;
}
return axios.post(`${WA_BASE_URL}/v1/messages`, body, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}});
}
return false;
} catch (e) {
return false;
}
}
/**
* Validate a user before sending message
* Complains with https://developers.facebook.com/docs/whatsapp/api/contacts
* @param {Object} the params:
* - {String} token: the auth token
* - {String} to: to number to send
* @return the post request
*/
async function validateUser({ to, token }) {
if (WA_CHECK) {
if (!to.startsWith('+')) {
to = `+${to}`;
}
return axios.post(`${WA_BASE_URL}/v1/contacts`, {
'blocking': 'wait',
'contacts': [ to ],
'force_check': false
},
{headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}});
} else {
return {
"data": {
"contacts": [
{
"status": "valid"
}
]
}
};
}
}
/**
* Send a list or button message to the user as of https://developers.facebook.com/docs/whatsapp/guides/interactive-messages
* @param {Object} params the data needed:
* to: destination
* header: optional header text
* body: the message body
* footer: option footer text
* actions: the list of actions
* type: button or list
*/
async function sendInteractive({ to, header, body, footer, actions, type }) {
try {
if (!to || !body) {
return;
}
// Find token
const token = await authorize();
// Verify user before sending
const verification = await validateUser({to, token});
const {contacts} = verification.data;
const status = contacts[0].status;
if (status === 'valid') {
const sendBody = {
'to': to,
'type': 'interactive',
'recipient_type': 'individual',
'interactive': {
'type': type,
'body': {
'text': body
},
'action': actions
},
};
if (header) {
sendBody.interactive.header = {
'type': 'text',
'text': header
};
}
if (footer) {
sendBody.interactive.footer = {
'text': footer
};
}
return axios.post(`${WA_BASE_URL}/v1/messages`, sendBody, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}});
}
return false;
} catch (e) {
return false;
}
}
/**
* Auth the user on WhatsApp servers
* @return {String} the auth token
*/
async function authorize() {
const now = new Date().getTime();
const exp = TOKEN_EXP ? new Date(TOKEN_EXP) : 0;
if (!TOKEN || now > exp) {
const response = await axios.post(`${WA_BASE_URL}/v1/users/login`, {},
{headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${WA_TOKEN}`
}
});
if (response && response.data) {
const {users} = response.data;
const {token, expires_after} = users[0];
TOKEN = token;
TOKEN_EXP = expires_after;
}
}
return TOKEN;
}
module.exports = { processIncomingMessages, sendMessage, sendFile, sendInteractive };