new(whatsapp.gblib): General Bots WhatsApp provider.

This commit is contained in:
Rodrigo Rodriguez 2022-07-12 13:30:12 -03:00
parent 844004fa01
commit 9e82beaf19
7 changed files with 466 additions and 223 deletions

57
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "botserver",
"version": "2.0.153",
"version": "2.0.156",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -3240,6 +3240,11 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.18.2.tgz",
"integrity": "sha512-+0P+PrP9qSFVaayNdek4P1OAGE+PEl2SsufuHDRmUpOY25Wzjo7Atyar56Trjc32jkNy4lID6ZFT6BahsR9P9A=="
},
"@pedroslopez/moduleraid": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@pedroslopez/moduleraid/-/moduleraid-5.0.2.tgz",
"integrity": "sha512-wtnBAETBVYZ9GvcbgdswRVSLkFkYAGv1KzwBBTeRXvGT9sb9cPllOgFFWXCn9PyARQ0H+Ijz6mmoRrGateUDxQ=="
},
"@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@ -12464,6 +12469,15 @@
"integrity": "sha512-iEjGZ94OBMcESxnLorXNjJmtd/JtQYXUVrQpfwvtAKkuyawRmv+2LM6nqyOsOJkISEYbyY6ziudRE0u4VyPSVA==",
"dev": true
},
"fluent-ffmpeg": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz",
"integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==",
"requires": {
"async": ">=0.2.9",
"which": "^1.1.1"
}
},
"fn.name": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
@ -15166,6 +15180,11 @@
}
}
},
"jsqr": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz",
"integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A=="
},
"jszip": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz",
@ -17223,6 +17242,11 @@
"resolved": "https://registry.npmjs.org/node-tesseract-ocr/-/node-tesseract-ocr-2.2.1.tgz",
"integrity": "sha512-Q9cD79JGpPNQBxbi1fV+OAsTxYKLpx22sagsxSyKbu1u+t6UarApf5m32uVc8a5QAP1Wk7fIPN0aJFGGEE9DyQ=="
},
"node-webpmux": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/node-webpmux/-/node-webpmux-3.1.1.tgz",
"integrity": "sha512-vG75BAe9zKghN+Y+XsJMPdOfVyesn1MmGvd/DMxeQ6gtpB3U053yCWXO1Gl2QWXTfU1++7flTihv/yB6EEdtKQ=="
},
"nodesecurity-npm-utils": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/nodesecurity-npm-utils/-/nodesecurity-npm-utils-6.0.0.tgz",
@ -20475,6 +20499,11 @@
"uniq": "^1.0.1"
}
},
"pptxtemplater": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pptxtemplater/-/pptxtemplater-1.0.5.tgz",
"integrity": "sha512-Fr9LzjpHMG12bq1gps3i9Jy75aVVXRUzv0fPnOsd0DfZnt7doPTulkXD6mjmTf30PrEu3YvIhZSsn5R88Lylmg=="
},
"pragmatismo-io-framework": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/pragmatismo-io-framework/-/pragmatismo-io-framework-1.0.20.tgz",
@ -21362,6 +21391,11 @@
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qrcode-terminal": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz",
"integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
@ -25939,6 +25973,27 @@
}
}
},
"whatsapp-web.js": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.17.0.tgz",
"integrity": "sha512-oLl5ExnBOt0d6oIx+ksRJKkMNshnmg5b2fU2LKMPCF7XtRaAcwtrdZSEXSnBLAQShJWKMKrG5l0D32U3hOub/w==",
"requires": {
"@pedroslopez/moduleraid": "^5.0.2",
"fluent-ffmpeg": "^2.1.2",
"jsqr": "^1.3.1",
"mime": "^3.0.0",
"node-fetch": "^2.6.5",
"node-webpmux": "^3.1.0",
"puppeteer": "^13.0.0"
},
"dependencies": {
"mime": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="
}
}
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",

View file

