From 73671b26efde102be491aa4393804974bb330db2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 14 Dec 2022 18:20:02 +0000 Subject: [PATCH 1/5] ci(version): :zap: automatic - "${date}" updated versions every packages --- packages/bot/package.json | 2 +- packages/cli/package.json | 2 +- packages/create-bot-whatsapp/package.json | 2 +- packages/database/package.json | 2 +- packages/provider/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/bot/package.json b/packages/bot/package.json index 88a782b..ebd2d4b 100644 --- a/packages/bot/package.json +++ b/packages/bot/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/bot", - "version": "0.0.21-alpha.0", + "version": "0.0.22-alpha.0", "description": "", "main": "./lib/bundle.bot.cjs", "scripts": { diff --git a/packages/cli/package.json b/packages/cli/package.json index 50aa41f..6030446 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/cli", - "version": "0.0.28-alpha.0", + "version": "0.0.29-alpha.0", "description": "", "main": "index.js", "devDependencies": { diff --git a/packages/create-bot-whatsapp/package.json b/packages/create-bot-whatsapp/package.json index 9935c59..5de6a2b 100644 --- a/packages/create-bot-whatsapp/package.json +++ b/packages/create-bot-whatsapp/package.json @@ -1,6 +1,6 @@ { "name": "create-bot-whatsapp", - "version": "0.0.39-alpha.0", + "version": "0.0.40-alpha.0", "description": "", "main": "./lib/bundle.create-bot-whatsapp.cjs", "files": [ diff --git a/packages/database/package.json b/packages/database/package.json index 6dd7def..571d809 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/database", - "version": "0.0.20-alpha.0", + "version": "0.0.21-alpha.0", "description": "Esto es el conector a mysql, pg, mongo", "main": "./lib/mock/index.cjs", "keywords": [], diff --git a/packages/provider/package.json b/packages/provider/package.json index 3262cdc..2bbe175 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/provider", - "version": "0.0.26-alpha.0", + "version": "0.0.27-alpha.0", "description": "Esto es el conector a Twilio, Meta, etc...", "main": "./lib/mock/index.cjs", "keywords": [], From 342cbccff1d09f9aabe5423ad6d686d590a2448f Mon Sep 17 00:00:00 2001 From: Joseph VTX <1395609@senati.pe> Date: Wed, 14 Dec 2022 14:52:09 -0500 Subject: [PATCH 2/5] feat(provider): :zap: add sendfile and sendButtons SendFile and SendButtons --- packages/provider/src/baileys/index.js | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/provider/src/baileys/index.js b/packages/provider/src/baileys/index.js index e985e4a..8bd860e 100644 --- a/packages/provider/src/baileys/index.js +++ b/packages/provider/src/baileys/index.js @@ -1,5 +1,7 @@ const { ProviderClass } = require('@bot-whatsapp/bot') const pino = require('pino') +const mime = require('mime-types') +const fs = require('fs') const { default: makeWASocket, useMultiFileAuthState, @@ -166,6 +168,49 @@ class BaileysProvider extends ProviderClass { if (options?.media) return this.sendMedia(number, options.media) return this.sendText(number, message) } + + /** + * + * @param {string} number + * @param {string} filePath + * @example await sendMessage('+XXXXXXXXXXX', './document/file.pdf') + */ + + sendFile = async (number, filePath) => { + if (fs.existsSync(filePath)) { + const mimeType = mime.lookup(filePath) + const numberClean = number.replace('+', '') + const fileName = filePath.split('/').pop() + + await this.vendor.sendMessage(`${numberClean}@c.us`, { + document: { url: filePath }, + mimetype: mimeType, + fileName: fileName, + }) + } + } + + /** + * + * @param {string} number + * @param {string} text + * @param {string} footer + * @param {Array} buttons + * @example await sendMessage("+XXXXXXXXXXX", "Your Text", "Your Footer", [{"buttonId": "id", "buttonText": {"displayText": "Button"}, "type": 1}]) + */ + + sendButtons = async (number, text, footer, buttons) => { + const numberClean = number.replace('+', '') + + const buttonMessage = { + text: text, + footer: footer, + buttons: buttons, + headerType: 1, + } + + await this.vendor.sendMessage(`${numberClean}@c.us`, buttonMessage) + } } module.exports = BaileysProvider From a42b6f4af869f0f4ecf48ac042323913b13d6094 Mon Sep 17 00:00:00 2001 From: Joseph VTX <1395609@senati.pe> Date: Wed, 14 Dec 2022 16:51:52 -0500 Subject: [PATCH 3/5] ci(provider): :package: mime-types package.json mime-types --- starters/apps/base-bailey-memory/package.json | 1 + starters/apps/base-bailey-mongo/package.json | 1 + starters/apps/base-bailey-mysql/package.json | 1 + 3 files changed, 3 insertions(+) diff --git a/starters/apps/base-bailey-memory/package.json b/starters/apps/base-bailey-memory/package.json index 1efeb95..ef0e2b3 100644 --- a/starters/apps/base-bailey-memory/package.json +++ b/starters/apps/base-bailey-memory/package.json @@ -10,6 +10,7 @@ "keywords": [], "dependencies": { "@adiwajshing/baileys": "^4.4.0", + "mime-types": "^2.1.35", "@bot-whatsapp/bot": "latest", "@bot-whatsapp/cli": "latest", "@bot-whatsapp/database": "latest", diff --git a/starters/apps/base-bailey-mongo/package.json b/starters/apps/base-bailey-mongo/package.json index d2ffa4a..ad14f04 100644 --- a/starters/apps/base-bailey-mongo/package.json +++ b/starters/apps/base-bailey-mongo/package.json @@ -10,6 +10,7 @@ "keywords": [], "dependencies": { "@adiwajshing/baileys": "^4.4.0", + "mime-types": "^2.1.35", "@bot-whatsapp/bot": "latest", "@bot-whatsapp/cli": "latest", "@bot-whatsapp/database": "latest", diff --git a/starters/apps/base-bailey-mysql/package.json b/starters/apps/base-bailey-mysql/package.json index a52fd19..c8c66de 100644 --- a/starters/apps/base-bailey-mysql/package.json +++ b/starters/apps/base-bailey-mysql/package.json @@ -10,6 +10,7 @@ "keywords": [], "dependencies": { "@adiwajshing/baileys": "^4.4.0", + "mime-types": "^2.1.35", "@bot-whatsapp/bot": "latest", "@bot-whatsapp/cli": "latest", "@bot-whatsapp/database": "latest", From 438607c222b91d6f8814201dabe5f7c3e7ba1abb Mon Sep 17 00:00:00 2001 From: vicente1992 Date: Thu, 15 Dec 2022 00:14:15 -0500 Subject: [PATCH 4/5] feat(provider): meta provider is added --- packages/provider/package.json | 3 +- packages/provider/rollup-provider.config.js | 9 ++ packages/provider/src/meta/index.js | 115 ++++++++++++++++++++ packages/provider/src/meta/server.js | 63 +++++++++++ 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 packages/provider/src/meta/index.js create mode 100644 packages/provider/src/meta/server.js diff --git a/packages/provider/package.json b/packages/provider/package.json index c6ace86..5c01179 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -14,6 +14,7 @@ "exports": { "./mock": "./lib/mock/index.cjs", "./twilio": "./lib/twilio/index.cjs", - "./web-whatsapp": "./lib/web-whatsapp/index.cjs" + "./web-whatsapp": "./lib/web-whatsapp/index.cjs", + "./meta": "./lib/meta/index.cjs" } } diff --git a/packages/provider/rollup-provider.config.js b/packages/provider/rollup-provider.config.js index 8a6adcf..83f38be 100644 --- a/packages/provider/rollup-provider.config.js +++ b/packages/provider/rollup-provider.config.js @@ -30,4 +30,13 @@ module.exports = [ }, plugins: [commonjs()], }, + { + input: join(__dirname, 'src', 'meta', 'index.js'), + output: { + banner: banner['banner.output'].join(''), + file: join(__dirname, 'lib', 'meta', 'index.cjs'), + format: 'cjs', + }, + plugins: [commonjs()], + }, ] diff --git a/packages/provider/src/meta/index.js b/packages/provider/src/meta/index.js new file mode 100644 index 0000000..e32ec51 --- /dev/null +++ b/packages/provider/src/meta/index.js @@ -0,0 +1,115 @@ +const { ProviderClass } = require('@bot-whatsapp/bot') +const axios = require('axios') +const MetaWebHookServer = require('./server') +const URL = `https://graph.facebook.com/v15.0` + +/** + * ⚙️MetaProvider: Es un provedor que te ofrece enviar + * mensaje a Whatsapp via API + * info: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages + * + * + * Necesitas las siguientes tokens y valores + * { token, numberId, vendorNumber, verify_token } + */ + +class MetaProvider extends ProviderClass { + metHook + token + numberId + constructor({ token, numberId, verifyToken }, _port = 3000) { + super() + this.token = token + this.numberId = numberId + this.metHook = new MetaWebHookServer(verifyToken, _port) + this.metHook.start() + + const listEvents = this.busEvents() + + for (const { event, func } of listEvents) { + this.metHook.on(event, func) + } + } + + /** + * Mapeamos los eventos nativos de whatsapp-web.js a los que la clase Provider espera + * para tener un standar de eventos + * @returns + */ + busEvents = () => [ + { + event: 'auth_failure', + func: (payload) => this.emit('error', payload), + }, + { + event: 'ready', + func: () => this.emit('ready', true), + }, + { + event: 'message', + func: (payload) => { + this.emit('message', payload) + }, + }, + ] + + async sendMessageMeta(body) { + try { + const response = await axios.post( + `${URL}/${this.numberId}/messages`, + body, + { + headers: { + Authorization: `Bearer ${this.token}`, + }, + } + ) + return response.data + } catch (error) { + return Promise.resolve(error) + } + } + + async sendtext(number, message) { + const body = { + messaging_product: 'whatsapp', + to: number, + type: 'text', + text: { + preview_url: false, + body: message, + }, + } + await this.sendMessageMeta(body) + } + + async sendMedia(number, message, mediaInput = null) { + if (!mediaInput) throw new Error(`MEDIA_INPUT_NULL_: ${mediaInput}`) + const body = { + messaging_product: 'whatsapp', + to: number, + type: 'image', + image: { + link: mediaInput, + }, + } + await this.sendMessageMeta(body) + } + + /** + * + * @param {*} userId + * @param {*} message + * @param {*} param2 + * @returns + */ + sendMessage = async (number, message, { options }) => { + if (options?.buttons?.length) return console.log('Envio de botones') + if (options?.media) + return this.sendMedia(number, message, options.media) + + this.sendtext(number, message) + } +} + +module.exports = MetaProvider diff --git a/packages/provider/src/meta/server.js b/packages/provider/src/meta/server.js new file mode 100644 index 0000000..91ae8bc --- /dev/null +++ b/packages/provider/src/meta/server.js @@ -0,0 +1,63 @@ +const { EventEmitter } = require('node:events') +const polka = require('polka') +const { urlencoded } = require('body-parser') + +class MetaWebHookServer extends EventEmitter { + metaServer + metaPort + verifyToken + constructor(_verifyToken, _metaPort) { + super() + this.metaServer = this.buildHTTPServer() + this.metaPort = _metaPort + this.verifyToken = _verifyToken + } + + /** + * Mensaje entrante + * emit: 'message' + * @param {*} req + * @param {*} res + */ + incomingMsg = (req, res) => { + const { body } = req + const message = body.entry[0].changes[0].value.messages[0] + const to = body.entry[0].changes[0].value.metadata.display_phone_number + this.emit('message', { + from: message.from, + to, + body: message.text.body, + }) + const json = JSON.stringify({ body }) + res.end(json) + } + + /** + * Contruir HTTP Server + * @returns + */ + buildHTTPServer = () => { + return polka() + .use(urlencoded({ extended: true })) + .post('/meta-hook', this.incomingMsg) + } + + /** + * Puerto del HTTP + * @param {*} port default 3000 + */ + start = () => { + this.metaServer.listen(this.metaPort, () => { + console.log(``) + console.log(`[meta]: Agregar esta url "WHEN A MESSAGE COMES IN"`) + console.log( + `[meta]: POST http://localhost:${this.metaPort}/meta-hook` + ) + console.log(`[meta]: Más información en la documentacion`) + console.log(``) + }) + this.emit('ready') + } +} + +module.exports = MetaWebHookServer From a52aaa11d883bbaf526cf87720d3c3fd9f89a986 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Thu, 15 Dec 2022 14:06:19 +0100 Subject: [PATCH 5/5] fix(provider): :bug: fix metea provider --- packages/cli/interactive/index.js | 4 +- packages/provider/src/meta/index.js | 8 +- starters/apps/base-meta-memory/README.md | 12 +++ starters/apps/base-meta-memory/app.js | 88 +++++++++++++++++++++ starters/apps/base-meta-memory/package.json | 22 ++++++ 5 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 starters/apps/base-meta-memory/README.md create mode 100644 starters/apps/base-meta-memory/app.js create mode 100644 starters/apps/base-meta-memory/package.json diff --git a/packages/cli/interactive/index.js b/packages/cli/interactive/index.js index 7da0029..f7360ce 100644 --- a/packages/cli/interactive/index.js +++ b/packages/cli/interactive/index.js @@ -33,10 +33,10 @@ const startInteractive = async () => { message: '¿Cuál proveedor de whatsapp quieres utilizar?', choices: [ { title: 'whatsapp-web.js (gratis)', value: 'wweb' }, - { title: 'Twilio', value: 'twilio' }, { title: 'Venom (gratis)', value: 'venom' }, { title: 'Baileys (gratis)', value: 'bailey' }, - { title: 'API Oficial (Meta)', value: 'meta', disabled: true }, + { title: 'Twilio', value: 'twilio' }, + { title: 'API Oficial (Meta)', value: 'meta' }, ], max: 1, hint: 'Espacio para seleccionar', diff --git a/packages/provider/src/meta/index.js b/packages/provider/src/meta/index.js index e32ec51..f6b9ae6 100644 --- a/packages/provider/src/meta/index.js +++ b/packages/provider/src/meta/index.js @@ -32,7 +32,7 @@ class MetaProvider extends ProviderClass { } /** - * Mapeamos los eventos nativos de whatsapp-web.js a los que la clase Provider espera + * Mapeamos los eventos nativos a los que la clase Provider espera * para tener un standar de eventos * @returns */ @@ -53,7 +53,7 @@ class MetaProvider extends ProviderClass { }, ] - async sendMessageMeta(body) { + sendMessageMeta = async (body) => { try { const response = await axios.post( `${URL}/${this.numberId}/messages`, @@ -70,7 +70,7 @@ class MetaProvider extends ProviderClass { } } - async sendtext(number, message) { + sendtext = async (number, message) => { const body = { messaging_product: 'whatsapp', to: number, @@ -83,7 +83,7 @@ class MetaProvider extends ProviderClass { await this.sendMessageMeta(body) } - async sendMedia(number, message, mediaInput = null) { + sendMedia = async (number, _, mediaInput = null) => { if (!mediaInput) throw new Error(`MEDIA_INPUT_NULL_: ${mediaInput}`) const body = { messaging_product: 'whatsapp', diff --git a/starters/apps/base-meta-memory/README.md b/starters/apps/base-meta-memory/README.md new file mode 100644 index 0000000..f8e0e90 --- /dev/null +++ b/starters/apps/base-meta-memory/README.md @@ -0,0 +1,12 @@ +### BASE APP + +Este bot contiene un flujo basico en el cual una persona (cliente) escribe **"hola"** y el bot responde. +- Bienvenido a mi tienda +- Como puedo ayudarte? +- Tengo: Zapatos Bolsos etc.. + +------ +- [Discord](https://link.codigoencasa.com/DISCORD) +- [Twitter](https://twitter.com/leifermendez) +- [Youtube](https://www.youtube.com/watch?v=5lEMCeWEJ8o&list=PL_WGMLcL4jzWPhdhcUyhbFU6bC0oJd2BR) +- [Telegram](https://t.me/leifermendez) diff --git a/starters/apps/base-meta-memory/app.js b/starters/apps/base-meta-memory/app.js new file mode 100644 index 0000000..6f932f0 --- /dev/null +++ b/starters/apps/base-meta-memory/app.js @@ -0,0 +1,88 @@ +const { + createBot, + createProvider, + createFlow, + addKeyword, + addChild, +} = require('@bot-whatsapp/bot') + +const TwilioProvider = require('@bot-whatsapp/provider/twilio') +const MockAdapter = require('@bot-whatsapp/database/mock') + +/** + * Declarando flujo hijo + */ + +const flowBolsos2 = addKeyword(['bolsos2', '2']) + .addAnswer('🤯 *MUCHOS* bolsos ...') + .addAnswer('y mas bolsos... bla bla') + +const flowZapatos2 = addKeyword(['zapatos2', '2']) + .addAnswer('🤯 repito que tengo *MUCHOS* zapatos.') + .addAnswer('y algunas otras cosas.') + +const flowZapatos = addKeyword(['zapatos', 'ZAPATOS']) + .addAnswer('🤯 Veo que elegiste zapatos') + .addAnswer('Tengo muchos zapatos...bla bla') + .addAnswer( + ['Manda:', '*2*', 'o', '*zapatos2*', 'para mas información'], + { capture: true }, + (ctx) => { + console.log('Aqui puedes ver más info del usuario...') + console.log('Puedes enviar un mail, hook, etc..') + console.log(ctx) + }, + [...addChild(flowZapatos2)] + ) + +const flowBolsos = addKeyword(['bolsos', 'BOLSOS']) + .addAnswer('🙌 Veo que elegiste bolsos') + .addAnswer('Tengo muchos bolsos...bla bla') + .addAnswer( + ['Manda:', '*2*', 'o', '*bolsos2*', 'para mas información.'], + { capture: true }, + (ctx) => { + console.log('Aqui puedes ver más info del usuario...') + console.log('Puedes enviar un mail, hook, etc..') + console.log(ctx) + }, + [...addChild(flowBolsos2)] + ) + +/** + * Declarando flujo principal + */ +const flowPrincipal = addKeyword(['hola', 'ole', 'alo']) + .addAnswer('Hola, bienvenido a mi tienda') + .addAnswer('Como puedo ayudarte?') + .addAnswer(['Tengo:', 'Zapatos', 'Bolsos', 'etc..']) + .addAnswer( + ['Para continuar escribe:', '*Zapatos*', 'o', '*Bolsos*'], + { capture: true }, + (ctx) => { + console.log('Aqui puedes ver más info del usuario...') + console.log('Puedes enviar un mail, hook, etc..') + console.log(ctx) + console.log(ctx['_data']['notifyName']) + }, + [...addChild(flowBolsos), ...addChild(flowZapatos)] + ) + +const main = async () => { + const adapterDB = new MockAdapter() + const adapterFlow = createFlow([flowPrincipal]) + + const adapterProvider = createProvider(TwilioProvider, { + accountSid: 'YOUR_ACCOUNT_SID', + authToken: 'YOUR_ACCOUNT_TOKEN', + vendorNumber: '+14155238886', + }) + + createBot({ + flow: adapterFlow, + provider: adapterProvider, + database: adapterDB, + }) +} + +main() diff --git a/starters/apps/base-meta-memory/package.json b/starters/apps/base-meta-memory/package.json new file mode 100644 index 0000000..d0af65c --- /dev/null +++ b/starters/apps/base-meta-memory/package.json @@ -0,0 +1,22 @@ +{ + "name": "bot-whatsapp-base-meta-memory", + "version": "1.0.0", + "description": "", + "main": "app.js", + "scripts": { + "pre-copy": "cd .. && yarn run copy.lib base-meta-memory", + "start": "node app.js" + }, + "keywords": [], + "dependencies": { + "body-parser": "^1.20.1", + "polka": "^0.5.2", + "twilio": "^3.83.4", + "@bot-whatsapp/bot": "latest", + "@bot-whatsapp/cli": "latest", + "@bot-whatsapp/database": "latest", + "@bot-whatsapp/provider": "latest" + }, + "author": "", + "license": "ISC" +}