UNPKG

@onboardmobility/whatsapp

Version:

Utility class to connect to WhatsApp APIs

322 lines (286 loc) 9.57 kB
'use strict'; 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 };