@ -107,10 +107,12 @@
"pdf-extraction": "1.0.2",
"pdfkit": "^0.13.0",
"phone": "2.4.21",
"pptxtemplater": "1.0.5",
"pragmatismo-io-framework": "1.0.20",
"prism-media": "1.3.1",
"public-ip": "4.0.4",
"puppeteer": "13.7.0",
"qrcode-terminal": "0.12.0",
"readline": "1.3.0",
"reflect-metadata": "0.1.13",
"request-promise": "4.2.5",
@ -134,7 +136,8 @@
"url-join": "4.0.1",
"vbscript-to-typescript": "1.0.8",
"walk-promise": "0.2.0",
"washyourmouthoutwithsoap": "1.0.2"
"washyourmouthoutwithsoap": "1.0.2",
"whatsapp-web.js": "1.17.0"
},
"devDependencies": {
"@types/puppeteer": "5.4.6",

View file

@ -48,6 +48,9 @@ const DateDiff = require('date-diff');
const puppeteer = require('puppeteer');
const Path = require('path');
const sgMail = require('@sendgrid/mail');
const PizZip = require("pizzip");
const Docxtemplater = require("docxtemplater");
var mammoth = require("mammoth");
/**
* Base services of conversation to be called by BASIC which
@ -564,6 +567,14 @@ export class DialogKeywords {
GBLog.info(`[E-mail]: to:${to}, subject: ${subject}, body: ${body}.`);
const emailToken = process.env.EMAIL_API_KEY;
// Inline word document used as e-mail body.
if (typeof (body) === "object" )
{
const result = await mammoth.convertToHtml({buffer: body});
body = result.value;
}
return new Promise<any>((resolve, reject) => {
sgMail.setApiKey(emailToken);
const msg = {

View file

@ -475,6 +475,10 @@ export class GBVMService extends GBService {
return `${$1} = sys().asPdf(${$2})\n`;
});
code = code.replace(/(\w+)\s*\=\s*FILL\s(.*)\sWITH\s(.*)/gi, ($0, $1, $2, $3) => {
return `${1} = sys().fill(${$2}, ${$1})\n`;
});
code = code.replace(/save\s(.*)\sas\s(.*)/gi, ($0, $1, $2, $3) => {
return `sys().saveFile(${$2}, ${$1})\n`;
});

View file

@ -30,17 +30,15 @@
| |
\*****************************************************************************/
'use strict';
import { GBDialogStep, GBLog, GBMinInstance } from 'botlib';
import { GBLog, GBMinInstance } from 'botlib';
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
import { CollectionUtil } from 'pragmatismo-io-framework';
import * as request from 'request-promise-native';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
import { DialogKeywords } from './DialogKeywords';
import { Tabulator } from 'tabulator-tables';
import { GBServer } from '../../../src/app';
import * as fs from 'fs';
import { jar } from 'request-promise';
const Fs = require('fs');
const Excel = require('exceljs');
@ -51,7 +49,9 @@ const Path = require('path');
const ComputerVisionClient = require('@azure/cognitiveservices-computervision').ComputerVisionClient;
const ApiKeyCredentials = require('@azure/ms-rest-js').ApiKeyCredentials;
const alasql = require('alasql');
const DateDiff = require('date-diff');
const PizZip = require("pizzip");
const Docxtemplater = require("docxtemplater");
const pptxTemplaterModule = require('pptxtemplater');
/**
@ -194,20 +194,19 @@ export class SystemKeywords {
if (isObject || JSON.parse(data) !== null) {
let keys = Object.keys(data[0]);
if (headers) {
output[0] = [];
// Copies headers as the first element.
for (let i = 0; i < keys.length; i++) {
output[0][i] = keys[i];
}
}
else
{
output.push({ 'gbarray': '0' }); ;
else {
output.push({ 'gbarray': '0' });;
}
// Copies data from JSON format into simple array.
@ -504,7 +503,8 @@ export class SystemKeywords {
* @exaple SAVE variable as "my.txt"
*
*/
public async saveFile(file: string, data: any): Promise<any> {
public async saveFile(file: any, data: any): Promise<any> {
GBLog.info(`BASIC: Saving '${file}' (SAVE file).`);
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
const botId = this.min.instance.botId;
@ -816,6 +816,7 @@ export class SystemKeywords {
let foundIndex = 1;
// Fills the row variable.
let rowCount = 0;
for (; foundIndex < rows.length; foundIndex++) {
let filterAcceptCount = 0;
@ -952,8 +953,8 @@ export class SystemKeywords {
}
row[propertyName] = value;
}
row['line'] = rowCount;
row['originalLine'] = foundIndex + 1;
row['ordinal'] = rowCount;
row['line'] = foundIndex + 1;
table.push(row);
}
@ -1393,4 +1394,45 @@ export class SystemKeywords {
return text.replace(/\D/gi, '');
}
/**
*
* Fills a .docx or .pptx with template data.
*
* doc = FILL "templates/template.docx", data
*
*/
public async fill(templateName, data) {
const botId = this.min.instance.botId;
const gbaiName = `${botId}.gbai`;
const path = `/${botId}.gbai/${botId}.gbdata`;
// Downloads template from .gbdrive.
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
let template = await this.internalGetDocument(client, baseUrl, path, templateName);
const url = template['@microsoft.graph.downloadUrl'];
const localName = Path.join('work', gbaiName, 'cache', ``);
const response = await request({ uri: url, encoding: null });
Fs.writeFileSync(localName, response, { encoding: null });
// Loads the file as binary content.
const content = fs.readFileSync(localName, "binary");
const zip = new PizZip(content);
const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true, });
if (localName.endsWith('.pptx')) {
doc.attachModule(pptxTemplaterModule);
}
// Renders the document (Replace {first_name} by John, {last_name} by Doe, ...)
doc.render(data);
// Returns the buffer to be used with SAVE AS for example.
const buf = doc.getZip().generate({ type: "nodebuffer", compression: "DEFLATE", });
return buf;
}
}

View file

@ -45,6 +45,7 @@ const wash = require('washyourmouthoutwithsoap');
const { FacebookAdapter } = require('botbuilder-adapter-facebook');
const path = require('path');
const { NerManager } = require('node-nlp');
const mkdirp = require('mkdirp');
import {
AutoSaveStateMiddleware,
BotFrameworkAdapter,
@ -245,6 +246,16 @@ export class GBMinService {
await this.deployer.deployPackage(min, packagePath);
}
let dir = `work/${min.botId}.gbai/cache`;
if (!fs.existsSync(dir)) {
mkdirp.sync(dir);
}
dir = `work/${min.botId}.gbai/profile`;
if (!fs.existsSync(dir)) {
mkdirp.sync(dir);
}
// Loads Named Entity data for this bot.
await KBService.RefreshNER(min);
@ -320,8 +331,11 @@ export class GBMinService {
this.createCheckHealthAddress(GBServer.globals.server, min, min.instance);
}
public static isChatAPI(req) {
return req.body.phone_id ? false : true;
public static isChatAPI(req, res) {
if (!res) {
return "GeneralBots";
}
return req.body.phone_id ? "maytapi" : "chatapi";
}
private async WhatsAppCallback(req, res) {
@ -334,72 +348,80 @@ export class GBMinService {
return;
}
let chatapi = GBMinService.isChatAPI(req);
let provider = GBMinService.isChatAPI(req, res);
let id = provider ? req.body.messages[0].author.split('@')[0] : req.body.user.phone;
let senderName = provider ? req.body.messages[0].senderName : req.body.user.name;
let botId;
let text;
if (chatapi) {
if (req.body.ack) {
res.status(200);
res.end();
switch (provider) {
case "GeneralBots":
return;
}
} else {
if (req.body.type !== 'message') {
res.status(200);
res.end();
id = req.body.messages[0].author.split('@')[0];
senderName = req.body.messages[0].senderName;
text = req.body;
return;
}
break;
case "chatapi":
id = req.body.messages[0].author.split('@')[0];
senderName = req.body.messages[0].senderName;
text = req.body.messages[0].body;
if (req.body.ack) {
res.status(200);
res.end();
return;
}
if (req.body.messages[0].fromMe) {
res.end();
return; // Exit here.
}
botId = req.params.botId;
if (botId === '[default]' || botId === undefined) {
botId = GBConfigService.get('BOT_ID');
}
break;
case "maytapi":
id = req.body.user.phone;
senderName = req.body.user.name;
text = req.body.message.text;
if (req.body.type !== 'message') {
res.status(200);
res.end();
return;
}
if (req.body.message.fromMe) {
res.end();
return; // Exit here.
}
botId = WhatsappDirectLine.phones[req.body.phoneId];
break;
}
// Detects if the message is echo from itself.
const id = chatapi ? req.body.messages[0].author.split('@')[0] : req.body.user.phone;
const senderName = chatapi ? req.body.messages[0].senderName : req.body.user.name;
const sec = new SecService();
let user = await sec.getUserFromSystemId(id);
if (chatapi) {
if (req.body.messages[0].fromMe) {
res.end();
return; // Exit here.
}
} else {
if (req.body.message.fromMe) {
res.end();
return; // Exit here.
}
}
let botId;
if (chatapi) {
botId = req.params.botId;
if (botId === '[default]' || botId === undefined) {
botId = GBConfigService.get('BOT_ID');
}
}
else {
botId = WhatsappDirectLine.phones[req.body.phoneId];
}
GBLog.info(`A WhatsApp mobile requested instance for: ${botId}.`);
let urlMin: any = GBServer.globals.minInstances.filter
(p => p.instance.botId === botId)[0];
const botNumber = urlMin ? urlMin.core.getParam(urlMin.instance, 'Bot Number', null) : null;
let activeMin;
// Processes group behaviour.
let text = chatapi ? req.body.messages[0].body : req.body.message.text;
text = text.replace(/\@\d+ /gi, '');
if (chatapi) {
if (provider === "chatapi") {
// Ensures that the bot group is the active bot for the user (like switching).
@ -452,10 +474,10 @@ export class GBMinService {
if (startDialog) {
GBLog.info(`Calling /start to Auto start ${startDialog} for ${activeMin.instance.instanceId}...`);
if (chatapi) {
if (provider === "chatapi") {
req.body.messages[0].body = `/start`;
}
else {
else if (provider === "maytapi") {
req.body.message = `/start`;
}
@ -488,10 +510,10 @@ export class GBMinService {
if (startDialog) {
GBLog.info(`Calling /start for Auto start : ${startDialog} for ${activeMin.instance.botId}...`);
if (chatapi) {
if (provider === "chatapi") {
req.body.messages[0].body = `/start`;
}
else {
else if (provider === "maytapi") {
req.body.message = `/start`;
}
@ -821,7 +843,7 @@ export class GBMinService {
// If there is WhatsApp configuration specified, initialize
// infrastructure objects.
if (min.instance.whatsappServiceUrl) {
if (min.instance.whatsappServiceKey) {
min.whatsAppDirectLine = new WhatsappDirectLine(
min,
min.botId,
@ -1024,10 +1046,6 @@ export class GBMinService {
const folder = `work/${min.instance.botId}.gbai/cache`;
const filename = `${GBAdminService.generateUuid()}.png`;
if (!Fs.existsSync(folder)) {
Fs.mkdirSync(folder);
}
Fs.writeFileSync(path.join(folder, filename), data);
step.context.activity.text = urlJoin(GBServer.globals.publicAddress, `${min.instance.botId}`, 'cache', filename);
}

View file

@ -43,6 +43,10 @@ import { SecService } from '../../security.gbapp/services/SecService';
import { Messages } from '../strings';
import { GuaribasUser } from '../../security.gbapp/models';
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords';
const { MessageMedia, Client, LocalAuth } = require('whatsapp-web.js');
const qrcode = require('qrcode-terminal');
/**
* Support for Whatsapp.
@ -68,8 +72,9 @@ export class WhatsappDirectLine extends GBService {
public min: GBMinInstance;
private directLineSecret: string;
private locale: string = 'pt-BR';
chatapi: any;
provider: any;
INSTANCE_URL = 'https://api.maytapi.com/api';
private customClient;
constructor(
min: GBMinInstance,
@ -87,7 +92,8 @@ export class WhatsappDirectLine extends GBService {
this.whatsappServiceKey = whatsappServiceKey;
this.whatsappServiceNumber = whatsappServiceNumber;
this.whatsappServiceUrl = whatsappServiceUrl;
this.chatapi = whatsappServiceNumber.indexOf(';') > -1 ? false : false;
this.provider = whatsappServiceKey === "gbnative" ?
'GeneralBots' : whatsappServiceNumber.indexOf(';') > -1 ? 'maytapi' : 'chatapi';
}
public static async asyncForEach(array, callback) {
@ -111,44 +117,101 @@ export class WhatsappDirectLine extends GBService {
);
let options;
if (this.chatapi) {
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'webhook'),
timeout: 10000,
qs: {
token: this.whatsappServiceKey,
webhookUrl: `${GBServer.globals.publicAddress}/webhooks/whatsapp/${this.botId}`,
set: true
},
headers: {
'cache-control': 'no-cache'
}
};
switch (this.provider) {
case 'GeneralBots':
const Path = require('path');
const gbaiName = `${this.min.botId}.gbai`;
let localName = Path.join('work', gbaiName, 'profile');
let client = this.customClient = new Client({
authStrategy: new LocalAuth(),
puppeteer: {
headless: false, args: ['--disable-features=site-per-process',
`--user-data-dir=${localName}`]
}
});
client.initialize();
client.on('message', (async message => {
await this.received(message, null);
}).bind(this));
client.on('qr', ((qr) => {
const adminNumber = this.min.core.getParam(this.min.instance, 'Bot Admin Number', null);
const adminEmail = this.min.core.getParam(this.min.instance, 'Bot Admin E-mail', null);
// Sends QR Code to boot bot admin.
const info = this.customClient.info;
const msg = `Please, scan QR Code with ${info.wid.user}(${info.pushname}) for bot ${this.botId}: ${qr}.`;
GBLog.info(msg);
qrcode.generate(qr, { small: true, scale: 0.5 });
// While handling other bots uses boot instance of this class to send QR Codes.
if (this.botId !== GBServer.globals.minBoot.botId) {
GBServer.globals.minBoot.whatsAppDirectLine.sendMessage(msg);
GBServer.globals.minBoot.whatsAppDirectLine.sendMessage(adminNumber, qr);
const s = new DialogKeywords(null, null, null, null);
s.sendEmail(adminEmail, `Check your WhatsApp for bot ${this.botId}`, msg);
}
}).bind(this));
client.on('authenticated', () => {
GBLog.info(`WhatsApp QR Code authenticated for ${this.botId}.`);
});
setUrl = false;
break;
case 'chatapi':
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'webhook'),
timeout: 10000,
qs: {
token: this.whatsappServiceKey,
webhookUrl: `${GBServer.globals.publicAddress}/webhooks/whatsapp/${this.botId}`,
set: true
},
headers: {
'cache-control': 'no-cache'
}
};
break;
case 'maytapi':
let phoneId = this.whatsappServiceNumber.split(';')[0];
let productId = this.whatsappServiceNumber.split(';')[1]
let url = `${this.INSTANCE_URL}/${productId}/${phoneId}/config`;
WhatsappDirectLine.phones[phoneId] = this.botId;
options = {
url: url,
method: 'POST',
body: {
webhook: `${GBServer.globals.publicAddress}/webhooks/whatsapp/${this.botId}`,
"ack_delivery": false
},
headers: {
'x-maytapi-key': this.whatsappServiceKey,
'Content-Type': 'application/json',
},
json: true,
};
break;
}
else {
let phoneId = this.whatsappServiceNumber.split(';')[0];
let productId = this.whatsappServiceNumber.split(';')[1]
let url = `${this.INSTANCE_URL}/${productId}/${phoneId}/config`;
WhatsappDirectLine.phones[phoneId] = this.botId;
options = {
url: url,
method: 'POST',
body: {
webhook: `${GBServer.globals.publicAddress}/webhooks/whatsapp/${this.botId}`,
"ack_delivery": false
},
headers: {
'x-maytapi-key': this.whatsappServiceKey,
'Content-Type': 'application/json',
},
json: true,
};
}
if (setUrl) {
const express = require('express');
GBServer.globals.server.use(`/audios`, express.static('work'));
@ -186,43 +249,54 @@ export class WhatsappDirectLine extends GBService {
}
public async received(req, res) {
if (this.chatapi && req.body.messages === undefined) {
if (this.provider === "chatapi" && req.body.messages === undefined) {
res.end();
return; // Exit here.
}
const message = this.chatapi ? req.body.messages[0] : req.body.message;
let message, from, fromName, text;
let group = "";
let answerText = null;
switch (this.provider) {
case 'GeneralBots':
message = req;
break;
let text = this.chatapi ? message.body : message.text;
text = text.replace(/\@\d+ /gi, '');
case 'chatapi':
message = req.body.messages[0];
text = message.body;
from = req.body.messages[0].author.split('@')[0];
fromName = req.body.messages[0].senderName;
const from = this.chatapi ? req.body.messages[0].author.split('@')[0] : req.body.user.phone;
const fromName = this.chatapi ? req.body.messages[0].senderName : req.body.user.name;
if (req.body.messages[0].fromMe) {
res.end();
GBLog.info(`GBWhatsapp: RCV ${from}(${fromName}): ${text})`);
return; // Exit here.
}
break;
if (this.chatapi) {
if (req.body.messages[0].fromMe) {
res.end();
case 'maytapi':
message = req.body.message;
text = message.text;
from = req.body.user.phone;
fromName = req.body.user.name;
return; // Exit here.
}
} else {
if (req.body.message.fromMe) {
res.end();
if (req.body.message.fromMe) {
res.end();
return; // Exit here.
}
return; // Exit here.
}
break;
}
if (this.chatapi) {
text = text.replace(/\@\d+ /gi, '');
GBLog.info(`GBWhatsapp: RCV ${from}(${fromName}): ${text})`);
if (this.provider === "chatapi") {
if (message.chatName.charAt(0) !== '+') {
group = message.chatName;
@ -283,7 +357,6 @@ export class WhatsappDirectLine extends GBService {
}
const botId = this.min.instance.botId;
const state = WhatsappDirectLine.state[botId + from];
if (state) {
WhatsappDirectLine.state[botId + from] = null;
@ -302,7 +375,6 @@ export class WhatsappDirectLine extends GBService {
const user = await sec.ensureUser(this.min.instance.instanceId, from,
fromName, '', 'whatsapp', fromName, null);
const locale = user.locale ? user.locale : 'pt';
if (answerText) {
@ -315,7 +387,7 @@ export class WhatsappDirectLine extends GBService {
if (process.env.AUDIO_DISABLED !== 'true') {
const options = {
url: this.chatapi ? message.body : message.text,
url: this.provider ? message.body : message.text,
method: 'GET',
encoding: 'binary'
};
@ -535,51 +607,57 @@ export class WhatsappDirectLine extends GBService {
public async sendFileToDevice(to, url, filename, caption, chatId) {
let options;
if (this.chatapi) {
switch (this.provider) {
case 'GeneralBots':
const attachment = MessageMedia.fromurl(url);
await this.customClient.sendMessage(to, attachment, { caption: caption });
break;
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'sendFile'),
qs: {
token: this.whatsappServiceKey,
phone: chatId ? null : to,
chatId: chatId,
body: url,
filename: filename,
caption: caption
},
headers: {
'cache-control': 'no-cache'
}
};
case 'chatapi':
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'sendFile'),
qs: {
token: this.whatsappServiceKey,
phone: chatId ? null : to,
chatId: chatId,
body: url,
filename: filename,
caption: caption
},
headers: {
'cache-control': 'no-cache'
}
};
break;
case 'maytapi':
let contents = 0;
let body = {
to_number: to,
type: "media",
message: url,
text: caption
};
let phoneId = this.whatsappServiceNumber.split(';')[0];
let productId = this.whatsappServiceNumber.split(';')[1]
options = {
url: `${this.INSTANCE_URL}/${productId}/${phoneId}/sendMessage`,
method: 'post',
json: true,
body,
headers: {
'Content-Type': 'application/json',
'x-maytapi-key': this.whatsappServiceKey,
},
};
break;
}
else {
let contents = 0;
let body = {
to_number: to,
type: "media",
message: url,
text: caption
};
let phoneId = this.whatsappServiceNumber.split(';')[0];
let productId = this.whatsappServiceNumber.split(';')[1]
options = {
url: `${this.INSTANCE_URL}/${productId}/${phoneId}/sendMessage`,
method: 'post',
json: true,
body,
headers: {
'Content-Type': 'application/json',
'x-maytapi-key': this.whatsappServiceKey,
},
};
}
try {
// tslint:disable-next-line: await-promise
const result = await request.post(options);
@ -590,21 +668,42 @@ export class WhatsappDirectLine extends GBService {
}
public async sendAudioToDevice(to, url, chatId) {
const options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'sendPTT'),
qs: {
token: this.whatsappServiceKey,
phone: chatId ? null : to,
chatId: chatId,
body: url
},
headers: {
'cache-control': 'no-cache'
}
};
let options;
switch (this.provider) {
case 'GeneralBots':
const attachment = MessageMedia.fromurl(url);
await this.customClient.sendMessage(to, attachment);
break;
case 'chatapi':
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'sendPTT'),
qs: {
token: this.whatsappServiceKey,
phone: chatId ? null : to,
chatId: chatId,
body: url
},
headers: {
'cache-control': 'no-cache'
}
};
break;
case 'maytapi':
options = {}; // TODO: Code Maytapi.
break;
}
try {
// tslint:disable-next-line: await-promise
const result = await request.post(options);
GBLog.info(`Audio ${url} sent to ${to}: ${result}`);
@ -635,48 +734,59 @@ export class WhatsappDirectLine extends GBService {
} else {
let options;
if (this.chatapi) {
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'message'),
qs: {
token: this.whatsappServiceKey,
phone: chatId ? null : to,
chatId: chatId,
body: msg
},
headers: {
'cache-control': 'no-cache'
}
};
switch (this.provider) {
case 'GeneralBots':
this.customClient.sendMessage(to, msg);
break;
case 'chatapi':
options = {
method: 'POST',
url: urlJoin(this.whatsappServiceUrl, 'message'),
qs: {
token: this.whatsappServiceKey,
phone: chatId ? null : to,
chatId: chatId,
body: msg
},
headers: {
'cache-control': 'no-cache'
}
};
break;
case 'maytapi':
let phoneId = this.whatsappServiceNumber.split(';')[0];
let productId = this.whatsappServiceNumber.split(';')[1]
let url = `${this.INSTANCE_URL}/${productId}/${phoneId}/sendMessage`;
options = {
url: url,
method: 'post',
json: true,
body: { type: 'text', message: msg, to_number: to },
headers: {
'Content-Type': 'application/json',
'x-maytapi-key': this.whatsappServiceKey,
},
};
break;
}
else {
let phoneId = this.whatsappServiceNumber.split(';')[0];
let productId = this.whatsappServiceNumber.split(';')[1]
let url = `${this.INSTANCE_URL}/${productId}/${phoneId}/sendMessage`;
options = {
url: url,
method: 'post',
json: true,
body: { type: 'text', message: msg, to_number: to },
headers: {
'Content-Type': 'application/json',
'x-maytapi-key': this.whatsappServiceKey,
},
};
}
try {
// tslint:disable-next-line: await-promise
const result = await request.post(options);
GBLog.info(`Message [${msg}] sent to ${to}: ${result}`);
if (this.provider !== "GeneralBots") {
await request.post(options);
}
GBLog.info(`Message [${msg}] sent to ${to}.`);
} catch (error) {
GBLog.error(`Error sending message to Whatsapp provider ${error.message}`);