From ab474b57287c6ef82fc5f88e7d2c57eb20d04e6e Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Sun, 29 Jan 2023 15:59:30 -0600 Subject: [PATCH 01/19] Init --- adapter/index.js | 35 ++++- app.js | 172 ++++++++++++++++++------ flow/{initial.json => initial.json.bak} | 11 ++ flow/response.json | 55 ++++++++ package-lock.json | 105 +++++++++------ 5 files changed, 292 insertions(+), 86 deletions(-) rename flow/{initial.json => initial.json.bak} (89%) diff --git a/adapter/index.js b/adapter/index.js index 12bb7ff..086c9f2 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -1,7 +1,7 @@ const { getData, getReply, saveMessageMysql } = require('./mysql') const { saveMessageJson } = require('./jsonDb') const { getDataIa } = require('./diaglogflow') -const stepsInitial = require('../flow/initial.json') +// const stepsInitial = require('../flow/initial.json') const stepsReponse = require('../flow/response.json') const { isUndefined } = require('util'); var msjsRecibidos = []; @@ -14,6 +14,23 @@ var elNum; //MOD by CHV - var cumplePasoPrevio; //MOD by CHV - const resps = require('../flow/response.json'); //MOD by CHV - Agregamos para traer las respuestas. const { appendFile } = require('fs') +/** + * Regresa un arreglo de objetos como el stepsInitial original, que se generaba desde "initial.json". + * Contiene el nombre del paso (key) y las palabras clave correspondientes (keywords). + */ +const getStepsInitial = () => { + let contSI = 0 + let stepsInitial0 = [] + for (const resp in stepsReponse) { + // console.log(`${resp}: ${stepsReponse[resp]['keywords']}`); + if(stepsReponse[resp]['keywords'] !== undefined){ + stepsInitial0[contSI]= {"keywords":stepsReponse[resp]['keywords'], "key":resp} + contSI++ + } + } + return stepsInitial0 +} +const stepsInitial = getStepsInitial() const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - Agregamos parametro "num" para recibir el número de "app.js" // console.log(num) @@ -32,6 +49,7 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - */ if (process.env.DATABASE === 'none') { + var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null } /* ############################################### * REGEXP * #################################################### @@ -290,6 +308,21 @@ function remplazos(elTexto, extraInfo){ } // return histlMsjs; } + if (laLista[i].search('%body%')>-1){//Remplaza con el body del ctx. + const {theMsg} = extraInfo; + const { body } = theMsg + elTexto = elTexto.toString().replace('%body%', body); + } + if (laLista[i].search('%from%')>-1){//Remplaza con el from del ctx. + const {theMsg} = extraInfo; + const { from } = theMsg + elTexto = elTexto.toString().replace('%from%', from); + } + if (laLista[i].search('%solonumero%')>-1){//Remplaza con el from del ctx. + const {theMsg} = extraInfo; + const { from } = theMsg + elTexto = elTexto.toString().replace('%solonumero%', from.replace('@c.us', '')); + } if (laLista[i].search('%nombre%')>-1){//Remplaza con el nombre del remitente. if(typeof extraInfo !== undefined){ const {theMsg} = extraInfo; diff --git a/app.js b/app.js index d11d2d8..f3540d8 100644 --- a/app.js +++ b/app.js @@ -175,17 +175,73 @@ const listenMessage = () => client.on('message', async msg => { const step = await getMessages(message, from); if (step) { const response = await responseMessages(step); - // console.log("URL:"+nuevaRespuesta); - // console.log("HAY URL?? : "+nuevaRespuesta.search("/URL")); - + var resps = require('./flow/response.json'); nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); var pasoRequerido = resps[step].pasoRequerido; // var hayRequest = false; // if(hayRequest==false && nuevaRespuesta.search("/URL")>-1){console.log("Paramos flujo para que no mande el mensaje '/URL'."); return;}//Si el trigger es desbloqueo ya no hace nada mas. + // nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); + console.log('NUEVA RESPUESTA=', nuevaRespuesta) + + if(nuevaRespuesta.search("/URL")>-1){ + + // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. + // console.log(theUrl); + console.log("========== GET URL ============"); + /* + ============================================================================ + ======================== DESBLOQUEO DE USUARIOS ========================== + ============================================================================ + */ + console.log('PASOREQUERIDO=', pasoRequerido) + if(pasoRequerido=="soporte"){ + // var theUrl=nuevaRespuesta.substring(5).replace("XXPARAM1XX",newBody); + + // const RES = await axios.get(theUrl).then(function (response) { + // const { AffectedRows } = response.data['respuesta'][0] + // console.log('AFFECTED_ROWS = ', AffectedRows) + // if(response.data['respuesta'][0]['AffectedRows']=="1"){ + // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); + // } + // else{ + // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); + // } + // return response + // // console.log('AXIOS RES=', response) + // }).catch(function (error) { + // console.log(error); + // return error + // }); + // console.log('RES=', RES) + } + } + + if(response.hasOwnProperty('url') && response.hasOwnProperty('values')){ + let theURL = response.url; + let url0 = theURL + // console.log('EL_URL=', theURL) + let vals = response.values // Traemos los valores desde el response.json + let j = theURL.split('j=')[1] // Traemos el JSON del URL. + let j2 = JSON.parse(j) + let cont = 0 + const { params } = j2 // Traemos los parametros del JSON. + console.log('PARAMS=', params, params['par1'], Object.keys(params).length) + let url2 + for (const par in params) { // Remplazamos los valores en lo parametros. + console.log(`${par}: ${params[par]}, ${cont}: ${remplazos(vals[cont], client)}`); + if(cont==0){url2=url0.replace(params[par], remplazos(vals[cont], client));} + else {url2=url2.replace(params[par], remplazos(vals[cont], client));} + cont++ + } + // console.log('THE_URL=', url2) + desbloqueaUsuario(url2, step) //Llamamos al API para desbloquear el usuario. + return + } + /** - * Si quieres enviar botones + * Si quieres enviar imagen */ if (!response.delay && response.media) { // console.log("++++++++++++++++++++++++++++ SEND MEDIA NO DELAY +++++++++++++++++++++++++++++++++++"); @@ -199,20 +255,26 @@ const listenMessage = () => client.on('message', async msg => { } if (response.delay){ // await sendMessage(client, from, nuevaRespuesta, response.trigger, step); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. - response.replyMessage.forEach( async messages => { - var thisMsg = messages.mensaje - if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} - await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); + setTimeout(() => { + response.replyMessage.forEach( async messages => { + var thisMsg = messages.mensaje + if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} + await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); + }) }, response.delay) - } - else{ + } + else + { // await sendMessage(client, from, nuevaRespuesta, response.trigger, step); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. response.replyMessage.forEach( async messages => { var thisMsg = messages.mensaje if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); }) - } + } + /** + * Si quieres enviar botones o listas + */ if(response.hasOwnProperty('actions')){ const { actions } = response; // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); @@ -228,15 +290,6 @@ const listenMessage = () => client.on('message', async msg => { } return } - /** - * Regresa el mensaje enviado, con los remplazos procesados. - */ - if(message.search('/rpt') > -1){ - newBody = remplazos(newBody, client); - newBody = newBody.replace("/rpt ", ""); - client.sendMessage(from, newBody); - return - } /* ============================================================================ @@ -297,17 +350,17 @@ const listenMessage = () => client.on('message', async msg => { /** * Si quieres enviar botones */ - if(response.hasOwnProperty('actions')){ - const { actions } = response; - if(actions['sections'] === undefined){ //Botones - console.log("Botones") - await sendMessageButton(client, from, null, actions); - } - else{ //Listas - console.log("Listas") - await sendMessageList(client, from, null, actions); - } - } + // if(response.hasOwnProperty('actions')){ + // const { actions } = response; + // if(actions['sections'] === undefined){ //Botones + // console.log("Botones") + // await sendMessageButton(client, from, null, actions); + // } + // else{ //Listas + // console.log("Listas") + // await sendMessageList(client, from, null, actions); + // } + // } return } }); @@ -334,34 +387,34 @@ const listenMessageFromBot = () => client.on('message_create', async botMsg => { } }); - client = new Client({ +client = new Client({ authStrategy: new LocalAuth(), puppeteer: { headless: true, args: ['--no-sandbox','--disable-setuid-sandbox'] } - }); +}); - client.on('qr', qr => generateImage(qr, () => { +client.on('qr', qr => generateImage(qr, () => { qrcode.generate(qr, { small: true }); console.log(`Ver QR http://localhost:${port}/qr`) socketEvents.sendQR(qr) - })) +})) - client.on('ready', (a) => { +client.on('ready', (a) => { connectionReady() listenMessage() listenMessageFromBot() // socketEvents.sendStatus(client) - }); +}); - client.on('auth_failure', (e) => { +client.on('auth_failure', (e) => { // console.log(e) // connectionLost() - }); +}); - client.on('authenticated', () => { +client.on('authenticated', () => { console.log('AUTHENTICATED'); - }); +}); - client.initialize(); +client.initialize(); /** * Verificamos si tienes un gesto de db @@ -375,6 +428,41 @@ const listenMessageFromBot = () => client.on('message_create', async botMsg => { console.log(`El server esta listo en el puerto ${port}`); }) checkEnvFile(); + + /** + * Llama el API para desbloquear el usuario. + * + * @param {*} theURL El URL para llamar al API + * @param {*} step + */ + async function desbloqueaUsuario (theUrl, step) { + const {from} = client.theMsg + const RES = await axios.get(theUrl).then(function (response) { + const { AffectedRows } = response.data['respuesta'][0] + console.log('AFFECTED_ROWS = ', AffectedRows) + if(response.data['respuesta'][0]['AffectedRows']=="1"){ + sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); + } + else{ + sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); + } + return response + }).catch(function (error) { + console.log(error); + return error + }); + + + + + // const r = await axios.get(theUrl).then(function (response) { + // console.log('AXIOS RES=', response) + // }).catch(function (error) { + // console.log(error); + // return error + // }) + // return Promise.resolve(r) +} function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json" if (fs.existsSync(theFile)) { diff --git a/flow/initial.json b/flow/initial.json.bak similarity index 89% rename from flow/initial.json rename to flow/initial.json.bak index a4dfb3e..99158c3 100644 --- a/flow/initial.json +++ b/flow/initial.json.bak @@ -86,5 +86,16 @@ { "keywords": "*pak*3*|*pak*angular*|*paquete*3*|*paquete*angular*", "key": "paq3" + }, + { + "keywords": [ + "/soporte", + "/ayuda" + ], + "key": "soporte" + }, + { + "keywords": "*", + "key": "Desbloqueo" } ] \ No newline at end of file diff --git a/flow/response.json b/flow/response.json index 8663c30..723a7e9 100644 --- a/flow/response.json +++ b/flow/response.json @@ -15,6 +15,7 @@ "trigger":null }, "doblemensaje":{ + "keywords": "7|*doble*mensaje*", "replyMessage":[ {"mensaje":["Este es un ejemplo del envío de *varios* mensajes con la *misma regla* en el *response.json*"]}, { @@ -27,6 +28,7 @@ "goto":"menu" }, "menu":{ + "keywords": ["/menu"], "replyMessage":[ { "mensaje":[ @@ -45,6 +47,7 @@ "trigger":null }, "opcion1":{ + "keywords": ["1"], "replyMessage":[ { "mensaje":[ @@ -64,6 +67,7 @@ "goto":"menu" }, "opcion2":{ + "keywords": ["2"], "replyMessage":[ { "mensaje":[ @@ -81,6 +85,7 @@ "goto":"menu" }, "opcion3":{ + "keywords": ["3"], "replyMessage":[ { "mensaje":[ @@ -95,6 +100,7 @@ "pasoRequerido":"menu" }, "recibenombre":{ + "keywords": "*", "replyMessage":[ { "mensaje":[ @@ -109,6 +115,7 @@ "goto":"menu" }, "gRevisaCliente":{ + "keywords": "*", "replyMessage":[ { "mensaje":[ @@ -121,6 +128,7 @@ "pasoRequerido":"gallina" }, "gGuardainfo":{ + "keywords": "*", "replyMessage":[ { "mensaje":[ @@ -133,6 +141,7 @@ "pasoRequerido":"gRevisaCliente" }, "rnd":{ + "keywords": ["rnd"], "replyMessage":[ { "mensaje":[ @@ -150,6 +159,7 @@ "trigger":null }, "rnd2":{ + "keywords": ["rnd2"], "replyMessage":[ { "mensaje":[""] @@ -169,6 +179,7 @@ } }, "lista":{ + "keywords": ["4"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de listas"] @@ -195,6 +206,7 @@ "goto":"menu" }, "botones":{ + "keywords": ["5"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de botones"] @@ -216,6 +228,7 @@ "goto":"menu" }, "cursos":{ + "keywords": ["cursos"], "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste *Cursos*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -226,6 +239,7 @@ "goto":"menu" }, "youtube":{ + "keywords": ["youtube"], "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste *YouTube*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -236,6 +250,7 @@ "goto":"menu" }, "telegram":{ + "keywords": ["telegram"], "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste *Telegram*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -246,6 +261,7 @@ "goto":"menu" }, "manzana":{ + "keywords": ["manzana"], "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste *manzana*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -256,6 +272,7 @@ "goto":"menu" }, "mango":{ + "keywords": ["mango"], "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste *mango*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -266,6 +283,7 @@ "goto":"menu" }, "platano":{ + "keywords": ["platano"], "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste *platano*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -276,6 +294,7 @@ "goto":"menu" }, "paq3":{ + "keywords": "*pak*3*|*pak*angular*|*paquete*3*|*paquete*angular*", "replyMessage":[ { "mensaje":["*%saludo% %primer_nombre%*, seleccionaste el *paquete 3 de Angular*\n","Automáticamente el flujo se regresa al *menú*, asi que puedes poner nuevamente un número del 1 al 7 sin necesidad de volver a iniciar con */menu*."] @@ -286,6 +305,7 @@ "goto":"menu" }, "botonespaq3":{ + "keywords": ["6"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de botones y regExp"] @@ -305,5 +325,40 @@ }, "pasoRequerido":"menu", "goto":"menu" + }, + "soporte":{ + "keywords":["/soporte", "/ayuda"], + "replyMessage":[ + { + "mensaje":[ + "Bienvenido al soporte de Keymon, soy *Bow*.\n\n", + "Dame por favor el usuario que quieres desbloquear respetando *mayúsculas* y *minúsculas*." + ] + } + ], + "media":null, + "trigger":null + }, + "Desbloqueo":{ + "keywords": "*", + "replyMessage":[ + "/URL=http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\"}}" + ], + "url":"http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\", \"par2\":\"XXPARAM2XX\", \"par3\":\"XXPARAM3XX\"}}", + "values":["%body%","CDIAZ","%solonumero%"], + "media":null, + "trigger":null, + "pasoRequerido":"soporte" + }, + "gunaCats":{ + "keywords": "*", + "replyMessage":[ + "/URL=http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\"}}" + ], + "url":"http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\", \"par2\":\"XXPARAM2XX\", \"par3\":\"XXPARAM3XX\"}}", + "values":["%body%","CDIAZ","%solonumero%"], + "media":null, + "trigger":null, + "pasoRequerido":"soporte" } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c341a09..945db22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "test-ws-bot", - "version": "1.0.0", + "name": "chv-wweb-bot", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "test-ws-bot", - "version": "1.0.0", + "name": "chv-wweb-bot", + "version": "1.0.1", "license": "ISC", "dependencies": { "@google-cloud/dialogflow": "^5.2.0", @@ -25,7 +25,7 @@ "qrcode-terminal": "^0.12.0", "socket.io": "^4.5.1", "stormdb": "^0.6.0", - "whatsapp-web.js": "github:cheveguerra/whatsapp-web.js#WaWJS", + "whatsapp-web.js": "github:cheveguerra/whatsapp-web.js#WaWJS2", "xlsx": "^0.18.5" }, "devDependencies": { @@ -37,9 +37,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz", + "integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -576,9 +576,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "bin": { "acorn": "bin/acorn" }, @@ -1330,6 +1330,25 @@ "node-fetch": "2.6.7" } }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/culvert": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", @@ -1526,9 +1545,9 @@ } }, "node_modules/engine.io-parser": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.5.tgz", - "integrity": "sha512-mjEyaa4zhuuRhaSLOdjEb57X0XPP9JEsnXI4E+ivhwT0GgzUogARx4MqoY1jQyB+4Bkz3BUOmzL7t9RMKmlG3g==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz", + "integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==", "engines": { "node": ">=10.0.0" } @@ -2162,9 +2181,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -3030,9 +3049,9 @@ } }, "node_modules/marked": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz", - "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==", + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", "bin": { "marked": "bin/marked.js" }, @@ -3255,9 +3274,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", + "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -3330,9 +3349,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3908,9 +3927,9 @@ } }, "node_modules/protobufjs-cli/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3926,9 +3945,9 @@ } }, "node_modules/protobufjs-cli/node_modules/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4195,9 +4214,9 @@ } }, "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4518,9 +4537,9 @@ "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" }, "node_modules/socket.io-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", - "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", + "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -4774,9 +4793,9 @@ } }, "node_modules/systeminformation": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.17.1.tgz", - "integrity": "sha512-NX/EjbKznOTgt2pfCzZb5bPj5YJOO9mCUrRXquGMtmlfs+BowVaMsJSUUCvqOm9wexx4/F+ng4JQp6I4sG+SyA==", + "version": "5.17.4", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.17.4.tgz", + "integrity": "sha512-mEiIYrw7X5ABX8tJUgzbumQAuFQxNyHdZDz6+UtwNKUbKgIoZqLtug2z1spFB/LiXZne5tdPBJOlvVckbvfhiQ==", "dev": true, "optional": true, "os": [ @@ -5120,8 +5139,8 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatsapp-web.js": { - "version": "1.18.4", - "resolved": "git+ssh://git@github.com/cheveguerra/whatsapp-web.js.git#b3e5d99f521c6d594fd2e204f12d3fd8ae4eba3b", + "version": "1.19.2", + "resolved": "git+ssh://git@github.com/cheveguerra/whatsapp-web.js.git#025f9914c3ee090c760fe6f2218e68b8bc9225af", "license": "Apache-2.0", "dependencies": { "@pedroslopez/moduleraid": "^5.0.2", From ff05e96cc6671e3f4ab1ebc89e9214a9c7f054a6 Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Sun, 29 Jan 2023 16:03:14 -0600 Subject: [PATCH 02/19] No Initial --- app.js | 257 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 145 insertions(+), 112 deletions(-) diff --git a/app.js b/app.js index f3540d8..5ff1103 100644 --- a/app.js +++ b/app.js @@ -21,6 +21,7 @@ const { isUndefined } = require('util'); const { isSet } = require('util/types'); const { Console } = require('console'); const { ClientRequest } = require('http'); +const { guardaXLSDatos, leeXLSDatos} = require('./Excel'); const app = express(); app.use(cors()) app.use(express.json()) @@ -105,6 +106,8 @@ const listenMessage = () => client.on('message', async msg => { return } + + if(body=='/listas'){ const productList = new List( "Here's our list of products at 50% off", @@ -123,104 +126,104 @@ const listenMessage = () => client.on('message', async msg => { ); console.log('##################################################################################################') // console.log(from, lista) - // let sections = [{title:'sectionTitle',rows:[{id:'ListItem1', title: 'title1'},{id:'ListItem2', title:'title2'}]}]; - // let lista = new List('List body','btnText',sections,'Title','footer'); - console.log("****************** productList ******************") - console.log(productList) - client.sendMessage(from, productList); //cliente.sendMessage recibe el arreglo SIN nombres (solo las secciones los necesitan) - // client.sendMessage('5215527049036@c.us', productList); - // client.sendMessage('5215554192439@c.us', productList); - // await sendMessageList(client, '5215545815654@c.us', null, lista); //sendMessageList recibe el arreglo CON nombres, como viene del response.json - // await sendMessageList(client, '5215527049036@c.us', null, lista); - // await sendMessageList(client, '5215554192439@c.us', null, lista); - // client.sendMessage(from, lista); - } - - /** - * PRUEBA BOTONES NUEVOS - */ - // if(body=="579"){ - // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button + // let sections = [{title:'sectionTitle',rows:[{id:'ListItem1', title: 'title1'},{id:'ListItem2', title:'title2'}]}]; + // let lista = new List('List body','btnText',sections,'Title','footer'); + console.log("****************** productList ******************") + console.log(productList) + client.sendMessage(from, productList); //cliente.sendMessage recibe el arreglo SIN nombres (solo las secciones los necesitan) + // client.sendMessage('5215527049036@c.us', productList); + // client.sendMessage('5215554192439@c.us', productList); + // await sendMessageList(client, '5215545815654@c.us', null, lista); //sendMessageList recibe el arreglo CON nombres, como viene del response.json + // await sendMessageList(client, '5215527049036@c.us', null, lista); + // await sendMessageList(client, '5215554192439@c.us', null, lista); + // client.sendMessage(from, lista); + } + + /** + * PRUEBA BOTONES NUEVOS + */ + // if(body=="579"){ + // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button // for (const component of [buttons_reply]) await client.sendMessage(from, component); // } - - - + + + /** * Ver si viene de un paso anterior * Aqui podemos ir agregando más pasos * a tu gusto! - */ - - const lastStep = await lastTrigger(from) || null; - // console.log("LAST STEP="+lastStep+", FROM:"+from); - if (lastStep) { - const response = await responseMessages(lastStep) - console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); - // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. - response.replyMessage.forEach( async messages => { - var thisMsg = messages.mensaje - if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} - await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); + */ + + const lastStep = await lastTrigger(from) || null; + // console.log("LAST STEP="+lastStep+", FROM:"+from); + if (lastStep) { + const response = await responseMessages(lastStep) + console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); + // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. + response.replyMessage.forEach( async messages => { + var thisMsg = messages.mensaje + if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} + await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); }) } /** * Respondemos al primero paso si encuentra palabras clave - */ - // const step = await getMessages(message, ); - // console.log("STEP - "+step+"|"+message); - // console.log("****** STEP="+step); - // console.log("****** MESSAGE:"+message); - const step = await getMessages(message, from); - if (step) { - const response = await responseMessages(step); - - var resps = require('./flow/response.json'); - nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); - var pasoRequerido = resps[step].pasoRequerido; - // var hayRequest = false; - // if(hayRequest==false && nuevaRespuesta.search("/URL")>-1){console.log("Paramos flujo para que no mande el mensaje '/URL'."); return;}//Si el trigger es desbloqueo ya no hace nada mas. - - // nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); - console.log('NUEVA RESPUESTA=', nuevaRespuesta) - - if(nuevaRespuesta.search("/URL")>-1){ - - // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. - // console.log(theUrl); - console.log("========== GET URL ============"); - /* - ============================================================================ + */ + // const step = await getMessages(message, ); + // console.log("STEP - "+step+"|"+message); + // console.log("****** STEP="+step); + // console.log("****** MESSAGE:"+message); + const step = await getMessages(message, from); + if (step) { + const response = await responseMessages(step); + + var resps = require('./flow/response.json'); + nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); + var pasoRequerido = resps[step].pasoRequerido; + // var hayRequest = false; + // if(hayRequest==false && nuevaRespuesta.search("/URL")>-1){console.log("Paramos flujo para que no mande el mensaje '/URL'."); return;}//Si el trigger es desbloqueo ya no hace nada mas. + + // nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); + console.log('NUEVA RESPUESTA=', nuevaRespuesta) + + if(nuevaRespuesta.search("/URL")>-1){ + + // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. + // console.log(theUrl); + console.log("========== GET URL ============"); + /* + ============================================================================ ======================== DESBLOQUEO DE USUARIOS ========================== ============================================================================ */ - console.log('PASOREQUERIDO=', pasoRequerido) - if(pasoRequerido=="soporte"){ - // var theUrl=nuevaRespuesta.substring(5).replace("XXPARAM1XX",newBody); - - // const RES = await axios.get(theUrl).then(function (response) { - // const { AffectedRows } = response.data['respuesta'][0] - // console.log('AFFECTED_ROWS = ', AffectedRows) - // if(response.data['respuesta'][0]['AffectedRows']=="1"){ - // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); - // } - // else{ - // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); - // } - // return response - // // console.log('AXIOS RES=', response) - // }).catch(function (error) { - // console.log(error); - // return error - // }); - // console.log('RES=', RES) - } - } - - if(response.hasOwnProperty('url') && response.hasOwnProperty('values')){ - let theURL = response.url; - let url0 = theURL + console.log('PASOREQUERIDO=', pasoRequerido) + if(pasoRequerido=="soporte"){ + // var theUrl=nuevaRespuesta.substring(5).replace("XXPARAM1XX",newBody); + + // const RES = await axios.get(theUrl).then(function (response) { + // const { AffectedRows } = response.data['respuesta'][0] + // console.log('AFFECTED_ROWS = ', AffectedRows) + // if(response.data['respuesta'][0]['AffectedRows']=="1"){ + // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); + // } + // else{ + // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); + // } + // return response + // // console.log('AXIOS RES=', response) + // }).catch(function (error) { + // console.log(error); + // return error + // }); + // console.log('RES=', RES) + } + } + + if(response.hasOwnProperty('url') && response.hasOwnProperty('values')){ + let theURL = response.url; + let url0 = theURL // console.log('EL_URL=', theURL) let vals = response.values // Traemos los valores desde el response.json let j = theURL.split('j=')[1] // Traemos el JSON del URL. @@ -239,13 +242,13 @@ const listenMessage = () => client.on('message', async msg => { desbloqueaUsuario(url2, step) //Llamamos al API para desbloquear el usuario. return } - + /** * Si quieres enviar imagen - */ - if (!response.delay && response.media) { - // console.log("++++++++++++++++++++++++++++ SEND MEDIA NO DELAY +++++++++++++++++++++++++++++++++++"); - sendMedia(client, from, response.media, response.trigger); + */ + if (!response.delay && response.media) { + // console.log("++++++++++++++++++++++++++++ SEND MEDIA NO DELAY +++++++++++++++++++++++++++++++++++"); + sendMedia(client, from, response.media, response.trigger); } if (response.delay && response.media) { setTimeout(() => { @@ -274,32 +277,62 @@ const listenMessage = () => client.on('message', async msg => { } /** * Si quieres enviar botones o listas - */ - if(response.hasOwnProperty('actions')){ - const { actions } = response; - // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); - if(actions['sections'] === undefined){ //Botones - console.log("Botones") - await sendMessageButton(client, from, null, actions); - } - else{ //Listas - console.log("Listas") - // console.log(actions) - await sendMessageList(client, from, null, actions); - } + */ + if(response.hasOwnProperty('actions')){ + const { actions } = response; + // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); + if(actions['sections'] === undefined){ //Botones + console.log("Botones") + await sendMessageButton(client, from, null, actions); + } + else{ //Listas + console.log("Listas") + // console.log(actions) + await sendMessageList(client, from, null, actions); } - return } + return +} - /* - ============================================================================ - ========================== ENVIO MASIVO TEST =========================== - ============================================================================ - */ - if(message=='/spam'){ - const masivo = require('./spam.json') - var saludo; - var caritas; +if(body=='trae'){ + const rows = await leeXLSDatos('x') + console.log("RESULTADOS:") + // d.forEach(row => async function() { + // console.log(row.nombre, row.edad, row.sexo) + // client.sendMessage(from, `Hola ${row.nombre}, recuerda que tienes un adeudo pendiente`) + // }) + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + async function retardo() { + for (sp=1;sp setTimeout(resolve, ms)); } From 3b2106fef8e9cb536ceaee1f3911e5724c94fbbc Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Sun, 29 Jan 2023 16:09:15 -0600 Subject: [PATCH 03/19] NoInitial2 --- Excel.js | 57 ++++++++++++++++++++++++++++++++++++++++++++++ bot.xlsx | Bin 0 -> 10160 bytes package-lock.json | 18 +++++++-------- 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 Excel.js create mode 100644 bot.xlsx diff --git a/Excel.js b/Excel.js new file mode 100644 index 0000000..c02a45e --- /dev/null +++ b/Excel.js @@ -0,0 +1,57 @@ +const ExcelJS = require('exceljs'); +const fs = require('fs') +const workbook = new ExcelJS.Workbook(); + +const guardaXLSDatos = async (nombre, edad, sexo) => { + // read from a file + await workbook.xlsx.readFile('./bot.xlsx'); + // fetch sheet by name + const worksheet = workbook.getWorksheet('Bot'); + const rowValues = []; + rowValues[1] = nombre; + rowValues[2] = edad; + rowValues[3] = sexo; + worksheet.addRow(rowValues); + await workbook.xlsx.writeFile('./bot.xlsx'); + console.log(rowValues) + console.log("Guardamos XLS") +} + +const leeXLSDatos = async (srchStr) => { + // read from a file + await workbook.xlsx.readFile('./bot.xlsx'); + // fetch sheet by name + const worksheet = workbook.getWorksheet('Bot'); + console.log(worksheet.rowCount) + let colNombre = worksheet.getColumn(1).values + let cont = 0 + let encontrado = 0 + let row + let res = [] + // while (cont <= worksheet.rowCount && encontrado == 0) { // Ocupamos while en lugar de forEach para que deje de buscar en cuanto encuentre el resultado. + // console.log(cont, colNombre[cont], srchStr) + // if(colNombre[cont] === srchStr) { + // row = worksheet.getRow(cont); + // res['nombre'] = row.getCell(1).value + // res['edad'] = row.getCell(2).value + // res['sexo'] = row.getCell(3).value + // encontrado = colNombre[cont] + // } + // cont++; + // } + // console.log("RES=", res) + // for (let index = 0; index < worksheet.rowCount; index++) { + + + + // } + let rows = [] + worksheet.eachRow(function(row, rowNumber) { + // console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values)); + rows[rowNumber-1]={'nombre':row.getCell(1).value, 'carnet':row.getCell(4).value, 'factura':row.getCell(5).value, 'prefijo':row.getCell(6).value} + }); + // console.log(rows) + return rows +} + +module.exports = {guardaXLSDatos, leeXLSDatos}; \ No newline at end of file diff --git a/bot.xlsx b/bot.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2a8d0997ad610921a32bae61fe27f60f6a65b9cb GIT binary patch literal 10160 zcmeHtWmFtlw|3+18l2#+L4sR?yF&uqxVuYm4-O$Xfe_r?-Q6X)1}9jsa66fqJ2On~ zx89%MTJKb^?pn3F_EUBCInRD}?Olp8P|(-_SO7c#03ZhxTxsUGLjVBSumAuS03K3D z%*NW$$l6g))y>w(;T5y1l_l8+Xh_;j03`VQf4Bc)4-BdHn|HFJH{;!)y_m&hkjje3 zqzPv3<%&Ls!nUvspNk!no!C6)bHBMm&@*A(p6&BH!5 z>HDbhMR$wrcIn7pHjS!mDvLl28IC17UqWhpKkSW7{7?kW_}TVrxdiwvFEeEcMpfow zL9#D(j2v{P@0jU>BFEtr36KB<19Nbl5kN?BOXNWQfhU<=&N(_7Y#Ll0WvnE}b2kV< zH=9+3R!eYE6!<9PnlSDfI3Di`mA&g(GkCe9M*XX-bcFwp?rRI!M%OSLTuGlsQpHB!pFN^{9eOvJXa z%5NVAW4aRf%5Z9$cvKj@uT79Ml4&J9hN4VhO@vi6t(@Q-!+PHE=7bOcczA#UDE^JI z)oQF17vOa$3uYt|n6i5IMwSjN%s+nrrRsk%KmRiHh}cp2PFCceW6375&D%X|N%*Xf zjk1!B;sWw#`&Yi9js!oei`i|TOMBA~|7vZbDDPJ9Yz_BO8~Je;5*{*D5~Nvwd4bb4U_F@{xX0BAZM z_ax8gbNrS-P%DWd6aRF(IXs*PT!G*X|8+$zr<{!|%eEKjoqU9FIu_rc^Ol$~QvT>- zUb5(*lt0c{>Lf=0?NbA&bm|3Nh4Y6R9=oS9p<|M(XZ$N+4#NBUzRVe>`QMsH_}4!L ztjQUE1Gaagsp^3T{!f-HBiz$Mf`x4g3IHGgz(crNviwFA7aMyEkd2MS4{7^@G!S5Y z1E2ffy*0&+g5x`Q(fBv}k9*n0S{ubbZ;lWt)wu#tE3J=paV1{T*a*dmH3;`JXW{u% z-gya)eY#)!blimpYo4YSO+^P^^|4TUk@g!;vmn1e*-XtuT4kQTu%DRSo7y*>@(y?6 zxfhfl!l+<^=8to7CiF|`>`1Iqr^_k`iP7-Y>GM{!CBs}IQa_FJdG;wdQab_zrWzx>i&xUA<9SA_R|ib{ zcApTX?L?tf&dlA{vU&JHFBnyQZF$eW9foLr1e*)-Hf3Ti*~9WMvc3lruLSa>8YG4N zR%`fUE?!XnJz6lGj8Gbx{^}*PW=<|7-*sW?O9o{v0XG`?Pw=$7GvvsT`j*Nl7oQ(3YL*1Y$`};Z$0XD`UnQ_~d3|C)Le?3lY?GL0&D+b^%hg!0Ln!4ao%gqe_?P#sL#Y%x>Sbi(RoC zS2>fsV}FGENYi`Z*0Fi@H*B_Zq_h(9>U zPtG!JZ{3A|^MnI1qA$-_#?$2ayr# zOD&g*1Iw2_!znsq^bWx>L~9XB(7>CM5-mO$KM|37;q~-g)4!itl8kaUI7f0z6oOyRbIBo3ZG2BiV-OZhNaxvmuyXbfVYj`?L z<@q38sO54Bi_K1;@NR4&>)u;hAXt`Xktxsy;F+D=fkzt>#NWUfju16npc#JR#e4%8 z6Ar?88Sz0!PHGE7i-Zam}rVVhmliVyk%{V#z1l}O@H&Scdc^1 zcOAD8JQ_**-SKXB{IrvliOFP*InsZ<zuDyjsj_Y*dG8_tr&2_>>mvb;gp5A#ngG*A!ug5V#4r;xQp+mPWA^JEPZh zii6mvW2 z^m#fRQ9=ySdI%1RH&$VpY+t+XHwj$@`V&WC{FlvaF%_1>RuDJ1soqdx&Gb&UBq=YM zm1&><6#5|MXSIoMO@a?`ybnJi=Fd*gXm>g@_L8ayYvaq zkB`$u+j}G`4j{XujY-h_iDCIN-S%et>(H0Vok2Z z%U=iHq9yJU^M_v{75o)B$##-kEgG6B%@G%= zodv2-il)8S84fWH`_Rdxp_MY1I@rEhZ_b*egY}#c`W{`g9--HJm|%o2DW<%p@j_`E zcOx*|F$VcGDMxU^o#i&qI5oa|Aoi&?8X@w{fos?_;%DvT143KA@VKypJ%%}>We+SC zBaEgKOhvx;k&MjLG~we)ix$sj2uQx#O!_iCHKp90@^y@Mkm(586;e?n;R9s@auN)u=8oZf37N$!IogV0i^fy_TA^Tvf|jn z-QoNa_6`JV(#s|znwqGS_CbqUr;bjt9(lW%jAU1xzESDut{^GCl}s%RcqgPHaZFZ8z9M=Bno+;_3SF1^mt`ZViumZzJij{ja!^zsIZ*5sREoRJl_GqWb%B&N zEb@`zUH!2c>|4mCP3*Jbe8cNy3y0N=BTq|qe`RZ8E)+TA2i>kF0nLK~=Vq<+!)6JI z^R5rW1twY$Lx?&e405-#*lVde#l@O31f|c|*V@7d2|D$c(Wz`>0?tY29`a7!->+tI zPmv4xEQGDz22#TUp_IJ(xkx1OB>8y!diqfp^e1wP%qC}~beI;4Sn4K+uhUs;5)T-^ z3w|m;+a5C7*<6<(;Hxe(u;8nim|C5WqeB#nJ0LS4GH8j%5i&j<_p&`l_2f!oqmpB7 z|3vSb6-<)E@3UD;G(1t<`b!bxvtpNN2md1qPBAEc6R{uZg@dV)k)y-!x$4h@pL+H) zQw@k}59?sXmbilYF6QbHHxq~~ro#QSPHhJYbh7}v_%8Yi``)9H$f#{=%XV~&E9I6y zpU@aJhH8BCxg{A&US2x1H(C=1sXS1L@*cm_ zyKBBY5+OfYaC=@V)Qz?OI-GEhx}ddt0*F$+&}@+9BPTyQ-Hl*iKU-$+0{&^K3 z2BSUDua?aji`>t=eIObL7in#NuKq&Wi$ZiqMBOXq**f*;abUv2DHL#>1*reZ0tQKy z5Q&+Dj3gq0^Npz!ULT$ajG2Tk^3UeZNErN+=!pNNG6}Own zHq~G8%Oanwbpgj5h7H(o#gpY2aHrgCx87U>Dq#TP>;mI>|!7~{+%QUTj-v{n9W9?&~!(jy)QHsx@GnF$tvJs(i( zEq;_#^22$l@ta?+*8gCxIR2fh|3BtR4PAfX6Zo;$81et))z6qxq`qjq$b;^sr~e?b z>QNMK)X&a{cPcT*Z;4@9bI8Fo&V?a06cK303Gg1IF&;-l$NbMo&g}D7qPh7#+wl zwnBTZMp7ZC4b(xe+%e#L3Mo^!^-@PQbye0s?DHiNO&OA`j3GYm9R<;WZ6@7(#kp>@ zG6AN%J!6))-G_v{`LJ^eN0{x=ojqnF2^egTWR>dzsTj4K@L+>}p5>j)+wKcHZHN67 z3@;It5oo?Xgt7VDvGVP{NK1WfCJscz_(NQpVEm=Va7y7z^Zfg3>3%iG5~k2A1xlKH z$|qF_S}RW&(v?%=Mh8}j(s{?8Psa-wj3Ryq_@ZuN5afPcRh>YZk0$CkhT7eKLtQCv z!R@9oc-c@wK5pf?sr~}>Tk7DOxeFH2C>n&&`_QPOb4E&rWRul+cFUM%>rlxo6~#fr zg3XVNaLV7R5eukMBYIeF9;7+k{0j9kgVv@pf+~|Q7p=B}xFwH+QvEC|1v7?rM0Q7T z6#F!$xiYyEnx!C|_BT)TXyCA}#QOs1jf7ytFj0aYuFh@?3>QsjU~S5~3aLyqka~zQ zLl6sxH<&X?Tlc8v@-&Zd2rJB{a&Pyi_-Y!6Xxvq;OrdKUQi|9C8x|))ix-ac7annl$t7 z>eY7PL*$lEuKMN^Ok)Tqx3HPcW77j|kb>HL} z2efj0D^Yi0^^vNryUKk&d8p`J{i8F2!TD--zX@hQR|r zg#IZ)B+AXm4h1;_xE~J5H=9fJ+l_CoWhI!MVp1zQR+M6vlSclmt+FxAnwDh8CwK z6yH|(qCYJj=m=dM9`}SBs1!nB>KtPVkVt4}F?gCSagCE6Uk|6L6SXBMdIX1l7nun^ zzo9oqEg;Eoo0)8a%v z9_LZ4ZPKbU#LPNvHpKN->}D^8rDHCDlZ)nh@)M>sIE!~T(+Y%B9c9AwEgGg)eoe_3 zGmo38UelQU9Xe)c2U9TXMa9V|YLCPFQ6D1Md|vFV!&1_;18@S3zku)hU ziqCVej)P`7WBZ@A`^=BczSO|1(7q-vOEvmZ|6rec>+*%=m+mCEICDM*yAm4Q4nz6f zosMpnMnC;nrPgn~_@m>oD}>&}pbe_8A*T!3fQKK0g^7i1p1?H1T6-F;YW``r)g`Z6 zJ(<~TQukmj+VjkK+b%x!5c=hnDq*f+SZ5r7f*whYyh+8hQq#l%&F0!HfubERTzdU_JRr; zz)oQS2*zu`{%F)ocpz3<%0e-Vz)Xb*qAI+sE^aS;XbBg)OeleB8)69yH68s{OPRKW zvqJF+*^E0SMirl(2#=1%cBGm(Ys>NH7>BCvgHZ(VOnf?ab+oK7Jd|&CFXGDaO^P^E zf_eTjQJ98tnmzc{)MD)|fpP*_awNOu{ptCOI4}I}Y$R_&^a|Am=or*$7o#IxtqwDz zEZAhLnxmBh0`J)Y?OoHv_z25*N+Q`eb>oE5@*=#gcB0>P1v-}1B)OjAT^7i)@gr!Q zvqP~fk0Y>Q?WZqqsnQ9Q9=-Cp+G;H5GjBqI{(!ACXj($}uuJdsoDrfgx zyG`)Wu%^&kjyK@LT@xnUz$?WoR^6rtaUi>p^Ts?;31NBea~qoRm_Y`1hgdgtCvQWp zKKK9*x3W{??HV&_nhvs_v^K$xfXWUQofbZ7n%C zW_8U1mbu?d-(*r*Ko7NkpL*$BYKauHo_)V8&}X{`8cXxC(Fe5)nRCjV&JJ!hUhlC- zHEETly2Yswc$~S`e_ikIwyz%85y95=Bpg1%lRdgbf)YigLFxpy>-ae?e_H| z4MK0pqBave=e!h+)4xukyvxFB;q`2(JpLs!w0jUCBxq?Zk!m7?DzH~QllupRqN|Fm``F6KAy4( zlcV~q%jN=mdW*JopkP6zMF+o{e)LS)I27ODsX{@9J717>S)UGC^hJ}6M z(qDT2l_bI%DcAW!~0 zE)}6mv)PItx!NWs);shIjs-xJYMzxV*nTf<=183d77FiOkDxv@a1GOLzYpqr-VF6P zUspKYX&dX;NS>>hTw9tUxlw_KT27FBDW`1c+V?iC?%Zc7mfA- z{7UP-@+$jq3W-5uVMRykgJ5F?k@JzMgp&po#k0J~4kHvfggLR|A4uUp3;4@rD(i!@ z?_b;vUmOLJFql?KV9~+&E3FJ{?2Z2A71(FLZ=SJA7M*0+fh%ygXzf?xaiX)*u^n7D zRUP_I2tBZxt&GM)8b01%aY&`)D#Et7j@GXTydKhkQ+wH}pJwUkI}wlx&uIhhus}9z z?7R9t-Fc5&WX*}a3y)enaNC$lI6#P0TEnK_42=g9>l~i~dDzU2ZP0s_nIz*U24}aZ z+3i`kK+F~KrjmFyBAQoy^}T-j8Y+HDOo+T>`^%i`awjx&A~6)iDiUn~`}3j@Q4D00NQ;oFe}EO`ku!{Kx(m z@BJvs{2k!$?;ZSM_+wuQzT{utLU?TW_g3s*4d=mx{l6Qtk8vJ1z9bTr&9cUZ!woC3m literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 945db22..1d5f556 100644 --- a/package-lock.json +++ b/package-lock.json @@ -797,9 +797,9 @@ } }, "node_modules/ast-types/node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", "dev": true }, "node_modules/async": { @@ -1246,9 +1246,9 @@ } }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } @@ -4793,9 +4793,9 @@ } }, "node_modules/systeminformation": { - "version": "5.17.4", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.17.4.tgz", - "integrity": "sha512-mEiIYrw7X5ABX8tJUgzbumQAuFQxNyHdZDz6+UtwNKUbKgIoZqLtug2z1spFB/LiXZne5tdPBJOlvVckbvfhiQ==", + "version": "5.17.7", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.17.7.tgz", + "integrity": "sha512-0eQA5IkDlP4njQm9b5LvApCXaD52zFLfu+Xte1VdfaMChu4DxCSCmCjr/jAQK63gtHJ63x5gstCW5y3oWh9n+A==", "dev": true, "optional": true, "os": [ From ce9d82fcf7afff756da58d933ebfcead03c517cf Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Mon, 30 Jan 2023 20:30:02 -0600 Subject: [PATCH 04/19] feat: Funciones --- app.js | 144 +++++++++++++++++++++++++++++++++++---------- flow/response.json | 15 ++--- 2 files changed, 120 insertions(+), 39 deletions(-) diff --git a/app.js b/app.js index 5ff1103..d496246 100644 --- a/app.js +++ b/app.js @@ -45,11 +45,7 @@ const listenMessage = () => client.on('message', async msg => { // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); console.log("+++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++"); // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); - client.theMsg = msg; - - - console.log("HORA:"+new Date().toLocaleTimeString()+" FROM:"+from+", BODY:"+body+", HASMEDIA:"+hasMedia); newBody = removeDiacritics(body) //MOD by CHV - Agregamos para quitar acentos // newBody = remplazos(newBody); @@ -146,15 +142,13 @@ const listenMessage = () => client.on('message', async msg => { // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button // for (const component of [buttons_reply]) await client.sendMessage(from, component); // } - - - + /** * Ver si viene de un paso anterior * Aqui podemos ir agregando más pasos * a tu gusto! */ - + const lastStep = await lastTrigger(from) || null; // console.log("LAST STEP="+lastStep+", FROM:"+from); if (lastStep) { @@ -167,7 +161,7 @@ const listenMessage = () => client.on('message', async msg => { await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); }) } - + /** * Respondemos al primero paso si encuentra palabras clave */ @@ -189,7 +183,6 @@ const listenMessage = () => client.on('message', async msg => { console.log('NUEVA RESPUESTA=', nuevaRespuesta) if(nuevaRespuesta.search("/URL")>-1){ - // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. // console.log(theUrl); console.log("========== GET URL ============"); @@ -201,7 +194,6 @@ const listenMessage = () => client.on('message', async msg => { console.log('PASOREQUERIDO=', pasoRequerido) if(pasoRequerido=="soporte"){ // var theUrl=nuevaRespuesta.substring(5).replace("XXPARAM1XX",newBody); - // const RES = await axios.get(theUrl).then(function (response) { // const { AffectedRows } = response.data['respuesta'][0] // console.log('AFFECTED_ROWS = ', AffectedRows) @@ -218,13 +210,101 @@ const listenMessage = () => client.on('message', async msg => { // return error // }); // console.log('RES=', RES) - } - } - - if(response.hasOwnProperty('url') && response.hasOwnProperty('values')){ - let theURL = response.url; - let url0 = theURL - // console.log('EL_URL=', theURL) + } + } + /** + * Llama el API para tre categoria de Guna. + * @param {*} ctx El objeto del mensaje. + */ + async function getGunaCats(ctx) { + // let par1 = ctx.theMsg.body + // let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectTipoFerreroMty","exec":"ExecuteQuery","params":{"par1":"${par1}"}}` + // const RES = await axios.get(theUrl).then(function (response) { + // console.log('getGunaCats = ', response.data.respuesta.length, response.data.respuesta) + // let elMensaje = "%saludo%,\nEscoge una de nuestras categorías:\n\n" + // let lasOpciones = "[" + // for(reg=0;reg client.on('message', async msg => { cont++ } // console.log('THE_URL=', url2) - desbloqueaUsuario(url2, step) //Llamamos al API para desbloquear el usuario. + desbloqueaUsuario2(url2, step) //Llamamos al API para desbloquear el usuario. return } - + /** - * Si quieres enviar imagen + * Si quieres enviar imagen. */ - if (!response.delay && response.media) { - // console.log("++++++++++++++++++++++++++++ SEND MEDIA NO DELAY +++++++++++++++++++++++++++++++++++"); - sendMedia(client, from, response.media, response.trigger); + if (!response.delay && response.media) { + // console.log("++++++++++++++++++++++++++++ SEND MEDIA NO DELAY +++++++++++++++++++++++++++++++++++"); + sendMedia(client, from, response.media, response.trigger); } + /** + * Si quieres enviar imagen con retraso. + */ if (response.delay && response.media) { setTimeout(() => { // console.log("++++++++++++++++++++++++++++ SEND MEDIA AND DELAY +++++++++++++++++++++++++++++++++++"); sendMedia(client, from, response.media, response.trigger); }, response.delay) } + /** + * Si quieres enviar mensaje con retraso. + */ if (response.delay){ // await sendMessage(client, from, nuevaRespuesta, response.trigger, step); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. setTimeout(() => { @@ -267,6 +353,9 @@ const listenMessage = () => client.on('message', async msg => { }, response.delay) } else + /** + * Si quieres enviar un mensaje. + */ { // await sendMessage(client, from, nuevaRespuesta, response.trigger, step); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. response.replyMessage.forEach( async messages => { @@ -402,7 +491,6 @@ if(message=='/spam'){ /** * Este evento es necesario para el filtro de Dialogflow */ - const listenMessageFromBot = () => client.on('message_create', async botMsg => { const { body } = botMsg; const dialogflowFilterConfig = fs.readFileSync('./flow/dialogflow.json', 'utf8'); @@ -468,7 +556,7 @@ client.initialize(); * @param {*} theURL El URL para llamar al API * @param {*} step */ - async function desbloqueaUsuario (theUrl, step) { + async function desbloqueaUsuario2(theUrl, step) { const {from} = client.theMsg const RES = await axios.get(theUrl).then(function (response) { const { AffectedRows } = response.data['respuesta'][0] @@ -484,10 +572,6 @@ client.initialize(); console.log(error); return error }); - - - - // const r = await axios.get(theUrl).then(function (response) { // console.log('AXIOS RES=', response) // }).catch(function (error) { diff --git a/flow/response.json b/flow/response.json index 723a7e9..e64b56f 100644 --- a/flow/response.json +++ b/flow/response.json @@ -342,23 +342,20 @@ "Desbloqueo":{ "keywords": "*", "replyMessage":[ - "/URL=http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\"}}" + "Mensaje de desbloqueo de usuarios." ], - "url":"http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\", \"par2\":\"XXPARAM2XX\", \"par3\":\"XXPARAM3XX\"}}", - "values":["%body%","CDIAZ","%solonumero%"], + "funcion":"desbloqueaUsuario", "media":null, "trigger":null, "pasoRequerido":"soporte" }, "gunaCats":{ - "keywords": "*", + "keywords": "/guna", "replyMessage":[ - "/URL=http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\"}}" + "Mensaje de getGunaCats" ], - "url":"http://localhost:8888/dbrquery?j={\"query\":\"update_usuario_guna_nobajas\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\", \"par2\":\"XXPARAM2XX\", \"par3\":\"XXPARAM3XX\"}}", - "values":["%body%","CDIAZ","%solonumero%"], + "funcion":"getGunaCats", "media":null, - "trigger":null, - "pasoRequerido":"soporte" + "trigger":null } } \ No newline at end of file From 652515adb9283c877a66373af8ad2b55e195102e Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Fri, 3 Feb 2023 18:17:11 -0600 Subject: [PATCH 05/19] Initial --- .env | 2 +- adapter/index.js | 107 +++++--- adapter/test.js | 394 +++++++++++++++++++++++++++++ app.js | 386 +++++++++++++++++++--------- controllers/send.js | 2 +- flow/response.json | 67 ++++- implementaciones/credenciales.json | 12 + implementaciones/sheets.js | 81 ++++++ package-lock.json | 101 ++++++++ package.json | 2 + 10 files changed, 982 insertions(+), 172 deletions(-) create mode 100644 adapter/test.js create mode 100644 implementaciones/credenciales.json create mode 100644 implementaciones/sheets.js diff --git a/.env b/.env index 1480e57..346cec9 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ ######DATABASE: none, mysql, dialogflow -DEFAULT_MESSAGE=true +DEFAULT_MESSAGE=false SAVE_MEDIA=true PORT=3005 DATABASE=none diff --git a/adapter/index.js b/adapter/index.js index 086c9f2..0f0be4b 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -6,12 +6,12 @@ const stepsReponse = require('../flow/response.json') const { isUndefined } = require('util'); var msjsRecibidos = []; var ultimoStep; //MOD by CHV - -var pasoAnterior = []; //MOD by CHV - Para guardar el paso anterior de cada número. +// var pasoAnterior = []; //MOD by CHV - Para guardar el paso anterior de cada número. (MOD - global en app.js) var pasoRequerido; //MOD by CHV - -var vamosA = ""; //MOD by CHV - +var _vamosA = ""; //MOD by CHV - var VA = ""; //MOD by CHV - var elNum; //MOD by CHV - -var cumplePasoPrevio; //MOD by CHV - +var cumplePasoPrevio = []; //MOD by CHV - const resps = require('../flow/response.json'); //MOD by CHV - Agregamos para traer las respuestas. const { appendFile } = require('fs') /** @@ -51,6 +51,7 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - if (process.env.DATABASE === 'none') { var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null } + console.log("KEY="+key) /* ############################################### * REGEXP * #################################################### Si queremos usar RegExp, en los "keywords" de inital.json, en lugar de un arreglo usamos un string (quitamos los []) @@ -70,38 +71,50 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - var {keywords} = stepsInitial.find(k => k.key.includes(key)) || { keywords: null } if(!Array.isArray(keywords)){key=null;}//Si "keywords" no es arreglo entonces ponemos "key" en null y usamos REGEXP para buscar reglas. if(key == null && message.length > 0){ - console.log("======= KEY ES NULO USAMOS REGEXP ======="); + var logRegEx = true + console.log("======= KEY ES NULO, USAMOS REGEXP ======="); for (i=0; i -1){ - console.log("**************** HAY URL ****************") + if(logRegEx) console.log("**************** HAY URL ****************") } break; } - else{x = null;} - } else - { console.log("NO CUMPLE PASO REQ"); - console.log("pasoReq=" + resps[stepsInitial[i].key.toString()].pasoRequerido + " - PasoAnt=" + ultimoStep) + else { + coincideKeyword = null + } + } + else { + if(logRegEx) console.log("--- NO CUMPLE PASO REQ"); + // console.log("pasoReq=" + resps[stepsInitial[i].key.toString()].pasoRequerido + " - PasoAnt=" + ultimoStep) } } } @@ -114,19 +127,19 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - // if(key != null){remplazos(resps[key].replyMessage.join(''));} if(resps[key]!=undefined){VA = resps[key].goto}else{VA=null} cumplePasoRequerido(key); - vamosA = VA; - // console.log(elNum) + _vamosA = VA; + console.log("cumplePasoPrevio[elNum]=", cumplePasoPrevio[elNum]) - if(vamosA != "" && vamosA != undefined && cumplePasoPrevio == true){ - // console.log("ASIGNAMOS VAMOSA = " + vamosA); - pasoAnterior[elNum] = vamosA; + if(_vamosA != "" && _vamosA != undefined && cumplePasoPrevio[elNum] == true){ + console.log("ASIGNAMOS _VAMOSA = " + _vamosA); + pasoAnterior[elNum] = _vamosA; } // console.log("ULTIMOSTEP="+ultimoStep) - vamosA = ""; + _vamosA = ""; // console.log("MESSAGE: "+message); // console.log("KEY: "+key); // console.log("RESPONSE: "+response); - if(cumplePasoPrevio) {resolve(response);} + if(cumplePasoPrevio[elNum]) {resolve(response);} } /** @@ -137,7 +150,6 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - resolve(dt) }); } - }) const reply = (step) => new Promise((resolve, reject) => { @@ -203,7 +215,18 @@ const saveMessage = ( message, trigger, number, regla ) => new Promise( async (r } }) -module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js" +module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial, vamosA } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js" + +/** + * Asigna el valor especificado a la variable pasoAnterior. + * Esta hace que el flujo se redirija al paso siguente al especificado. + * @param {elNum} El numero del remitente. + * @param {elPaso} El paso al que se va redirigir el flujo. + */ +function vamosA (elNum, elPaso){ + pasoAnterior[elNum] = elPaso; + console.log("Asignamos pasoAnterior con " + elPaso, elNum) +} /** * Reemplaza texto en la respuesta con variables predefinidas. @@ -276,7 +299,7 @@ function remplazos(elTexto, extraInfo){ } if(laLista[i].search('%msjant_')>-1){//Remplaza con el mensaje anterior especificado. var histlMsjs = {}; - console.log("entramos a msjant") + // console.log("entramos a msjant") // var hayHistorial = (chkFile(`${__dirname}/chats/`+from+".json")); if(chkFile(`${__dirname}/../chats/`+elNum+".json")){ let rawdata = fs.readFileSync(`./chats/${elNum}.json`); @@ -286,18 +309,18 @@ function remplazos(elTexto, extraInfo){ var inicio = laLista[i].search('%msjant_'); var final = laLista[i].indexOf("%", inicio+1); var subStr = laLista[i].substring(inicio, final+1); - console.log("Substr = |" + subStr + "|"); + // console.log("Substr = |" + subStr + "|"); var partes = subStr.toString().split('_'); if(partes.length > 1){ - console.log("Partes[1] = |" + partes[1] + "|"); + // console.log("Partes[1] = |" + partes[1] + "|"); let posicion0 = partes[1].substring(0, partes[1].length-1) - console.log("Posicion0 = |" + posicion0 + "|"); + // console.log("Posicion0 = |" + posicion0 + "|"); posicion = ((posicion0*1) + 1); - console.log("Posicion = " + posicion); - console.log( elHistorial.length ); - console.log((elHistorial.length*1)-posicion); - console.log("Mensaje="+elHistorial[elHistorial.length - posicion]["message"]) - elTexto = elTexto.toString().replace(subStr, elHistorial[elHistorial.length - posicion]["message"]); + // console.log("Posicion = " + posicion); + // console.log( elHistorial.length ); + // console.log((elHistorial.length*1)-posicion); + // console.log("Mensaje="+elHistorial[elHistorial.length - posicion]["message"]) + elTexto = elTexto.toString().replace(subStr, elHistorial[elHistorial.length - posicion]["message"].trim()); } // histlMsjs = elHistorial["messages"]; // totalMsjs = histlMsjs.length-1; @@ -341,7 +364,7 @@ function remplazos(elTexto, extraInfo){ } } // console.log("EL TEXTO="+elTexto); - return elTexto + return elTexto.trim() } /** @@ -352,15 +375,15 @@ function remplazos(elTexto, extraInfo){ if(resps[step]!=undefined){pasoRequerido=resps[step].pasoRequerido}else{pasoRequerido=null} if((pasoRequerido != null && pasoRequerido == ultimoStep)){ // console.log("REQUIERE PASO PREVIO Y CUMPLE"); - cumplePasoPrevio = true; + cumplePasoPrevio[elNum] = true; } else if((pasoRequerido != null && pasoRequerido != pasoAnterior[elNum])){ // console.log("REQUIERE PASO PREVIO Y NO LO CUMPLE"); - cumplePasoPrevio = false; + cumplePasoPrevio[elNum] = false; } else{ // console.log("NO REQUIERE PASO PREVIO") - cumplePasoPrevio = true; + cumplePasoPrevio[elNum] = true; } pasoAnterior[elNum] = step ultimoPaso = pasoRequerido; diff --git a/adapter/test.js b/adapter/test.js new file mode 100644 index 0000000..9e66faa --- /dev/null +++ b/adapter/test.js @@ -0,0 +1,394 @@ ++++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++ +HORA:4:55:56 PM FROM:5215519561677@c.us, BODY:/Guna, HASMEDIA:false +NUEVA RESPUESTA= Mensaje de getGunaCats +############# Encontramos Funcion, ejecutamos funcion getGunaCats +1 { id: 'CHOCOLATE', title: 'CHOCOLATE' } +2 { id: 'DULCES', title: 'DULCES' } +lasOpciones=[object Object] +List { + description: 'Buenas tardes, selecciona una categoría 👇🏽', + buttonText: 'Ver las categorías', + title: 'Categorías', + footer: 'Selecciona', + sections: [ { title: 'Categorías', rows: [Array] } ] +} + Client { + _events: [Object: null prototype] { + qr: [Function (anonymous)], + ready: [Function (anonymous)], + auth_failure: [Function (anonymous)], + authenticated: [Function (anonymous)], + message: [AsyncFunction (anonymous)], + message_create: [AsyncFunction (anonymous)] + }, + _eventsCount: 6, + _maxListeners: undefined, + options: { + authStrategy: LocalAuth { + dataPath: 'C:\\Users\\cheve\\Documents\\GitHub\\botDemoGuna\\.wwebjs_auth', + clientId: undefined, + client: [Circular *1], + userDataDir: 'C:\\Users\\cheve\\Documents\\GitHub\\botDemoGuna\\.wwebjs_auth\\session' + }, + puppeteer: { + headless: true, + args: [Array], + defaultViewport: null, + userDataDir: 'C:\\Users\\cheve\\Documents\\GitHub\\botDemoGuna\\.wwebjs_auth\\session' + }, + authTimeoutMs: 0, + qrMaxRetries: 0, + takeoverOnConflict: false, + takeoverTimeoutMs: 0, + userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36', + ffmpegPath: 'ffmpeg', + bypassCSP: false + }, + authStrategy: LocalAuth { + dataPath: 'C:\\Users\\cheve\\Documents\\GitHub\\botDemoGuna\\.wwebjs_auth', + clientId: undefined, + client: [Circular *1], + userDataDir: 'C:\\Users\\cheve\\Documents\\GitHub\\botDemoGuna\\.wwebjs_auth\\session' + }, + pupBrowser: Browser { + eventsMap: Map(2) { 'targetcreated' => [], 'targetchanged' => [] }, + emitter: { + all: [Map], + on: [Function: on], + off: [Function: off], + emit: [Function: emit] + }, + _ignoredTargets: Set(0) {}, + _ignoreHTTPSErrors: false, + _defaultViewport: null, + _process: ChildProcess { + _events: [Object: null prototype], + _eventsCount: 1, + _maxListeners: undefined, + _closesNeeded: 2, + _closesGot: 0, + connected: false, + signalCode: null, + exitCode: null, + killed: false, + spawnfile: 'C:\\Users\\cheve\\Documents\\GitHub\\botDemoGuna\\node_modules\\puppeteer\\.local-chromium\\win64-982053\\chrome-win\\chrome.exe', + _handle: [Process], + spawnargs: [Array], + pid: 7188, + stdin: [Socket], + stdout: null, + stderr: [Socket], + stdio: [Array], + [Symbol(kCapture)]: false + }, + _screenshotTaskQueue: TaskQueue { _chain: [Promise] }, + _connection: Connection { + eventsMap: [Map], + emitter: [Object], + _lastId: 372, + _sessions: [Map], + _closed: false, + _callbacks: Map(0) {}, + _url: 'ws://127.0.0.1:49386/devtools/browser/8ba98a74-7751-45aa-8256-8f82b8312e65', + _delay: 0, + _transport: [NodeWebSocketTransport] + }, + _closeCallback: [Function: bound close], + _targetFilterCallback: [Function (anonymous)], + _defaultContext: BrowserContext { + eventsMap: Map(0) {}, + emitter: [Object], + _connection: [Connection], + _browser: [Circular *2], + _id: undefined + }, + _contexts: Map(0) {}, + _targets: Map(5) { + '4904d96d-4dec-4069-95d8-fe7d70f62b06' => [Target], + '71cc8c5e-8516-49de-9387-b2940074aea5' => [Target], + 'C7071524BC87DF4C8E9569AD3FBB7348' => [Target], + '1D7791C3C62A14FB306A0ABD1CD86677' => [Target], + '969B67293789E4A52B827E4619DF58D7' => [Target] + } + }, + pupPage: Page { + eventsMap: Map(1) { 'framenavigated' => [Array] }, + emitter: { + all: [Map], + on: [Function: on], + off: [Function: off], + emit: [Function: emit] + }, + _closed: false, + _timeoutSettings: TimeoutSettings { + _defaultTimeout: null, + _defaultNavigationTimeout: null + }, + _pageBindings: Map(12) { + 'loadingScreen' => [AsyncFunction (anonymous)], + 'qrChanged' => [AsyncFunction (anonymous)], + 'onAddMessageEvent' => [Function (anonymous)], + 'onChangeMessageTypeEvent' => [Function (anonymous)], + 'onChangeMessageEvent' => [Function (anonymous)], + 'onRemoveMessageEvent' => [Function (anonymous)], + 'onMessageAckEvent' => [Function (anonymous)], + 'onMessageMediaUploadedEvent' => [Function (anonymous)], + 'onAppStateChangedEvent' => [AsyncFunction (anonymous)], + 'onBatteryStateChangedEvent' => [Function (anonymous)], + 'onIncomingCall' => [Function (anonymous)], + 'onReaction' => [Function (anonymous)] + }, + _javascriptEnabled: true, + _workers: Map(1) { '96E97F3B444D00EB81EFEFDBC3128749' => [WebWorker] }, + _fileChooserInterceptors: Set(0) {}, + _userDragInterceptionEnabled: false, + _handlerMap: WeakMap { }, + _client: CDPSession { + eventsMap: [Map], + emitter: [Object], + _callbacks: Map(0) {}, + _connection: [Connection], + _targetType: 'page', + _sessionId: '44F15C73737F3B036CBCBE340984F10E' + }, + _target: Target { + _targetInfo: [Object], + _browserContext: [BrowserContext], + _targetId: 'C7071524BC87DF4C8E9569AD3FBB7348', + _sessionFactory: [Function (anonymous)], + _ignoreHTTPSErrors: false, + _defaultViewport: null, + _screenshotTaskQueue: [TaskQueue], + _pagePromise: [Promise], + _workerPromise: null, + _initializedCallback: [Function (anonymous)], + _initializedPromise: [Promise], + _closedCallback: [Function (anonymous)], + _isClosedPromise: [Promise], + _isInitialized: true + }, + _keyboard: Keyboard { + _modifiers: 0, + _pressedKeys: Set(0) {}, + _client: [CDPSession] + }, + _mouse: Mouse { + _x: 0, + _y: 0, + _button: 'none', + _client: [CDPSession], + _keyboard: [Keyboard] + }, + _touchscreen: Touchscreen { _client: [CDPSession], _keyboard: [Keyboard] }, + _accessibility: Accessibility { _client: [CDPSession] }, + _frameManager: FrameManager { + eventsMap: [Map], + emitter: [Object], + _frames: [Map], + _contextIdToContext: [Map], + _isolatedWorlds: [Set], + _client: [CDPSession], + _page: [Circular *3], + _networkManager: [NetworkManager], + _timeoutSettings: [TimeoutSettings], + _mainFrame: [Frame] + }, + _emulationManager: EmulationManager { + _emulatingMobile: false, + _hasTouch: false, + _client: [CDPSession] + }, + _tracing: Tracing { _recording: false, _path: '', _client: [CDPSession] }, + _coverage: Coverage { _jsCoverage: [JSCoverage], _cssCoverage: [CSSCoverage] }, + _screenshotTaskQueue: TaskQueue { _chain: [Promise] }, + _viewport: null + }, + info: ClientInfo { + pushname: 'Omega', + wid: { + server: 'c.us', + user: '5215527026728', + _serialized: '5215527026728@c.us' + }, + me: { + server: 'c.us', + user: '5215527026728', + _serialized: '5215527026728@c.us' + }, + phone: undefined, + platform: 'android' + }, + interface: InterfaceController { + pupPage: Page { + eventsMap: [Map], + emitter: [Object], + _closed: false, + _timeoutSettings: [TimeoutSettings], + _pageBindings: [Map], + _javascriptEnabled: true, + _workers: [Map], + _fileChooserInterceptors: Set(0) {}, + _userDragInterceptionEnabled: false, + _handlerMap: [WeakMap], + _client: [CDPSession], + _target: [Target], + _keyboard: [Keyboard], + _mouse: [Mouse], + _touchscreen: [Touchscreen], + _accessibility: [Accessibility], + _frameManager: [FrameManager], + _emulationManager: [EmulationManager], + _tracing: [Tracing], + _coverage: [Coverage], + _screenshotTaskQueue: [TaskQueue], + _viewport: null + } + }, + theMsg: Message { + _data: { + id: [Object], + body: '/Guna', + type: 'chat', + t: 1675378555, + notifyName: 'Alfredo', + from: '5215519561677@c.us', + to: '5215527026728@c.us', + self: 'in', + ack: 1, + isNewMsg: true, + star: false, + kicNotified: false, + recvFresh: true, + isFromTemplate: false, + pollInvalidated: false, + isSentCagPollCreation: false, + latestEditMsgKey: null, + latestEditSenderTimestampMs: null, + broadcast: false, + mentionedJidList: [], + isVcardOverMmsDocument: false, + isForwarded: false, + hasReaction: false, + productHeaderImageRejected: false, + lastPlaybackProgress: 0, + isDynamicReplyButtonsMsg: false, + isMdHistoryMsg: false, + stickerSentTs: 0, + isAvatar: false, + requiresDirectConnection: false, + pttForwardedFeaturesEnabled: true, + isEphemeral: false, + isStatusV3: false, + links: [] + }, + mediaKey: undefined, + id: { + fromMe: false, + remote: '5215519561677@c.us', + id: '3A98BA96F6922B404213', + _serialized: 'false_5215519561677@c.us_3A98BA96F6922B404213' + }, + ack: 1, + hasMedia: false, + body: '/Guna', + type: 'chat', + timestamp: 1675378555, + from: '5215519561677@c.us', + to: '5215527026728@c.us', + author: undefined, + deviceType: 'ios', + isForwarded: false, + forwardingScore: 0, + isStatus: false, + isStarred: false, + broadcast: false, + fromMe: false, + hasQuotedMsg: false, + duration: undefined, + location: undefined, + vCards: [], + inviteV4: undefined, + mentionedIds: [], + orderId: undefined, + token: undefined, + isGif: false, + isEphemeral: false, + links: [], + numero: '5215519561677@c.us', + key: 'gunaCats', + lastStep: null, + step: 'gunaCats', + trigger: null, + replyMessage: 'Mensaje de getGunaCats' + }, + [Symbol(kCapture)]: false +} ++++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++ +HORA:4:56:00 PM FROM:5215519561677@c.us, BODY:DULCES, HASMEDIA:false +======= KEY ES NULO USAMOS REGEXP ======= +KEY=|doblemensaje| +Esta Key=doblemensaje - pasoReq=menu - PasoAnt=undefined|gunaCats +NO CUMPLE PASO REQ +pasoReq=menu - PasoAnt=undefined +KEY=|recibenombre| +Esta Key=recibenombre - pasoReq=opcion3 - PasoAnt=undefined|gunaCats +NO CUMPLE PASO REQ +pasoReq=opcion3 - PasoAnt=undefined +KEY=|gRevisaCliente| +Esta Key=gRevisaCliente - pasoReq=gallina - PasoAnt=undefined|gunaCats +NO CUMPLE PASO REQ +pasoReq=gallina - PasoAnt=undefined +KEY=|gGuardainfo| +Esta Key=gGuardainfo - pasoReq=gRevisaCliente - PasoAnt=undefined|gunaCats +NO CUMPLE PASO REQ +pasoReq=gRevisaCliente - PasoAnt=undefined +KEY=|paq3| +Esta Key=paq3 - pasoReq=menu - PasoAnt=undefined|gunaCats +NO CUMPLE PASO REQ +pasoReq=menu - PasoAnt=undefined +KEY=|Desbloqueo| +Esta Key=Desbloqueo - pasoReq=soporte - PasoAnt=undefined|gunaCats +NO CUMPLE PASO REQ +pasoReq=soporte - PasoAnt=undefined +KEY=|gunaCats2| +Esta Key=gunaCats2 - pasoReq=gunaCats - PasoAnt=undefined|gunaCats +NUEVA RESPUESTA= Mensaje de getGunaCats2 +############# Encontramos Funcion, ejecutamos funcion getGunaSubtipo +1 { id: 'KINDER', title: 'KINDER' } +2 { id: 'CHOCOLATE', title: 'CHOCOLATE' } +lasOpciones=undefined ++++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++ +HORA:4:56:05 PM FROM:5215519561677@c.us, BODY:CHOCOLATE, HASMEDIA:false +======= KEY ES NULO USAMOS REGEXP ======= +KEY=|doblemensaje| +Esta Key=doblemensaje - pasoReq=menu - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=menu - PasoAnt=undefined +KEY=|recibenombre| +Esta Key=recibenombre - pasoReq=opcion3 - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=opcion3 - PasoAnt=undefined +KEY=|gRevisaCliente| +Esta Key=gRevisaCliente - pasoReq=gallina - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=gallina - PasoAnt=undefined +KEY=|gGuardainfo| +Esta Key=gGuardainfo - pasoReq=gRevisaCliente - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=gRevisaCliente - PasoAnt=undefined +KEY=|paq3| +Esta Key=paq3 - pasoReq=menu - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=menu - PasoAnt=undefined +KEY=|Desbloqueo| +Esta Key=Desbloqueo - pasoReq=soporte - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=soporte - PasoAnt=undefined +KEY=|gunaCats2| +Esta Key=gunaCats2 - pasoReq=gunaCats - PasoAnt=undefined|gunaCats2 +NO CUMPLE PASO REQ +pasoReq=gunaCats - PasoAnt=undefined +KEY=|gunaProds| +Esta Key=gunaProds - pasoReq=gunaCats2 - PasoAnt=undefined|gunaCats2 +NUEVA RESPUESTA= Mensaje de getGunaCats2 +############# Encontramos Funcion, ejecutamos funcion getGunaProds diff --git a/app.js b/app.js index d496246..b044a26 100644 --- a/app.js +++ b/app.js @@ -5,6 +5,7 @@ require('dotenv').config() const fs = require('fs'); const express = require('express'); global.siguientePaso = [{"numero":"1", "va":"XXX"}]; //MOD by CHV - Agregamos para pasar el VAMOSA a "index.js" +global.pasoAnterior = []; const cors = require('cors') const axios = require('axios').default;//MOD by CHV - Agregamos para el get del "/URL" const qrcode = require('qrcode-terminal'); @@ -16,12 +17,14 @@ const { connectionReady, connectionLost } = require('./controllers/connection') const { saveMedia, saveMediaToGoogleDrive } = require('./controllers/save') const { getMessages, responseMessages, bothResponse, waitFor } = require('./controllers/flows') const { sendMedia, sendMessage, lastTrigger, sendMessageButton, sendMessageList, readChat } = require('./controllers/send'); -const { remplazos, stepsInitial} = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial +const { remplazos, stepsInitial, vamosA } = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial const { isUndefined } = require('util'); const { isSet } = require('util/types'); const { Console } = require('console'); const { ClientRequest } = require('http'); const { guardaXLSDatos, leeXLSDatos} = require('./Excel'); +const { ContextsClient } = require('@google-cloud/dialogflow'); +const { ingresarDatos, leerDatos } = require('./implementaciones/sheets') const app = express(); app.use(cors()) app.use(express.json()) @@ -32,9 +35,10 @@ const port = process.env.PORT || 3000 var client; var dialogflowFilter = false; var totalMsjs; //MOD by CHV - -var vamosA = ""; //MOD by CHV - +// var vamosA = ""; //MOD by CHV - var newBody; //MOD by CHV - var nuevaRespuesta; //MOD by CHV - Se agrego para los remplazos +var vars = [] app.use('/', require('./routes/web')) /** @@ -42,14 +46,16 @@ app.use('/', require('./routes/web')) */ const listenMessage = () => client.on('message', async msg => { const { from, body, hasMedia } = msg; + if (vars[from] === undefined) vars[from] = [] // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); console.log("+++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++"); // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); client.theMsg = msg; - console.log("HORA:"+new Date().toLocaleTimeString()+" FROM:"+from+", BODY:"+body+", HASMEDIA:"+hasMedia); + // console.log("%%%%%%%%% userAgent = " + client?.options?.userAgent) + console.log("HORA:"+new Date().toLocaleTimeString()+" FROM:"+from+", BODY:"+body+", HASMEDIA:"+hasMedia+", DEVICETYPE:"+client.theMsg?.deviceType); newBody = removeDiacritics(body) //MOD by CHV - Agregamos para quitar acentos // newBody = remplazos(newBody); - vamosA = ""; + // vamosA = ""; if(!isValidNumber(from)){ return } @@ -59,9 +65,16 @@ const listenMessage = () => client.on('message', async msg => { } message = newBody.toLowerCase(); const number = cleanNumber(from) + client.theMsg['numero'] = number + // Guardamos el mensaje en Google Sheets + ingresarDatos(from, body) + + +// console.log(stepsInitial) var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null }//MOD by CHV - Se agrega para obtener KEY await readChat(number, message, null , key) //MOD by CHV - Agregamos key/regla para guardarla en "chats/numero.json" + client.theMsg['key'] = key /** * Guardamos el archivo multimedia que envia @@ -74,7 +87,7 @@ const listenMessage = () => client.on('message', async msg => { /** * Si estas usando dialogflow solo manejamos una funcion todo es IA */ - + if (process.env.DATABASE === 'dialogflow') { if (process.env.DIALOGFLOW_MEDIA_FOR_SLOT_FILLING === 'true' && dialogflowFilter) { waitFor(_ => hasMedia, 30000) @@ -102,8 +115,6 @@ const listenMessage = () => client.on('message', async msg => { return } - - if(body=='/listas'){ const productList = new List( "Here's our list of products at 50% off", @@ -133,13 +144,13 @@ const listenMessage = () => client.on('message', async msg => { // await sendMessageList(client, '5215527049036@c.us', null, lista); // await sendMessageList(client, '5215554192439@c.us', null, lista); // client.sendMessage(from, lista); - } + } - /** - * PRUEBA BOTONES NUEVOS - */ - // if(body=="579"){ - // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button + /** + * PRUEBA BOTONES NUEVOS + */ + // if(body=="579"){ + // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button // for (const component of [buttons_reply]) await client.sendMessage(from, component); // } @@ -149,16 +160,18 @@ const listenMessage = () => client.on('message', async msg => { * a tu gusto! */ - const lastStep = await lastTrigger(from) || null; - // console.log("LAST STEP="+lastStep+", FROM:"+from); - if (lastStep) { - const response = await responseMessages(lastStep) - console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); - // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. - response.replyMessage.forEach( async messages => { - var thisMsg = messages.mensaje - if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} - await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); + const lastStep = await lastTrigger(from) || null; + client.theMsg['lastStep'] = lastStep + // console.log("LAST STEP="+lastStep+", FROM:"+from); + if (lastStep) { + const response = await responseMessages(lastStep) + client.theMsg['trigger'] = response.trigger + console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); + // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. + response.replyMessage.forEach( async messages => { + var thisMsg = messages.mensaje + if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} + await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); }) } @@ -170,17 +183,15 @@ const listenMessage = () => client.on('message', async msg => { // console.log("****** STEP="+step); // console.log("****** MESSAGE:"+message); const step = await getMessages(message, from); + client.theMsg['step'] = step if (step) { const response = await responseMessages(step); - + client.theMsg['trigger'] = response.trigger var resps = require('./flow/response.json'); nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); + client.theMsg['replyMessage'] = nuevaRespuesta var pasoRequerido = resps[step].pasoRequerido; - // var hayRequest = false; - // if(hayRequest==false && nuevaRespuesta.search("/URL")>-1){console.log("Paramos flujo para que no mande el mensaje '/URL'."); return;}//Si el trigger es desbloqueo ya no hace nada mas. - - // nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); - console.log('NUEVA RESPUESTA=', nuevaRespuesta) + // console.log('NUEVA RESPUESTA=', nuevaRespuesta) if(nuevaRespuesta.search("/URL")>-1){ // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. @@ -213,63 +224,201 @@ const listenMessage = () => client.on('message', async msg => { } } /** - * Llama el API para tre categoria de Guna. + * Llama el API para traer categorias de Guna. * @param {*} ctx El objeto del mensaje. */ async function getGunaCats(ctx) { - // let par1 = ctx.theMsg.body - // let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectTipoFerreroMty","exec":"ExecuteQuery","params":{"par1":"${par1}"}}` - // const RES = await axios.get(theUrl).then(function (response) { - // console.log('getGunaCats = ', response.data.respuesta.length, response.data.respuesta) - // let elMensaje = "%saludo%,\nEscoge una de nuestras categorías:\n\n" - // let lasOpciones = "[" - // for(reg=0;reg { + elMensaje = elMensaje + `${vars[from]['prods'][prod].cant} - ${prod[0].toUpperCase() + prod.substring(1)}\n` + console.log(`${prod}: ${vars[from]['prods'][prod]}`); + }); + elMensaje = elMensaje + "\n¿Quieres agregar mas productos a tu orden?" + // for(pr=0;pr client.on('message', async msg => { * Si quieres ejecutar una función. */ if(response.hasOwnProperty('funcion')){ - console.log("############# Encontramos Funcion, ejecutamos funcion " + response.funcion) + console.log("############# Encontramos función, ejecutamos la función '" + response.funcion + "'") laFuncion = response.funcion + "(client)" eval(laFuncion) return } - if(response.hasOwnProperty('urlXXXXXXX') && response.hasOwnProperty('values')){ let theURL = response.url; let url0 = theURL @@ -322,7 +470,6 @@ const listenMessage = () => client.on('message', async msg => { desbloqueaUsuario2(url2, step) //Llamamos al API para desbloquear el usuario. return } - /** * Si quieres enviar imagen. */ @@ -373,45 +520,44 @@ const listenMessage = () => client.on('message', async msg => { if(actions['sections'] === undefined){ //Botones console.log("Botones") await sendMessageButton(client, from, null, actions); + } + else { //Listas + console.log("Listas") + // console.log(actions) + await sendMessageList(client, from, null, actions); + } } - else{ //Listas - console.log("Listas") - // console.log(actions) - await sendMessageList(client, from, null, actions); - } + return } - return -} -if(body=='trae'){ - const rows = await leeXLSDatos('x') - console.log("RESULTADOS:") - // d.forEach(row => async function() { - // console.log(row.nombre, row.edad, row.sexo) - // client.sendMessage(from, `Hola ${row.nombre}, recuerda que tienes un adeudo pendiente`) - // }) - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - async function retardo() { - for (sp=1;sp async function() { + // console.log(row.nombre, row.edad, row.sexo) + // client.sendMessage(from, `Hola ${row.nombre}, recuerda que tienes un adeudo pendiente`) + // }) + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); } - console.log('Terminamos'); + async function retardo() { + for (sp=1;sp=12.0.0" } }, + "node_modules/google-spreadsheet": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/google-spreadsheet/-/google-spreadsheet-3.3.0.tgz", + "integrity": "sha512-ahmRNh14s1i3phfvbF2mxen1lohWJpUaFWgsU6P6bXu7QrmxMaim1Ys/7BU4W5yucWCzphoIrHMbrbeIR5K9mw==", + "dependencies": { + "axios": "^0.21.4", + "google-auth-library": "^6.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/google-spreadsheet/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/google-spreadsheet/node_modules/gaxios": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", + "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/google-auth-library": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz", + "integrity": "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ==", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/google-p12-pem": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz", + "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==", + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/googleapis": { "version": "109.0.1", "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-109.0.1.tgz", @@ -5069,6 +5165,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/util-tiempo": { + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/util-tiempo/-/util-tiempo-1.0.41.tgz", + "integrity": "sha512-HEesdZQpLY3S51xZ6hGbDvH8dVge+k+RnKJrb1mcME5UYXFeOaB7KQHA+sBiLsjls2Z0arseuxO2CZe9ZMCdug==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index 9ec99bc..c77715a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "exceljs": "^4.3.0", "express": "^4.18.1", "file-type": "^17.1.6", + "google-spreadsheet": "^3.3.0", "googleapis": "^109.0.1", "mime-db": "^1.52.0", "moment": "^2.29.4", @@ -27,6 +28,7 @@ "qrcode-terminal": "^0.12.0", "socket.io": "^4.5.1", "stormdb": "^0.6.0", + "util-tiempo": "^1.0.41", "whatsapp-web.js": "github:cheveguerra/whatsapp-web.js#WaWJS2", "xlsx": "^0.18.5" }, From 9054f66ec35be4d4cbfc01fb5fb6337ab62104d4 Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Sun, 5 Feb 2023 07:00:42 -0600 Subject: [PATCH 06/19] feat: blacklist --- .vscode/launch.json | 7 ++ adapter/index.js | 13 ++-- app.js | 173 +++++++++++++++++++++++++++----------------- flow/response.json | 14 +++- 4 files changed, 134 insertions(+), 73 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5c7247b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/adapter/index.js b/adapter/index.js index 0f0be4b..11c6a50 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -49,9 +49,10 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - */ if (process.env.DATABASE === 'none') { - + // console.log(message) var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null } - console.log("KEY="+key) + // console.log(stepsInitial) + // console.log("KEY="+key) /* ############################################### * REGEXP * #################################################### Si queremos usar RegExp, en los "keywords" de inital.json, en lugar de un arreglo usamos un string (quitamos los []) @@ -71,7 +72,7 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - var {keywords} = stepsInitial.find(k => k.key.includes(key)) || { keywords: null } if(!Array.isArray(keywords)){key=null;}//Si "keywords" no es arreglo entonces ponemos "key" en null y usamos REGEXP para buscar reglas. if(key == null && message.length > 0){ - var logRegEx = true + var logRegEx = false console.log("======= KEY ES NULO, USAMOS REGEXP ======="); for (i=0; i x.message != "") //Quitamos mensajes en blanco. var inicio = laLista[i].search('%msjant_'); var final = laLista[i].indexOf("%", inicio+1); var subStr = laLista[i].substring(inicio, final+1); diff --git a/app.js b/app.js index b044a26..c32a4b5 100644 --- a/app.js +++ b/app.js @@ -31,7 +31,7 @@ app.use(express.json()) const MULTI_DEVICE = process.env.MULTI_DEVICE || 'true'; const server = require('http').Server(app) const port = process.env.PORT || 3000 - +const delay = (ms) => new Promise((resolve) => setTimeout(resolve,ms)) var client; var dialogflowFilter = false; var totalMsjs; //MOD by CHV - @@ -44,7 +44,7 @@ app.use('/', require('./routes/web')) /** * Escuchamos cuando entre un mensaje */ -const listenMessage = () => client.on('message', async msg => { +listenMessage = () => client.on('message', async msg => { const { from, body, hasMedia } = msg; if (vars[from] === undefined) vars[from] = [] // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); @@ -63,6 +63,9 @@ const listenMessage = () => client.on('message', async msg => { if (from === 'status@broadcast') { return } + let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','34630283553','34648827637','34630255646','14178973313'] + console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) + if (blackList.includes(from.replace("@c.us",""))) return message = newBody.toLowerCase(); const number = cleanNumber(from) client.theMsg['numero'] = number @@ -223,13 +226,13 @@ const listenMessage = () => client.on('message', async msg => { // console.log('RES=', RES) } } + /** * Llama el API para traer categorias de Guna. * @param {*} ctx El objeto del mensaje. */ async function getGunaCats(ctx) { - let par1 = ctx.theMsg.body - let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectTipoFerreroMty","exec":"ExecuteQuery","params":{"par1":"${par1}"}}` + let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectTipoFerreroMty","exec":"ExecuteQuery","params":{"par1":"xxx"}}` const RES = await axios.get(theUrl).then(function (response) { let lasOpciones = [] for(reg=0;reg client.on('message', async msg => { return error }); } + /** * Llama el API para traer productos de Guna. * @param {*} ctx El objeto del mensaje. */ async function getGunaProds(ctx) { if(vars[from]['recompra'] === undefined) vars[from]['subtipo'] = ctx.theMsg.body + console.log(vars[from]['tipo'], vars[from]['subtipo']) let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectProdsFerreroMty","exec":"ExecuteQuery","params":{"par1":"${vars[from]['tipo']}", "par2":"${vars[from]['subtipo']}"}}` const RES = await axios.get(theUrl).then(function (response) { let elMensaje = "Gracias,\nAhora un producto:\n\n" @@ -327,7 +332,7 @@ const listenMessage = () => client.on('message', async msg => { rows: lasOpciones, } ], - `SUBCATEGORÍA ${body}`, + `SUBCATEGORÍA ${vars[from]['subtipo']}`, "Footer" ) client.sendMessage(from, productList) @@ -337,6 +342,7 @@ const listenMessage = () => client.on('message', async msg => { return error }); } + /** * Llama el API para traer productos de Guna. * @param {*} ctx El objeto del mensaje. @@ -345,20 +351,34 @@ const listenMessage = () => client.on('message', async msg => { // vars[from]['subtipo'] = ctx.theMsg.body if(vars[from]['prods'] === undefined) { vars[from]['prods'] = [] } let elProd = ctx.theMsg.body - elProd = elProd.substring(0, elProd.indexOf(' $')).trim().toLowerCase() - var precio = ctx.theMsg.body.substring(ctx.theMsg.body.indexOf(' $')+2) - console.log("precio",precio) - precio = precio.substring(0, precio.indexOf(',')) - console.log("precio",precio) - vars[from]['prods'][elProd] = {"cant":0, "precio":precio} - console.log("EL_PROD=", elProd) - console.log(vars[from]['prods'][elProd]) - let elMensaje = ctx.theMsg.replyMessage - let re = ctx.theMsg.body.trim().toLowerCase() - elMensaje = elMensaje.replace(re, elProd.toLowerCase()) + let elMensaje = "" + if(elProd.indexOf(' $') > -1){ // Producto con formato correcto. + vars[from]['ultimoProd'] = elProd + elProd = elProd.substring(0, elProd.indexOf(' $')).trim().toLowerCase() + var precio = ctx.theMsg.body.substring(ctx.theMsg.body.indexOf(' $')+2) + console.log("precio",precio) + precio = precio.substring(0, precio.indexOf(',')) + console.log("precio",precio) + vars[from]['prods'][elProd] = {"cant":0, "precio":precio} + console.log("EL_PROD=", elProd) + console.log(vars[from]['prods']) + elMensaje = ctx.theMsg.replyMessage + let re = ctx.theMsg.body.trim().toLowerCase() + elMensaje = elMensaje.replace(re, elProd.toLowerCase()) + } + else{ // Producto SIN precio. + elMensaje = "El producto que seleccionaste es *incorrecto*, por favor intenta de nuevo." + sendMessage(client, from, elMensaje, ctx.theMsg.trigger, ctx.theMsg.step); + await delay(500) + vars[from]['recompra'] = true + getGunaProds() + vamosA(from, "gunaProds") + return + } sendMessage(client, from, elMensaje, ctx.theMsg.trigger, ctx.theMsg.step); return } + /** * Tomamos la cantidad del producto seleccionado. * @param {*} ctx El objeto del mensaje. @@ -366,33 +386,39 @@ const listenMessage = () => client.on('message', async msg => { async function prodCantidad(ctx) { // console.log("Entramos a prodCantidad") let laCant = ctx.theMsg.body.trim() - const reg = new RegExp('^[0-9]+$') - let elProd = remplazos("%msjant_2%").toLowerCase() + const reg = new RegExp(/^\d+$/) + let elProd = vars[from]['ultimoProd'].toLowerCase() elProd = elProd.substring(0, elProd.indexOf(' $')).trim() + console.log("SOLO NUMS |" + laCant + "|", reg.test(laCant)) if(reg.test(laCant)){ + console.log(vars) console.log("Recibimos cant = " + laCant) console.log("EL_PROD=", vars[from]['prods'][elProd]) console.log("precio=", vars[from]['prods'][elProd].precio) - console.log("precio=", vars[from]['prods'][elProd]['precio']) vars[from]['prods'][elProd] = {"cant":laCant, "precio":vars[from]['prods'][elProd]['precio']} - console.log(vars[from]['prods']) - var elMensaje = "" - const prods = Object.keys(vars[from]['prods']); - prods.forEach((prod, index) => { - elMensaje = elMensaje + `${vars[from]['prods'][prod].cant} - ${prod[0].toUpperCase() + prod.substring(1)}\n` - console.log(`${prod}: ${vars[from]['prods'][prod]}`); - }); - elMensaje = elMensaje + "\n¿Quieres agregar mas productos a tu orden?" - // for(pr=0;pr { + if( vars[from]['prods'][prod] !== undefined && prod[0] !== undefined ){ + elMensaje = elMensaje + `${vars[from]['prods'][prod].cant} - ${prod[0].toUpperCase() + prod.substring(1)}\n` + console.log("cant y precio=", vars[from]['prods'][prod].cant, vars[from]['prods'][prod].precio) + if(reg.test(vars[from]['prods'][prod].cant) && vars[from]['prods'][prod].precio != ""){ + total = total + (vars[from]['prods'][prod].cant * vars[from]['prods'][prod].precio) + } + } + console.log(prod, vars[from]['prods'][prod]); + }); + let pesos = Intl.NumberFormat('en-US') + elMensaje = elMensaje + "\n*Total*: $" + pesos.format(total) + elMensaje = elMensaje + "\n¿Quieres agregar mas productos a tu orden?" var bts = { "title":"Tu orden", "message":elMensaje, "buttons":[ - {"body":"Terminar"}, - {"body":"Agregar productos"} + {"body":"➕ Agregar productos"}, + {"body":"⬅️ Cambiar categoría"}, + {"body":"✖️ Terminar"} ] } sendMessageButton(client, from, "xxx", bts) @@ -412,11 +438,22 @@ const listenMessage = () => client.on('message', async msg => { async function comprarMas(ctx) { console.log("Entramos a comprarMas") vars[from]['recompra'] = true + vamosA(from, "gunaProds") await getGunaProds(ctx) vars[from]['recompra'] = false return "1" } - + + /** + * Mandamos nuevamente la lista de categorías. + * @param {*} ctx El objeto del mensaje. + */ + async function terminaCompra(ctx) { + console.log("Entramos a terminaCompra") + vars[from] = [] + sendMessage(client, from, "!Gracias por tu compra, regresa pronto!", response.trigger, step); + return + } /** @@ -448,7 +485,7 @@ const listenMessage = () => client.on('message', async msg => { console.log("############# Encontramos función, ejecutamos la función '" + response.funcion + "'") laFuncion = response.funcion + "(client)" eval(laFuncion) - return + // return } if(response.hasOwnProperty('urlXXXXXXX') && response.hasOwnProperty('values')){ let theURL = response.url; @@ -568,35 +605,35 @@ if(message=='/spam'){ const masivo = require('./spam.json') var saludo; var caritas; - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + async function retardo() { + for (sp=0;sp k.messages.message != "") + // console.log(hayHistorialNoBlanks) + // var {keywords} = stepsInitial.find(k => k.key.includes(key)) if(hayHistorial){ let rawdata = fs.readFileSync(`./chats/${from}.json`); let elHistorial = JSON.parse(rawdata); @@ -755,6 +794,10 @@ function traeMensajes(from){ //MOD by CHV - Agregamos para traer el historial de // console.log("Mensajes:"+totalMsjs+", Ultimo:"+JSON.stringify(ultimoMensaje)); // console.log("Anterior:"+JSON.stringify(mensajeAnterior)); } + console.log(histlMsjs) + // var histlMsjsNoBlanks = histlMsjs.find(k => k.message != "") + var histlMsjsNoBlanks = histlMsjs.filter(x => x.message != "") + console.log(histlMsjsNoBlanks) return histlMsjs; } diff --git a/flow/response.json b/flow/response.json index 6fb8226..eff337f 100644 --- a/flow/response.json +++ b/flow/response.json @@ -351,7 +351,7 @@ "pasoRequerido":"soporte" }, "gunaCats":{ - "keywords": ["/guna", "/demoventa", "/demoguna"], + "keywords": ["/guna", "/demoventa", "/demoguna", "⬅️ cambiar categoria"], "replyMessage":[ "Mensaje de getGunaCats" ], @@ -400,7 +400,7 @@ "pasoRequerido":"gunaProdsAgrega" }, "gunaComprarMas":{ - "keywords": ["Agregar productos"], + "keywords": "*agregar productos", "replyMessage":[ "Quiero comprar mas." ], @@ -408,5 +408,15 @@ "media":null, "trigger":null, "pasoRequerido":"gunaProdsCantidad" + }, + "gunaTerminaCompra":{ + "keywords": "*terminar", + "replyMessage":[ + "Termina la compra" + ], + "funcion":"terminaCompra", + "media":null, + "trigger":null, + "pasoRequerido":"gunaProdsCantidad" } } \ No newline at end of file From e779d2455310e66ffabebd57b61a15ad47bf8a72 Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Sun, 5 Feb 2023 07:19:42 -0600 Subject: [PATCH 07/19] feat: blacklist --- app.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app.js b/app.js index c32a4b5..a6863ff 100644 --- a/app.js +++ b/app.js @@ -40,10 +40,11 @@ var newBody; //MOD by CHV - var nuevaRespuesta; //MOD by CHV - Se agrego para los remplazos var vars = [] app.use('/', require('./routes/web')) - - /** - * Escuchamos cuando entre un mensaje - */ +let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','34630283553','34648827637','34630255646','14178973313'] + +/** + * Escuchamos cuando entre un mensaje +*/ listenMessage = () => client.on('message', async msg => { const { from, body, hasMedia } = msg; if (vars[from] === undefined) vars[from] = [] @@ -63,7 +64,10 @@ listenMessage = () => client.on('message', async msg => { if (from === 'status@broadcast') { return } - let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','34630283553','34648827637','34630255646','14178973313'] + + /** + * Blacklist, los telefonos inlcuidos en este arreglo son ignorados por el bot. + */ console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) if (blackList.includes(from.replace("@c.us",""))) return message = newBody.toLowerCase(); From 9d293d3d6da741a07fd5c6e431e5a9292fad0785 Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Sun, 5 Feb 2023 07:40:41 -0600 Subject: [PATCH 08/19] =?UTF-8?q?peque=C3=B1os=20camios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adapter/index.js | 13 ++-- app.js | 185 ++++++++++++++++++++++++++++----------------- flow/response.json | 14 +++- 3 files changed, 135 insertions(+), 77 deletions(-) diff --git a/adapter/index.js b/adapter/index.js index 0f0be4b..11c6a50 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -49,9 +49,10 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - */ if (process.env.DATABASE === 'none') { - + // console.log(message) var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null } - console.log("KEY="+key) + // console.log(stepsInitial) + // console.log("KEY="+key) /* ############################################### * REGEXP * #################################################### Si queremos usar RegExp, en los "keywords" de inital.json, en lugar de un arreglo usamos un string (quitamos los []) @@ -71,7 +72,7 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - var {keywords} = stepsInitial.find(k => k.key.includes(key)) || { keywords: null } if(!Array.isArray(keywords)){key=null;}//Si "keywords" no es arreglo entonces ponemos "key" en null y usamos REGEXP para buscar reglas. if(key == null && message.length > 0){ - var logRegEx = true + var logRegEx = false console.log("======= KEY ES NULO, USAMOS REGEXP ======="); for (i=0; i x.message != "") //Quitamos mensajes en blanco. var inicio = laLista[i].search('%msjant_'); var final = laLista[i].indexOf("%", inicio+1); var subStr = laLista[i].substring(inicio, final+1); diff --git a/app.js b/app.js index b044a26..a6863ff 100644 --- a/app.js +++ b/app.js @@ -31,7 +31,7 @@ app.use(express.json()) const MULTI_DEVICE = process.env.MULTI_DEVICE || 'true'; const server = require('http').Server(app) const port = process.env.PORT || 3000 - +const delay = (ms) => new Promise((resolve) => setTimeout(resolve,ms)) var client; var dialogflowFilter = false; var totalMsjs; //MOD by CHV - @@ -40,11 +40,12 @@ var newBody; //MOD by CHV - var nuevaRespuesta; //MOD by CHV - Se agrego para los remplazos var vars = [] app.use('/', require('./routes/web')) - - /** - * Escuchamos cuando entre un mensaje - */ -const listenMessage = () => client.on('message', async msg => { +let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','34630283553','34648827637','34630255646','14178973313'] + +/** + * Escuchamos cuando entre un mensaje +*/ +listenMessage = () => client.on('message', async msg => { const { from, body, hasMedia } = msg; if (vars[from] === undefined) vars[from] = [] // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); @@ -63,6 +64,12 @@ const listenMessage = () => client.on('message', async msg => { if (from === 'status@broadcast') { return } + + /** + * Blacklist, los telefonos inlcuidos en este arreglo son ignorados por el bot. + */ + console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) + if (blackList.includes(from.replace("@c.us",""))) return message = newBody.toLowerCase(); const number = cleanNumber(from) client.theMsg['numero'] = number @@ -223,13 +230,13 @@ const listenMessage = () => client.on('message', async msg => { // console.log('RES=', RES) } } + /** * Llama el API para traer categorias de Guna. * @param {*} ctx El objeto del mensaje. */ async function getGunaCats(ctx) { - let par1 = ctx.theMsg.body - let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectTipoFerreroMty","exec":"ExecuteQuery","params":{"par1":"${par1}"}}` + let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectTipoFerreroMty","exec":"ExecuteQuery","params":{"par1":"xxx"}}` const RES = await axios.get(theUrl).then(function (response) { let lasOpciones = [] for(reg=0;reg client.on('message', async msg => { return error }); } + /** * Llama el API para traer productos de Guna. * @param {*} ctx El objeto del mensaje. */ async function getGunaProds(ctx) { if(vars[from]['recompra'] === undefined) vars[from]['subtipo'] = ctx.theMsg.body + console.log(vars[from]['tipo'], vars[from]['subtipo']) let theUrl = `http://localhost:8888/dbrquery?j={"query":"selectProdsFerreroMty","exec":"ExecuteQuery","params":{"par1":"${vars[from]['tipo']}", "par2":"${vars[from]['subtipo']}"}}` const RES = await axios.get(theUrl).then(function (response) { let elMensaje = "Gracias,\nAhora un producto:\n\n" @@ -327,7 +336,7 @@ const listenMessage = () => client.on('message', async msg => { rows: lasOpciones, } ], - `SUBCATEGORÍA ${body}`, + `SUBCATEGORÍA ${vars[from]['subtipo']}`, "Footer" ) client.sendMessage(from, productList) @@ -337,6 +346,7 @@ const listenMessage = () => client.on('message', async msg => { return error }); } + /** * Llama el API para traer productos de Guna. * @param {*} ctx El objeto del mensaje. @@ -345,20 +355,34 @@ const listenMessage = () => client.on('message', async msg => { // vars[from]['subtipo'] = ctx.theMsg.body if(vars[from]['prods'] === undefined) { vars[from]['prods'] = [] } let elProd = ctx.theMsg.body - elProd = elProd.substring(0, elProd.indexOf(' $')).trim().toLowerCase() - var precio = ctx.theMsg.body.substring(ctx.theMsg.body.indexOf(' $')+2) - console.log("precio",precio) - precio = precio.substring(0, precio.indexOf(',')) - console.log("precio",precio) - vars[from]['prods'][elProd] = {"cant":0, "precio":precio} - console.log("EL_PROD=", elProd) - console.log(vars[from]['prods'][elProd]) - let elMensaje = ctx.theMsg.replyMessage - let re = ctx.theMsg.body.trim().toLowerCase() - elMensaje = elMensaje.replace(re, elProd.toLowerCase()) + let elMensaje = "" + if(elProd.indexOf(' $') > -1){ // Producto con formato correcto. + vars[from]['ultimoProd'] = elProd + elProd = elProd.substring(0, elProd.indexOf(' $')).trim().toLowerCase() + var precio = ctx.theMsg.body.substring(ctx.theMsg.body.indexOf(' $')+2) + console.log("precio",precio) + precio = precio.substring(0, precio.indexOf(',')) + console.log("precio",precio) + vars[from]['prods'][elProd] = {"cant":0, "precio":precio} + console.log("EL_PROD=", elProd) + console.log(vars[from]['prods']) + elMensaje = ctx.theMsg.replyMessage + let re = ctx.theMsg.body.trim().toLowerCase() + elMensaje = elMensaje.replace(re, elProd.toLowerCase()) + } + else{ // Producto SIN precio. + elMensaje = "El producto que seleccionaste es *incorrecto*, por favor intenta de nuevo." + sendMessage(client, from, elMensaje, ctx.theMsg.trigger, ctx.theMsg.step); + await delay(500) + vars[from]['recompra'] = true + getGunaProds() + vamosA(from, "gunaProds") + return + } sendMessage(client, from, elMensaje, ctx.theMsg.trigger, ctx.theMsg.step); return } + /** * Tomamos la cantidad del producto seleccionado. * @param {*} ctx El objeto del mensaje. @@ -366,33 +390,39 @@ const listenMessage = () => client.on('message', async msg => { async function prodCantidad(ctx) { // console.log("Entramos a prodCantidad") let laCant = ctx.theMsg.body.trim() - const reg = new RegExp('^[0-9]+$') - let elProd = remplazos("%msjant_2%").toLowerCase() + const reg = new RegExp(/^\d+$/) + let elProd = vars[from]['ultimoProd'].toLowerCase() elProd = elProd.substring(0, elProd.indexOf(' $')).trim() + console.log("SOLO NUMS |" + laCant + "|", reg.test(laCant)) if(reg.test(laCant)){ + console.log(vars) console.log("Recibimos cant = " + laCant) console.log("EL_PROD=", vars[from]['prods'][elProd]) console.log("precio=", vars[from]['prods'][elProd].precio) - console.log("precio=", vars[from]['prods'][elProd]['precio']) vars[from]['prods'][elProd] = {"cant":laCant, "precio":vars[from]['prods'][elProd]['precio']} - console.log(vars[from]['prods']) - var elMensaje = "" - const prods = Object.keys(vars[from]['prods']); - prods.forEach((prod, index) => { - elMensaje = elMensaje + `${vars[from]['prods'][prod].cant} - ${prod[0].toUpperCase() + prod.substring(1)}\n` - console.log(`${prod}: ${vars[from]['prods'][prod]}`); - }); - elMensaje = elMensaje + "\n¿Quieres agregar mas productos a tu orden?" - // for(pr=0;pr { + if( vars[from]['prods'][prod] !== undefined && prod[0] !== undefined ){ + elMensaje = elMensaje + `${vars[from]['prods'][prod].cant} - ${prod[0].toUpperCase() + prod.substring(1)}\n` + console.log("cant y precio=", vars[from]['prods'][prod].cant, vars[from]['prods'][prod].precio) + if(reg.test(vars[from]['prods'][prod].cant) && vars[from]['prods'][prod].precio != ""){ + total = total + (vars[from]['prods'][prod].cant * vars[from]['prods'][prod].precio) + } + } + console.log(prod, vars[from]['prods'][prod]); + }); + let pesos = Intl.NumberFormat('en-US') + elMensaje = elMensaje + "\n*Total*: $" + pesos.format(total) + elMensaje = elMensaje + "\n¿Quieres agregar mas productos a tu orden?" var bts = { "title":"Tu orden", "message":elMensaje, "buttons":[ - {"body":"Terminar"}, - {"body":"Agregar productos"} + {"body":"➕ Agregar productos"}, + {"body":"⬅️ Cambiar categoría"}, + {"body":"✖️ Terminar"} ] } sendMessageButton(client, from, "xxx", bts) @@ -412,11 +442,22 @@ const listenMessage = () => client.on('message', async msg => { async function comprarMas(ctx) { console.log("Entramos a comprarMas") vars[from]['recompra'] = true + vamosA(from, "gunaProds") await getGunaProds(ctx) vars[from]['recompra'] = false return "1" } - + + /** + * Mandamos nuevamente la lista de categorías. + * @param {*} ctx El objeto del mensaje. + */ + async function terminaCompra(ctx) { + console.log("Entramos a terminaCompra") + vars[from] = [] + sendMessage(client, from, "!Gracias por tu compra, regresa pronto!", response.trigger, step); + return + } /** @@ -448,7 +489,7 @@ const listenMessage = () => client.on('message', async msg => { console.log("############# Encontramos función, ejecutamos la función '" + response.funcion + "'") laFuncion = response.funcion + "(client)" eval(laFuncion) - return + // return } if(response.hasOwnProperty('urlXXXXXXX') && response.hasOwnProperty('values')){ let theURL = response.url; @@ -568,35 +609,35 @@ if(message=='/spam'){ const masivo = require('./spam.json') var saludo; var caritas; - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + async function retardo() { + for (sp=0;sp k.messages.message != "") + // console.log(hayHistorialNoBlanks) + // var {keywords} = stepsInitial.find(k => k.key.includes(key)) if(hayHistorial){ let rawdata = fs.readFileSync(`./chats/${from}.json`); let elHistorial = JSON.parse(rawdata); @@ -755,6 +798,10 @@ function traeMensajes(from){ //MOD by CHV - Agregamos para traer el historial de // console.log("Mensajes:"+totalMsjs+", Ultimo:"+JSON.stringify(ultimoMensaje)); // console.log("Anterior:"+JSON.stringify(mensajeAnterior)); } + console.log(histlMsjs) + // var histlMsjsNoBlanks = histlMsjs.find(k => k.message != "") + var histlMsjsNoBlanks = histlMsjs.filter(x => x.message != "") + console.log(histlMsjsNoBlanks) return histlMsjs; } diff --git a/flow/response.json b/flow/response.json index 6fb8226..eff337f 100644 --- a/flow/response.json +++ b/flow/response.json @@ -351,7 +351,7 @@ "pasoRequerido":"soporte" }, "gunaCats":{ - "keywords": ["/guna", "/demoventa", "/demoguna"], + "keywords": ["/guna", "/demoventa", "/demoguna", "⬅️ cambiar categoria"], "replyMessage":[ "Mensaje de getGunaCats" ], @@ -400,7 +400,7 @@ "pasoRequerido":"gunaProdsAgrega" }, "gunaComprarMas":{ - "keywords": ["Agregar productos"], + "keywords": "*agregar productos", "replyMessage":[ "Quiero comprar mas." ], @@ -408,5 +408,15 @@ "media":null, "trigger":null, "pasoRequerido":"gunaProdsCantidad" + }, + "gunaTerminaCompra":{ + "keywords": "*terminar", + "replyMessage":[ + "Termina la compra" + ], + "funcion":"terminaCompra", + "media":null, + "trigger":null, + "pasoRequerido":"gunaProdsCantidad" } } \ No newline at end of file From 693de00db8787c3d89e1143536994fd61da67a7e Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Tue, 7 Feb 2023 00:09:24 -0600 Subject: [PATCH 09/19] fixes varios --- adapter/index.js | 127 +++++++++++--- app.js | 424 +++++++++++++++++++++------------------------ flow/response.json | 14 +- 3 files changed, 311 insertions(+), 254 deletions(-) diff --git a/adapter/index.js b/adapter/index.js index 11c6a50..592a81b 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -4,9 +4,7 @@ const { getDataIa } = require('./diaglogflow') // const stepsInitial = require('../flow/initial.json') const stepsReponse = require('../flow/response.json') const { isUndefined } = require('util'); -var msjsRecibidos = []; var ultimoStep; //MOD by CHV - -// var pasoAnterior = []; //MOD by CHV - Para guardar el paso anterior de cada número. (MOD - global en app.js) var pasoRequerido; //MOD by CHV - var _vamosA = ""; //MOD by CHV - var VA = ""; //MOD by CHV - @@ -45,14 +43,43 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - if(siguientePaso.length>1){console.log(siguientePaso[1]["numero"], siguientePaso[1]["va"])} /** - * Si no estas usando un gesto de base de datos + * Si no estas usando una base de datos */ - if (process.env.DATABASE === 'none') { - // console.log(message) - var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null } - // console.log(stepsInitial) - // console.log("KEY="+key) + //******************************************************************************** */ + var logKeysArray = false // Poner en verdadero para ver logs de esta seccion. + //******************************************************************************** */ + key = null + let q = 0; + if(logKeysArray) console.log(stepsInitial.length) + while (key == null && q < stepsInitial.length) { + if(Array.isArray(stepsInitial[q].keywords)){ + let r = 0 + let rFound = false + while(!rFound && r new Promise((resolve, reject) => { //MOD by CHV - var {keywords} = stepsInitial.find(k => k.key.includes(key)) || { keywords: null } if(!Array.isArray(keywords)){key=null;}//Si "keywords" no es arreglo entonces ponemos "key" en null y usamos REGEXP para buscar reglas. if(key == null && message.length > 0){ + //******************************************************************************** */ var logRegEx = false + //******************************************************************************** */ console.log("======= KEY ES NULO, USAMOS REGEXP ======="); for (i=0; i new Promise((resolve, reject) => { //MOD by CHV - } else { if(logRegEx) console.log("--- NO CUMPLE PASO REQ"); - // console.log("pasoReq=" + resps[stepsInitial[i].key.toString()].pasoRequerido + " - PasoAnt=" + ultimoStep) } } } - // console.log("<<<<<<<<< "+key); + // console.log("<<<<<<<<< " + key); // cumplePasoRequerido(key) // ultimoPaso = pasoRequerido; // ultimoStep = key; @@ -135,7 +157,6 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - console.log("ASIGNAMOS _VAMOSA = " + _vamosA); pasoAnterior[elNum] = _vamosA; } - // console.log("ULTIMOSTEP="+ultimoStep) _vamosA = ""; // console.log("MESSAGE: "+message); // console.log("KEY: "+key); @@ -155,7 +176,7 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - const reply = (step) => new Promise((resolve, reject) => { /** - * Si no estas usando un gesto de base de datos + * Si no estas usando una base de datos */ if (process.env.DATABASE === 'none') { let resData = { replyMessage: '', media: null, trigger: null } @@ -207,7 +228,7 @@ const saveMessage = ( message, trigger, number, regla ) => new Promise( async (r resolve( await saveMessageMysql( message, trigger, number ) ) break; case 'none': - resolve( await saveMessageJson( message, trigger, number, regla) ) //MOD by CHV - Agregamos el paranetro "regla" + resolve( await saveMessageJson( message, trigger, number, regla) ) //MOD by CHV - Agregamos el parametro "regla" // console.log("REGLA DESDE APP.JS="+regla) break; default: @@ -216,11 +237,12 @@ const saveMessage = ( message, trigger, number, regla ) => new Promise( async (r } }) -module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial, vamosA } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js" +module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial, vamosA, traeUltimaVisita } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js" /** * Asigna el valor especificado a la variable pasoAnterior. - * Esta hace que el flujo se redirija al paso siguente al especificado. + * Esta hace que el flujo se redirija al paso siguente al especificado. + * NO EJECUTA EL PASO DADO, solo espfecifica cual es el paso anterior para cuando una regla tiene el parametro "pasoRequerido". * @param {elNum} string - El numero del remitente. * @param {elPaso} string - El paso al que se va redirigir el flujo. */ @@ -234,6 +256,7 @@ function vamosA (elNum, elPaso){ */ function remplazos(elTexto, extraInfo){ if(elTexto == null){elTexto = '';} + const fs = require('fs'); laLista = elTexto.toString().split(' '); // console.log(laLista); // console.log('============= remplazos ============'); @@ -390,8 +413,13 @@ function remplazos(elTexto, extraInfo){ ultimoPaso = pasoRequerido; } -const fs = require('fs'); +/** + * Revisa que exista el archivo "chats/numero.json" + * @param {*} theFile + * @returns + */ function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json" + const fs = require('fs'); if (fs.existsSync(theFile)) { // console.log("Si existe el archivo "+ theFile); var h = true; @@ -401,4 +429,59 @@ function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el a var h = false; } return h; +} + +/** + * Regresa el tiempo tanscurrido en (datepart) desde la ultima visita.\n + * datepart: 'y', 'm', 'w', 'd', 'h', 'n', 's' (default = n) + * @param {*} file + * @param {*} datepart + */ +function traeUltimaVisita(file, datepart = 'n'){ + // Node.js program to demonstrate the + // fs.futimes() method + let thisLog = false + const fs = require('fs'); + let theFile = `${__dirname}/../chats/`+file+".json" + if(thisLog) console.log("chkFile=", chkFile(theFile), datepart) + if(chkFile(theFile)){ + // Get the file descriptor of the file + const fd = fs.openSync(theFile); + // console.log("Details before changing time:"); + // Get the stats object of the file + if(thisLog) console.log(new Date()) + prevStats = fs.statSync(theFile); + // Access the modified and access time of the file + if(thisLog) console.log("Modification Time:", prevStats.mtime); + if(thisLog) console.log("Access Time:", prevStats.atime); + // Get the current time to change the timestamps + let changedModifiedTime = new Date(); + let changedAccessTime = new Date(); + // Use the futimes() function to assign + // the new timestamps to the file descriptor + fs.futimes(fd, changedAccessTime, changedModifiedTime, ()=>{}) + if(thisLog) console.log("dd=", dateDiff(datepart, prevStats.atime, changedAccessTime)) + if(thisLog) console.log(new Date()) + return dateDiff(datepart, prevStats.atime, changedAccessTime) + } + else { return 0 } +} + /** + * Regresa el tiempo transcurrido en (datepart) entre las fechas dadas. + * datepart: 'y', 'm', 'w', 'd', 'h', 'n', 's' + * @param {*} datepart + * @param {*} fromdate + * @param {*} todate + * @returns + */ +function dateDiff(datepart, fromdate, todate){ + datepart = datepart.toLowerCase(); + var diff = todate - fromdate; + var divideBy = { w:604800000, + d:86400000, + h:3600000, + n:60000, + s:1000 }; + + return Math.floor( diff/divideBy[datepart]); } \ No newline at end of file diff --git a/app.js b/app.js index a6863ff..bbd6120 100644 --- a/app.js +++ b/app.js @@ -11,19 +11,19 @@ const axios = require('axios').default;//MOD by CHV - Agregamos para el get del const qrcode = require('qrcode-terminal'); const { Client, LocalAuth, Buttons, List } = require('whatsapp-web.js'); const mysqlConnection = require('./config/mysql') -const { middlewareClient } = require('./middleware/client') +// const { middlewareClient } = require('./middleware/client') const { generateImage, cleanNumber, checkEnvFile, createClient, isValidNumber } = require('./controllers/handle') const { connectionReady, connectionLost } = require('./controllers/connection') const { saveMedia, saveMediaToGoogleDrive } = require('./controllers/save') const { getMessages, responseMessages, bothResponse, waitFor } = require('./controllers/flows') const { sendMedia, sendMessage, lastTrigger, sendMessageButton, sendMessageList, readChat } = require('./controllers/send'); -const { remplazos, stepsInitial, vamosA } = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial -const { isUndefined } = require('util'); -const { isSet } = require('util/types'); +const { remplazos, stepsInitial, vamosA, traeUltimaVisita } = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial +// const { isUndefined } = require('util'); +// const { isSet } = require('util/types'); const { Console } = require('console'); -const { ClientRequest } = require('http'); +// const { ClientRequest } = require('http'); const { guardaXLSDatos, leeXLSDatos} = require('./Excel'); -const { ContextsClient } = require('@google-cloud/dialogflow'); +// const { ContextsClient } = require('@google-cloud/dialogflow'); const { ingresarDatos, leerDatos } = require('./implementaciones/sheets') const app = express(); app.use(cors()) @@ -34,7 +34,7 @@ const port = process.env.PORT || 3000 const delay = (ms) => new Promise((resolve) => setTimeout(resolve,ms)) var client; var dialogflowFilter = false; -var totalMsjs; //MOD by CHV - +// var totalMsjs; //MOD by CHV - // var vamosA = ""; //MOD by CHV - var newBody; //MOD by CHV - var nuevaRespuesta; //MOD by CHV - Se agrego para los remplazos @@ -48,41 +48,39 @@ let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','346 listenMessage = () => client.on('message', async msg => { const { from, body, hasMedia } = msg; if (vars[from] === undefined) vars[from] = [] - // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); console.log("+++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++"); - // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); client.theMsg = msg; - // console.log("%%%%%%%%% userAgent = " + client?.options?.userAgent) console.log("HORA:"+new Date().toLocaleTimeString()+" FROM:"+from+", BODY:"+body+", HASMEDIA:"+hasMedia+", DEVICETYPE:"+client.theMsg?.deviceType); newBody = removeDiacritics(body) //MOD by CHV - Agregamos para quitar acentos - // newBody = remplazos(newBody); - // vamosA = ""; + + // const uv = traeUltimaVisita(from, 's') + // console.log("ultVista=", uv) + if(!isValidNumber(from)){ return } // Este bug lo reporto Lucas Aldeco Brescia para evitar que se publiquen estados - if (from === 'status@broadcast') { - return - } - + if (from === 'status@broadcast') { return } /** - * Blacklist, los telefonos inlcuidos en este arreglo son ignorados por el bot. - */ - console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) - if (blackList.includes(from.replace("@c.us",""))) return + * Blacklist, los telefonos incluidos en este arreglo son ignorados por el bot. + */ + if (blackList.includes(from.replace("@c.us",""))) { + console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) + return + } message = newBody.toLowerCase(); const number = cleanNumber(from) client.theMsg['numero'] = number + // Guardamos el mensaje en Google Sheets ingresarDatos(from, body) - -// console.log(stepsInitial) + // console.log(stepsInitial) var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null }//MOD by CHV - Se agrega para obtener KEY await readChat(number, message, null , key) //MOD by CHV - Agregamos key/regla para guardarla en "chats/numero.json" client.theMsg['key'] = key - + /** * Guardamos el archivo multimedia que envia */ @@ -94,7 +92,6 @@ listenMessage = () => client.on('message', async msg => { /** * Si estas usando dialogflow solo manejamos una funcion todo es IA */ - if (process.env.DATABASE === 'dialogflow') { if (process.env.DIALOGFLOW_MEDIA_FOR_SLOT_FILLING === 'true' && dialogflowFilter) { waitFor(_ => hasMedia, 30000) @@ -123,6 +120,7 @@ listenMessage = () => client.on('message', async msg => { } if(body=='/listas'){ + // Asi se manda directamente con el ciente de whatsapp-web.js "client.sendMessage(from, productList)" const productList = new List( "Here's our list of products at 50% off", "View all products", @@ -139,96 +137,118 @@ listenMessage = () => client.on('message', async msg => { "Please select a product" ); console.log('##################################################################################################') - // console.log(from, lista) - // let sections = [{title:'sectionTitle',rows:[{id:'ListItem1', title: 'title1'},{id:'ListItem2', title:'title2'}]}]; - // let lista = new List('List body','btnText',sections,'Title','footer'); console.log("****************** productList ******************") console.log(productList) - client.sendMessage(from, productList); //cliente.sendMessage recibe el arreglo SIN nombres (solo las secciones los necesitan) - // client.sendMessage('5215527049036@c.us', productList); - // client.sendMessage('5215554192439@c.us', productList); - // await sendMessageList(client, '5215545815654@c.us', null, lista); //sendMessageList recibe el arreglo CON nombres, como viene del response.json - // await sendMessageList(client, '5215527049036@c.us', null, lista); - // await sendMessageList(client, '5215554192439@c.us', null, lista); - // client.sendMessage(from, lista); + client.sendMessage(from, productList); + // Asi se manda directamente con la funcion del bot. "sendMessageList(client, from, null, lista)" + // let sections = [ + // { title:'sectionTitle', + // rows:[ + // {id:'ListItem1', title: 'title1'}, + // {id:'ListItem2', title:'title2'} + // ] + // } + // ]; + // let lista = new List('List body','btnText',sections,'Title','footer'); + await sendMessageList(client, from, null, productList); //sendMessageList recibe el arreglo CON nombres, tal cual se usa en "response.json" } - - /** - * PRUEBA BOTONES NUEVOS - */ - // if(body=="579"){ - // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button - // for (const component of [buttons_reply]) await client.sendMessage(from, component); - // } /** * Ver si viene de un paso anterior * Aqui podemos ir agregando más pasos * a tu gusto! */ - - const lastStep = await lastTrigger(from) || null; - client.theMsg['lastStep'] = lastStep - // console.log("LAST STEP="+lastStep+", FROM:"+from); - if (lastStep) { - const response = await responseMessages(lastStep) - client.theMsg['trigger'] = response.trigger - console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); - // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. - response.replyMessage.forEach( async messages => { - var thisMsg = messages.mensaje - if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} - await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); - }) - } + // const lastStep = await lastTrigger(from) || null; + // client.theMsg['lastStep'] = lastStep + // // console.log("LAST STEP="+lastStep+", FROM:"+from); + // if (lastStep) { + // const response = await responseMessages(lastStep) + // client.theMsg['trigger'] = response.trigger + // console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); + // // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. + // response.replyMessage.forEach( async messages => { + // var thisMsg = messages.mensaje + // if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} + // await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); + // }) + // } /** * Respondemos al primero paso si encuentra palabras clave */ - // const step = await getMessages(message, ); - // console.log("STEP - "+step+"|"+message); - // console.log("****** STEP="+step); - // console.log("****** MESSAGE:"+message); - const step = await getMessages(message, from); - client.theMsg['step'] = step - if (step) { - const response = await responseMessages(step); - client.theMsg['trigger'] = response.trigger - var resps = require('./flow/response.json'); - nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); - client.theMsg['replyMessage'] = nuevaRespuesta - var pasoRequerido = resps[step].pasoRequerido; - // console.log('NUEVA RESPUESTA=', nuevaRespuesta) - - if(nuevaRespuesta.search("/URL")>-1){ - // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. - // console.log(theUrl); - console.log("========== GET URL ============"); - /* - ============================================================================ - ======================== DESBLOQUEO DE USUARIOS ========================== - ============================================================================ - */ - console.log('PASOREQUERIDO=', pasoRequerido) - if(pasoRequerido=="soporte"){ - // var theUrl=nuevaRespuesta.substring(5).replace("XXPARAM1XX",newBody); - // const RES = await axios.get(theUrl).then(function (response) { - // const { AffectedRows } = response.data['respuesta'][0] - // console.log('AFFECTED_ROWS = ', AffectedRows) - // if(response.data['respuesta'][0]['AffectedRows']=="1"){ - // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); - // } - // else{ - // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); - // } - // return response - // // console.log('AXIOS RES=', response) - // }).catch(function (error) { - // console.log(error); - // return error - // }); - // console.log('RES=', RES) + const step = await getMessages(message, from); + client.theMsg['step'] = step + if (step) { + console.log("Entramos a STEP") + const response = await responseMessages(step); + client.theMsg['trigger'] = response.trigger + var resps = require('./flow/response.json'); + nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); + client.theMsg['replyMessage'] = nuevaRespuesta + // var pasoRequerido = resps[step].pasoRequerido; + if(body=='traeXLS'){ + const rows = await leeXLSDatos('x') + console.log("RESULTADOS:") + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); } + async function retardo() { + for (sp=1;sp setTimeout(resolve, ms)); + } + async function retardo() { + for (sp=0;sp client.on('message', async msg => { return } - /** * Llama el API para desbloquear un usuario. * @param {*} ctx El objeto del mensaje. @@ -482,6 +501,36 @@ listenMessage = () => client.on('message', async msg => { return error }); } + + /** + * Llama el API para desbloquear el usuario. + * + * @param {*} theURL El URL para llamar al API + * @param {*} step + */ + async function desbloqueaUsuario2(theUrl, step) { + // const {from} = client.theMsg + // const RES = await axios.get(theUrl).then(function (response) { + // const { AffectedRows } = response.data['respuesta'][0] + // console.log('AFFECTED_ROWS = ', AffectedRows) + // if(response.data['respuesta'][0]['AffectedRows']=="1"){ + // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); + // } + // else{ + // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); + // } + // return response + // }).catch(function (error) { + // console.log(error); + // return error + // }); + } + + // #################################################################################################################### + // ############################## INICIAN FUNCIONES PARA MANEJO DE PARAMETROS ##################################### + // ############################## EN EL RESPONSE.JSON ##################################### + // #################################################################################################################### + /* * Si quieres ejecutar una función. */ @@ -491,25 +540,25 @@ listenMessage = () => client.on('message', async msg => { eval(laFuncion) // return } - if(response.hasOwnProperty('urlXXXXXXX') && response.hasOwnProperty('values')){ - let theURL = response.url; - let url0 = theURL - let vals = response.values // Traemos los valores desde el response.json - let j = theURL.split('j=')[1] // Traemos el JSON del URL. - let j2 = JSON.parse(j) - let cont = 0 - const { params } = j2 // Traemos los parametros del JSON. - console.log('PARAMS=', params, params['par1'], Object.keys(params).length) - let url2 - for (const par in params) { // Remplazamos los valores en lo parametros. - console.log(`${par}: ${params[par]}, ${cont}: ${remplazos(vals[cont], client)}`); - if(cont==0){url2=url0.replace(params[par], remplazos(vals[cont], client));} - else {url2=url2.replace(params[par], remplazos(vals[cont], client));} - cont++ - } - // console.log('THE_URL=', url2) - desbloqueaUsuario2(url2, step) //Llamamos al API para desbloquear el usuario. - return + if(response.hasOwnProperty('url') && response.hasOwnProperty('values')){ + // let theURL = response.url; + // let url0 = theURL + // let vals = response.values // Traemos los valores desde el response.json + // let j = theURL.split('j=')[1] // Traemos el JSON del URL. + // let j2 = JSON.parse(j) + // let cont = 0 + // const { params } = j2 // Traemos los parametros del JSON. + // console.log('PARAMS=', params, params['par1'], Object.keys(params).length) + // let url2 + // for (const par in params) { // Remplazamos los valores en lo parametros. + // console.log(`${par}: ${params[par]}, ${cont}: ${remplazos(vals[cont], client)}`); + // if(cont==0){url2=url0.replace(params[par], remplazos(vals[cont], client));} + // else {url2=url2.replace(params[par], remplazos(vals[cont], client));} + // cont++ + // } + // // console.log('THE_URL=', url2) + // desbloqueaUsuario2(url2, step) //Llamamos al API para desbloquear el usuario. + // return } /** * Si quieres enviar imagen. @@ -571,82 +620,9 @@ listenMessage = () => client.on('message', async msg => { return } - if(body=='trae'){ - const rows = await leeXLSDatos('x') - console.log("RESULTADOS:") - // d.forEach(row => async function() { - // console.log(row.nombre, row.edad, row.sexo) - // client.sendMessage(from, `Hola ${row.nombre}, recuerda que tienes un adeudo pendiente`) - // }) - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - async function retardo() { - for (sp=1;sp setTimeout(resolve, ms)); - } - async function retardo() { - for (sp=0;sp client.on('message_create', async botMsg => { } }); +// #################################################################################################################### +// ############################## INICIAN FUNCIONES PARA LA CREACION DEL CLIENTE #################################### +// ############################## DE WHATSAPP-WEB.JS #################################### +// #################################################################################################################### + client = new Client({ authStrategy: new LocalAuth(), puppeteer: { headless: true, args: ['--no-sandbox','--disable-setuid-sandbox'] } @@ -733,40 +715,32 @@ client.initialize(); server.listen(port, () => { console.log(`El server esta listo en el puerto ${port}`); }) + checkEnvFile(); - /** - * Llama el API para desbloquear el usuario. - * - * @param {*} theURL El URL para llamar al API - * @param {*} step +// #################################################################################################################### +// ############################## INICIAN FUNCIONES VARIAS #################################### +// #################################################################################################################### + +/** + * Regresa un número random entre los parametros min y max dados. + * @param {*} min + * @param {*} max + * @returns */ - async function desbloqueaUsuario2(theUrl, step) { - const {from} = client.theMsg - const RES = await axios.get(theUrl).then(function (response) { - const { AffectedRows } = response.data['respuesta'][0] - console.log('AFFECTED_ROWS = ', AffectedRows) - if(response.data['respuesta'][0]['AffectedRows']=="1"){ - sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); - } - else{ - sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); - } - return response - }).catch(function (error) { - console.log(error); - return error - }); - // const r = await axios.get(theUrl).then(function (response) { - // console.log('AXIOS RES=', response) - // }).catch(function (error) { - // console.log(error); - // return error - // }) - // return Promise.resolve(r) +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive } - + +/** + * Revisa que exista el archivo "chats/numero.json" + * @param {*} theFile + * @returns + */ function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json" + const fs = require('fs'); if (fs.existsSync(theFile)) { // console.log("Si existe el archivo "+ theFile); var h = true; diff --git a/flow/response.json b/flow/response.json index eff337f..f171a64 100644 --- a/flow/response.json +++ b/flow/response.json @@ -48,7 +48,7 @@ "trigger":null }, "opcion1":{ - "keywords": "1", + "keywords": ["1"], "replyMessage":[ { "mensaje":[ @@ -68,7 +68,7 @@ "goto":"menu" }, "opcion2":{ - "keywords": "2", + "keywords": ["2"], "replyMessage":[ { "mensaje":[ @@ -86,12 +86,12 @@ "goto":"menu" }, "opcion3":{ - "keywords": "3", + "keywords": ["3"], "replyMessage":[ { "mensaje":[ "Seleccionaste la *opción 3*\n", - "Por favor dame tu nombre.\n", + "*Por favor dame tu nombre.*\n", "Aquí vamos a aceptar *cualquier* texto, porque en el *initial.json* tenemos keywords : \"*\" (un asterisco en expresiones regulares quiere decir *\"cualquier cosa\"*)", "Y en *response.json* en la opción correspondiente tenemos \"pasoRequerido\" : \"menu\", que quiere decir que SOLO se va a disparar cuando el paso anterior sea \"menu\"." ] @@ -180,7 +180,7 @@ } }, "lista":{ - "keywords": "4", + "keywords": ["4"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de listas"] @@ -207,7 +207,7 @@ "goto":"menu" }, "botones":{ - "keywords": "5", + "keywords": ["5"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de botones"] @@ -306,7 +306,7 @@ "goto":"menu" }, "botonespaq3":{ - "keywords": "6", + "keywords": ["6"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de botones y regExp"] From 26932ccefcd6da6ec23e86b30fe2bd06e055fc0b Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Tue, 7 Feb 2023 02:01:49 -0600 Subject: [PATCH 10/19] format --- adapter/index.js | 32 +++++++++++++------------------- app.js | 17 ++++++++--------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/adapter/index.js b/adapter/index.js index 592a81b..7c4c84b 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -35,7 +35,6 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - elNum = num //MOD by CHV - if(siguientePaso.find(k => k.numero.includes(elNum))){ console.log("siguientePaso="+siguientePaso.find(k => k.numero.includes(elNum))["numero"], siguientePaso.find(k => k.numero.includes(elNum))["va"]) - // ultimoStep = siguientePaso.find(k => k.numero.includes(elNum))["va"] pasoAnterior[elNum] = siguientePaso.find(k => k.numero.includes(elNum))["va"] //Asignamos pasoAnterior al número. siguientePaso.splice(siguientePaso.indexOf(elNum), 1) console.log("******************** "+siguientePaso.find(k => k.numero.includes(elNum))) @@ -103,31 +102,30 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - var logRegEx = false //******************************************************************************** */ console.log("======= KEY ES NULO, USAMOS REGEXP ======="); - for (i=0; i -1){ + if(resps[stepsInitial[si].key].replyMessage.toString().search("/URL") > -1){ if(logRegEx) console.log("**************** HAY URL ****************") } break; @@ -151,16 +149,12 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - if(resps[key]!=undefined){VA = resps[key].goto}else{VA=null} cumplePasoRequerido(key); _vamosA = VA; - console.log("cumplePasoPrevio[elNum]=", cumplePasoPrevio[elNum]) - + if(logRegEx) console.log("cumplePasoPrevio[elNum]=", cumplePasoPrevio[elNum], "_vamosA=", _vamosA) if(_vamosA != "" && _vamosA != undefined && cumplePasoPrevio[elNum] == true){ - console.log("ASIGNAMOS _VAMOSA = " + _vamosA); + if(logRegEx) console.log("ASIGNAMOS _VAMOSA = " + _vamosA); pasoAnterior[elNum] = _vamosA; } _vamosA = ""; - // console.log("MESSAGE: "+message); - // console.log("KEY: "+key); - // console.log("RESPONSE: "+response); if(cumplePasoPrevio[elNum]) {resolve(response);} } @@ -410,7 +404,7 @@ function remplazos(elTexto, extraInfo){ cumplePasoPrevio[elNum] = true; } pasoAnterior[elNum] = step - ultimoPaso = pasoRequerido; + // ultimoPaso = pasoRequerido; } /** diff --git a/app.js b/app.js index bbd6120..7f1c31d 100644 --- a/app.js +++ b/app.js @@ -179,7 +179,7 @@ listenMessage = () => client.on('message', async msg => { const step = await getMessages(message, from); client.theMsg['step'] = step if (step) { - console.log("Entramos a STEP") + // console.log("Entramos a STEP") const response = await responseMessages(step); client.theMsg['trigger'] = response.trigger var resps = require('./flow/response.json'); @@ -604,16 +604,15 @@ listenMessage = () => client.on('message', async msg => { /** * Si quieres enviar botones o listas */ - if(response.hasOwnProperty('actions')){ - const { actions } = response; - // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); - if(actions['sections'] === undefined){ //Botones - console.log("Botones") - await sendMessageButton(client, from, null, actions); + if(response.hasOwnProperty('actions')){ + const { actions } = response; + // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); + if(actions['sections'] === undefined){ //Botones + // console.log("Botones") + await sendMessageButton(client, from, null, actions); } else { //Listas - console.log("Listas") - // console.log(actions) + // console.log("Listas") await sendMessageList(client, from, null, actions); } } From fafcb41eccccf8a917ce4f3d17ddbd47b12f1a21 Mon Sep 17 00:00:00 2001 From: cheveguerra Date: Tue, 7 Feb 2023 02:06:57 -0600 Subject: [PATCH 11/19] merge con BotGuna --- adapter/index.js | 159 +++++++++++----- app.js | 445 +++++++++++++++++++++------------------------ flow/response.json | 14 +- 3 files changed, 336 insertions(+), 282 deletions(-) diff --git a/adapter/index.js b/adapter/index.js index 11c6a50..7c4c84b 100644 --- a/adapter/index.js +++ b/adapter/index.js @@ -4,9 +4,7 @@ const { getDataIa } = require('./diaglogflow') // const stepsInitial = require('../flow/initial.json') const stepsReponse = require('../flow/response.json') const { isUndefined } = require('util'); -var msjsRecibidos = []; var ultimoStep; //MOD by CHV - -// var pasoAnterior = []; //MOD by CHV - Para guardar el paso anterior de cada número. (MOD - global en app.js) var pasoRequerido; //MOD by CHV - var _vamosA = ""; //MOD by CHV - var VA = ""; //MOD by CHV - @@ -37,7 +35,6 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - elNum = num //MOD by CHV - if(siguientePaso.find(k => k.numero.includes(elNum))){ console.log("siguientePaso="+siguientePaso.find(k => k.numero.includes(elNum))["numero"], siguientePaso.find(k => k.numero.includes(elNum))["va"]) - // ultimoStep = siguientePaso.find(k => k.numero.includes(elNum))["va"] pasoAnterior[elNum] = siguientePaso.find(k => k.numero.includes(elNum))["va"] //Asignamos pasoAnterior al número. siguientePaso.splice(siguientePaso.indexOf(elNum), 1) console.log("******************** "+siguientePaso.find(k => k.numero.includes(elNum))) @@ -45,14 +42,43 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - if(siguientePaso.length>1){console.log(siguientePaso[1]["numero"], siguientePaso[1]["va"])} /** - * Si no estas usando un gesto de base de datos + * Si no estas usando una base de datos */ - if (process.env.DATABASE === 'none') { - // console.log(message) - var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null } - // console.log(stepsInitial) - // console.log("KEY="+key) + //******************************************************************************** */ + var logKeysArray = false // Poner en verdadero para ver logs de esta seccion. + //******************************************************************************** */ + key = null + let q = 0; + if(logKeysArray) console.log(stepsInitial.length) + while (key == null && q < stepsInitial.length) { + if(Array.isArray(stepsInitial[q].keywords)){ + let r = 0 + let rFound = false + while(!rFound && r new Promise((resolve, reject) => { //MOD by CHV - var {keywords} = stepsInitial.find(k => k.key.includes(key)) || { keywords: null } if(!Array.isArray(keywords)){key=null;}//Si "keywords" no es arreglo entonces ponemos "key" en null y usamos REGEXP para buscar reglas. if(key == null && message.length > 0){ + //******************************************************************************** */ var logRegEx = false + //******************************************************************************** */ console.log("======= KEY ES NULO, USAMOS REGEXP ======="); - for (i=0; i -1){ + if(resps[stepsInitial[si].key].replyMessage.toString().search("/URL") > -1){ if(logRegEx) console.log("**************** HAY URL ****************") } break; @@ -115,11 +136,10 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - } else { if(logRegEx) console.log("--- NO CUMPLE PASO REQ"); - // console.log("pasoReq=" + resps[stepsInitial[i].key.toString()].pasoRequerido + " - PasoAnt=" + ultimoStep) } } } - // console.log("<<<<<<<<< "+key); + // console.log("<<<<<<<<< " + key); // cumplePasoRequerido(key) // ultimoPaso = pasoRequerido; // ultimoStep = key; @@ -129,17 +149,12 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - if(resps[key]!=undefined){VA = resps[key].goto}else{VA=null} cumplePasoRequerido(key); _vamosA = VA; - console.log("cumplePasoPrevio[elNum]=", cumplePasoPrevio[elNum]) - + if(logRegEx) console.log("cumplePasoPrevio[elNum]=", cumplePasoPrevio[elNum], "_vamosA=", _vamosA) if(_vamosA != "" && _vamosA != undefined && cumplePasoPrevio[elNum] == true){ - console.log("ASIGNAMOS _VAMOSA = " + _vamosA); + if(logRegEx) console.log("ASIGNAMOS _VAMOSA = " + _vamosA); pasoAnterior[elNum] = _vamosA; } - // console.log("ULTIMOSTEP="+ultimoStep) _vamosA = ""; - // console.log("MESSAGE: "+message); - // console.log("KEY: "+key); - // console.log("RESPONSE: "+response); if(cumplePasoPrevio[elNum]) {resolve(response);} } @@ -155,7 +170,7 @@ const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - const reply = (step) => new Promise((resolve, reject) => { /** - * Si no estas usando un gesto de base de datos + * Si no estas usando una base de datos */ if (process.env.DATABASE === 'none') { let resData = { replyMessage: '', media: null, trigger: null } @@ -207,7 +222,7 @@ const saveMessage = ( message, trigger, number, regla ) => new Promise( async (r resolve( await saveMessageMysql( message, trigger, number ) ) break; case 'none': - resolve( await saveMessageJson( message, trigger, number, regla) ) //MOD by CHV - Agregamos el paranetro "regla" + resolve( await saveMessageJson( message, trigger, number, regla) ) //MOD by CHV - Agregamos el parametro "regla" // console.log("REGLA DESDE APP.JS="+regla) break; default: @@ -216,11 +231,12 @@ const saveMessage = ( message, trigger, number, regla ) => new Promise( async (r } }) -module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial, vamosA } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js" +module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial, vamosA, traeUltimaVisita } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js" /** * Asigna el valor especificado a la variable pasoAnterior. - * Esta hace que el flujo se redirija al paso siguente al especificado. + * Esta hace que el flujo se redirija al paso siguente al especificado. + * NO EJECUTA EL PASO DADO, solo espfecifica cual es el paso anterior para cuando una regla tiene el parametro "pasoRequerido". * @param {elNum} string - El numero del remitente. * @param {elPaso} string - El paso al que se va redirigir el flujo. */ @@ -234,6 +250,7 @@ function vamosA (elNum, elPaso){ */ function remplazos(elTexto, extraInfo){ if(elTexto == null){elTexto = '';} + const fs = require('fs'); laLista = elTexto.toString().split(' '); // console.log(laLista); // console.log('============= remplazos ============'); @@ -387,11 +404,16 @@ function remplazos(elTexto, extraInfo){ cumplePasoPrevio[elNum] = true; } pasoAnterior[elNum] = step - ultimoPaso = pasoRequerido; + // ultimoPaso = pasoRequerido; } -const fs = require('fs'); +/** + * Revisa que exista el archivo "chats/numero.json" + * @param {*} theFile + * @returns + */ function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json" + const fs = require('fs'); if (fs.existsSync(theFile)) { // console.log("Si existe el archivo "+ theFile); var h = true; @@ -401,4 +423,59 @@ function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el a var h = false; } return h; +} + +/** + * Regresa el tiempo tanscurrido en (datepart) desde la ultima visita.\n + * datepart: 'y', 'm', 'w', 'd', 'h', 'n', 's' (default = n) + * @param {*} file + * @param {*} datepart + */ +function traeUltimaVisita(file, datepart = 'n'){ + // Node.js program to demonstrate the + // fs.futimes() method + let thisLog = false + const fs = require('fs'); + let theFile = `${__dirname}/../chats/`+file+".json" + if(thisLog) console.log("chkFile=", chkFile(theFile), datepart) + if(chkFile(theFile)){ + // Get the file descriptor of the file + const fd = fs.openSync(theFile); + // console.log("Details before changing time:"); + // Get the stats object of the file + if(thisLog) console.log(new Date()) + prevStats = fs.statSync(theFile); + // Access the modified and access time of the file + if(thisLog) console.log("Modification Time:", prevStats.mtime); + if(thisLog) console.log("Access Time:", prevStats.atime); + // Get the current time to change the timestamps + let changedModifiedTime = new Date(); + let changedAccessTime = new Date(); + // Use the futimes() function to assign + // the new timestamps to the file descriptor + fs.futimes(fd, changedAccessTime, changedModifiedTime, ()=>{}) + if(thisLog) console.log("dd=", dateDiff(datepart, prevStats.atime, changedAccessTime)) + if(thisLog) console.log(new Date()) + return dateDiff(datepart, prevStats.atime, changedAccessTime) + } + else { return 0 } +} + /** + * Regresa el tiempo transcurrido en (datepart) entre las fechas dadas. + * datepart: 'y', 'm', 'w', 'd', 'h', 'n', 's' + * @param {*} datepart + * @param {*} fromdate + * @param {*} todate + * @returns + */ +function dateDiff(datepart, fromdate, todate){ + datepart = datepart.toLowerCase(); + var diff = todate - fromdate; + var divideBy = { w:604800000, + d:86400000, + h:3600000, + n:60000, + s:1000 }; + + return Math.floor( diff/divideBy[datepart]); } \ No newline at end of file diff --git a/app.js b/app.js index c32a4b5..7f1c31d 100644 --- a/app.js +++ b/app.js @@ -11,19 +11,19 @@ const axios = require('axios').default;//MOD by CHV - Agregamos para el get del const qrcode = require('qrcode-terminal'); const { Client, LocalAuth, Buttons, List } = require('whatsapp-web.js'); const mysqlConnection = require('./config/mysql') -const { middlewareClient } = require('./middleware/client') +// const { middlewareClient } = require('./middleware/client') const { generateImage, cleanNumber, checkEnvFile, createClient, isValidNumber } = require('./controllers/handle') const { connectionReady, connectionLost } = require('./controllers/connection') const { saveMedia, saveMediaToGoogleDrive } = require('./controllers/save') const { getMessages, responseMessages, bothResponse, waitFor } = require('./controllers/flows') const { sendMedia, sendMessage, lastTrigger, sendMessageButton, sendMessageList, readChat } = require('./controllers/send'); -const { remplazos, stepsInitial, vamosA } = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial -const { isUndefined } = require('util'); -const { isSet } = require('util/types'); +const { remplazos, stepsInitial, vamosA, traeUltimaVisita } = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial +// const { isUndefined } = require('util'); +// const { isSet } = require('util/types'); const { Console } = require('console'); -const { ClientRequest } = require('http'); +// const { ClientRequest } = require('http'); const { guardaXLSDatos, leeXLSDatos} = require('./Excel'); -const { ContextsClient } = require('@google-cloud/dialogflow'); +// const { ContextsClient } = require('@google-cloud/dialogflow'); const { ingresarDatos, leerDatos } = require('./implementaciones/sheets') const app = express(); app.use(cors()) @@ -34,51 +34,53 @@ const port = process.env.PORT || 3000 const delay = (ms) => new Promise((resolve) => setTimeout(resolve,ms)) var client; var dialogflowFilter = false; -var totalMsjs; //MOD by CHV - +// var totalMsjs; //MOD by CHV - // var vamosA = ""; //MOD by CHV - var newBody; //MOD by CHV - var nuevaRespuesta; //MOD by CHV - Se agrego para los remplazos var vars = [] app.use('/', require('./routes/web')) - - /** - * Escuchamos cuando entre un mensaje - */ +let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','34630283553','34648827637','34630255646','14178973313'] + +/** + * Escuchamos cuando entre un mensaje +*/ listenMessage = () => client.on('message', async msg => { const { from, body, hasMedia } = msg; if (vars[from] === undefined) vars[from] = [] - // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); console.log("+++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++"); - // console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); client.theMsg = msg; - // console.log("%%%%%%%%% userAgent = " + client?.options?.userAgent) console.log("HORA:"+new Date().toLocaleTimeString()+" FROM:"+from+", BODY:"+body+", HASMEDIA:"+hasMedia+", DEVICETYPE:"+client.theMsg?.deviceType); newBody = removeDiacritics(body) //MOD by CHV - Agregamos para quitar acentos - // newBody = remplazos(newBody); - // vamosA = ""; + + // const uv = traeUltimaVisita(from, 's') + // console.log("ultVista=", uv) + if(!isValidNumber(from)){ return } // Este bug lo reporto Lucas Aldeco Brescia para evitar que se publiquen estados - if (from === 'status@broadcast') { - return + if (from === 'status@broadcast') { return } + /** + * Blacklist, los telefonos incluidos en este arreglo son ignorados por el bot. + */ + if (blackList.includes(from.replace("@c.us",""))) { + console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) + return } - let blackList = ['34692936038', '34678310819', '34660962689', '34649145761','34630283553','34648827637','34630255646','14178973313'] - console.log('BlackListed: ',blackList.includes(from.replace("@c.us",""))) - if (blackList.includes(from.replace("@c.us",""))) return message = newBody.toLowerCase(); const number = cleanNumber(from) client.theMsg['numero'] = number + // Guardamos el mensaje en Google Sheets ingresarDatos(from, body) - -// console.log(stepsInitial) + // console.log(stepsInitial) var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null }//MOD by CHV - Se agrega para obtener KEY await readChat(number, message, null , key) //MOD by CHV - Agregamos key/regla para guardarla en "chats/numero.json" client.theMsg['key'] = key - + /** * Guardamos el archivo multimedia que envia */ @@ -90,7 +92,6 @@ listenMessage = () => client.on('message', async msg => { /** * Si estas usando dialogflow solo manejamos una funcion todo es IA */ - if (process.env.DATABASE === 'dialogflow') { if (process.env.DIALOGFLOW_MEDIA_FOR_SLOT_FILLING === 'true' && dialogflowFilter) { waitFor(_ => hasMedia, 30000) @@ -119,6 +120,7 @@ listenMessage = () => client.on('message', async msg => { } if(body=='/listas'){ + // Asi se manda directamente con el ciente de whatsapp-web.js "client.sendMessage(from, productList)" const productList = new List( "Here's our list of products at 50% off", "View all products", @@ -135,96 +137,118 @@ listenMessage = () => client.on('message', async msg => { "Please select a product" ); console.log('##################################################################################################') - // console.log(from, lista) - // let sections = [{title:'sectionTitle',rows:[{id:'ListItem1', title: 'title1'},{id:'ListItem2', title:'title2'}]}]; - // let lista = new List('List body','btnText',sections,'Title','footer'); console.log("****************** productList ******************") console.log(productList) - client.sendMessage(from, productList); //cliente.sendMessage recibe el arreglo SIN nombres (solo las secciones los necesitan) - // client.sendMessage('5215527049036@c.us', productList); - // client.sendMessage('5215554192439@c.us', productList); - // await sendMessageList(client, '5215545815654@c.us', null, lista); //sendMessageList recibe el arreglo CON nombres, como viene del response.json - // await sendMessageList(client, '5215527049036@c.us', null, lista); - // await sendMessageList(client, '5215554192439@c.us', null, lista); - // client.sendMessage(from, lista); + client.sendMessage(from, productList); + // Asi se manda directamente con la funcion del bot. "sendMessageList(client, from, null, lista)" + // let sections = [ + // { title:'sectionTitle', + // rows:[ + // {id:'ListItem1', title: 'title1'}, + // {id:'ListItem2', title:'title2'} + // ] + // } + // ]; + // let lista = new List('List body','btnText',sections,'Title','footer'); + await sendMessageList(client, from, null, productList); //sendMessageList recibe el arreglo CON nombres, tal cual se usa en "response.json" } - - /** - * PRUEBA BOTONES NUEVOS - */ - // if(body=="579"){ - // const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button - // for (const component of [buttons_reply]) await client.sendMessage(from, component); - // } /** * Ver si viene de un paso anterior * Aqui podemos ir agregando más pasos * a tu gusto! */ - - const lastStep = await lastTrigger(from) || null; - client.theMsg['lastStep'] = lastStep - // console.log("LAST STEP="+lastStep+", FROM:"+from); - if (lastStep) { - const response = await responseMessages(lastStep) - client.theMsg['trigger'] = response.trigger - console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); - // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. - response.replyMessage.forEach( async messages => { - var thisMsg = messages.mensaje - if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} - await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); - }) - } + // const lastStep = await lastTrigger(from) || null; + // client.theMsg['lastStep'] = lastStep + // // console.log("LAST STEP="+lastStep+", FROM:"+from); + // if (lastStep) { + // const response = await responseMessages(lastStep) + // client.theMsg['trigger'] = response.trigger + // console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage); + // // await sendMessage(client, from, response.replyMessage, lastStep); // Mod by CHV - Para mandar varios mensajes en el mismo response, se cambio esta linea por el forEach de abajo. + // response.replyMessage.forEach( async messages => { + // var thisMsg = messages.mensaje + // if(Array.isArray(messages.mensaje)){thisMsg = messages.mensaje.join('\n')} + // await sendMessage(client, from, remplazos(thisMsg, client), response.trigger); + // }) + // } /** * Respondemos al primero paso si encuentra palabras clave */ - // const step = await getMessages(message, ); - // console.log("STEP - "+step+"|"+message); - // console.log("****** STEP="+step); - // console.log("****** MESSAGE:"+message); - const step = await getMessages(message, from); - client.theMsg['step'] = step - if (step) { - const response = await responseMessages(step); - client.theMsg['trigger'] = response.trigger - var resps = require('./flow/response.json'); - nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); - client.theMsg['replyMessage'] = nuevaRespuesta - var pasoRequerido = resps[step].pasoRequerido; - // console.log('NUEVA RESPUESTA=', nuevaRespuesta) - - if(nuevaRespuesta.search("/URL")>-1){ - // Necesita instalado axios version 0.27.2 (npm i axios@0.27.2), si se instala una version mas nueva manda error de "GET no definido" o algo asi. - // console.log(theUrl); - console.log("========== GET URL ============"); - /* - ============================================================================ - ======================== DESBLOQUEO DE USUARIOS ========================== - ============================================================================ - */ - console.log('PASOREQUERIDO=', pasoRequerido) - if(pasoRequerido=="soporte"){ - // var theUrl=nuevaRespuesta.substring(5).replace("XXPARAM1XX",newBody); - // const RES = await axios.get(theUrl).then(function (response) { - // const { AffectedRows } = response.data['respuesta'][0] - // console.log('AFFECTED_ROWS = ', AffectedRows) - // if(response.data['respuesta'][0]['AffectedRows']=="1"){ - // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); - // } - // else{ - // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); - // } - // return response - // // console.log('AXIOS RES=', response) - // }).catch(function (error) { - // console.log(error); - // return error - // }); - // console.log('RES=', RES) + const step = await getMessages(message, from); + client.theMsg['step'] = step + if (step) { + // console.log("Entramos a STEP") + const response = await responseMessages(step); + client.theMsg['trigger'] = response.trigger + var resps = require('./flow/response.json'); + nuevaRespuesta = remplazos(resps[step].replyMessage.join(''), client); + client.theMsg['replyMessage'] = nuevaRespuesta + // var pasoRequerido = resps[step].pasoRequerido; + if(body=='traeXLS'){ + const rows = await leeXLSDatos('x') + console.log("RESULTADOS:") + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); } + async function retardo() { + for (sp=1;sp setTimeout(resolve, ms)); + } + async function retardo() { + for (sp=0;sp client.on('message', async msg => { return } - /** * Llama el API para desbloquear un usuario. * @param {*} ctx El objeto del mensaje. @@ -478,6 +501,36 @@ listenMessage = () => client.on('message', async msg => { return error }); } + + /** + * Llama el API para desbloquear el usuario. + * + * @param {*} theURL El URL para llamar al API + * @param {*} step + */ + async function desbloqueaUsuario2(theUrl, step) { + // const {from} = client.theMsg + // const RES = await axios.get(theUrl).then(function (response) { + // const { AffectedRows } = response.data['respuesta'][0] + // console.log('AFFECTED_ROWS = ', AffectedRows) + // if(response.data['respuesta'][0]['AffectedRows']=="1"){ + // sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); + // } + // else{ + // sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); + // } + // return response + // }).catch(function (error) { + // console.log(error); + // return error + // }); + } + + // #################################################################################################################### + // ############################## INICIAN FUNCIONES PARA MANEJO DE PARAMETROS ##################################### + // ############################## EN EL RESPONSE.JSON ##################################### + // #################################################################################################################### + /* * Si quieres ejecutar una función. */ @@ -487,25 +540,25 @@ listenMessage = () => client.on('message', async msg => { eval(laFuncion) // return } - if(response.hasOwnProperty('urlXXXXXXX') && response.hasOwnProperty('values')){ - let theURL = response.url; - let url0 = theURL - let vals = response.values // Traemos los valores desde el response.json - let j = theURL.split('j=')[1] // Traemos el JSON del URL. - let j2 = JSON.parse(j) - let cont = 0 - const { params } = j2 // Traemos los parametros del JSON. - console.log('PARAMS=', params, params['par1'], Object.keys(params).length) - let url2 - for (const par in params) { // Remplazamos los valores en lo parametros. - console.log(`${par}: ${params[par]}, ${cont}: ${remplazos(vals[cont], client)}`); - if(cont==0){url2=url0.replace(params[par], remplazos(vals[cont], client));} - else {url2=url2.replace(params[par], remplazos(vals[cont], client));} - cont++ - } - // console.log('THE_URL=', url2) - desbloqueaUsuario2(url2, step) //Llamamos al API para desbloquear el usuario. - return + if(response.hasOwnProperty('url') && response.hasOwnProperty('values')){ + // let theURL = response.url; + // let url0 = theURL + // let vals = response.values // Traemos los valores desde el response.json + // let j = theURL.split('j=')[1] // Traemos el JSON del URL. + // let j2 = JSON.parse(j) + // let cont = 0 + // const { params } = j2 // Traemos los parametros del JSON. + // console.log('PARAMS=', params, params['par1'], Object.keys(params).length) + // let url2 + // for (const par in params) { // Remplazamos los valores en lo parametros. + // console.log(`${par}: ${params[par]}, ${cont}: ${remplazos(vals[cont], client)}`); + // if(cont==0){url2=url0.replace(params[par], remplazos(vals[cont], client));} + // else {url2=url2.replace(params[par], remplazos(vals[cont], client));} + // cont++ + // } + // // console.log('THE_URL=', url2) + // desbloqueaUsuario2(url2, step) //Llamamos al API para desbloquear el usuario. + // return } /** * Si quieres enviar imagen. @@ -551,98 +604,24 @@ listenMessage = () => client.on('message', async msg => { /** * Si quieres enviar botones o listas */ - if(response.hasOwnProperty('actions')){ - const { actions } = response; - // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); - if(actions['sections'] === undefined){ //Botones - console.log("Botones") - await sendMessageButton(client, from, null, actions); + if(response.hasOwnProperty('actions')){ + const { actions } = response; + // console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON/LIST +++++++++++++++++++++++++++++++++++"); + if(actions['sections'] === undefined){ //Botones + // console.log("Botones") + await sendMessageButton(client, from, null, actions); } else { //Listas - console.log("Listas") - // console.log(actions) + // console.log("Listas") await sendMessageList(client, from, null, actions); } } return } - if(body=='trae'){ - const rows = await leeXLSDatos('x') - console.log("RESULTADOS:") - // d.forEach(row => async function() { - // console.log(row.nombre, row.edad, row.sexo) - // client.sendMessage(from, `Hola ${row.nombre}, recuerda que tienes un adeudo pendiente`) - // }) - function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - async function retardo() { - for (sp=1;sp setTimeout(resolve, ms)); - } - async function retardo() { - for (sp=0;sp client.on('message_create', async botMsg => { } }); +// #################################################################################################################### +// ############################## INICIAN FUNCIONES PARA LA CREACION DEL CLIENTE #################################### +// ############################## DE WHATSAPP-WEB.JS #################################### +// #################################################################################################################### + client = new Client({ authStrategy: new LocalAuth(), puppeteer: { headless: true, args: ['--no-sandbox','--disable-setuid-sandbox'] } @@ -729,40 +714,32 @@ client.initialize(); server.listen(port, () => { console.log(`El server esta listo en el puerto ${port}`); }) + checkEnvFile(); - /** - * Llama el API para desbloquear el usuario. - * - * @param {*} theURL El URL para llamar al API - * @param {*} step +// #################################################################################################################### +// ############################## INICIAN FUNCIONES VARIAS #################################### +// #################################################################################################################### + +/** + * Regresa un número random entre los parametros min y max dados. + * @param {*} min + * @param {*} max + * @returns */ - async function desbloqueaUsuario2(theUrl, step) { - const {from} = client.theMsg - const RES = await axios.get(theUrl).then(function (response) { - const { AffectedRows } = response.data['respuesta'][0] - console.log('AFFECTED_ROWS = ', AffectedRows) - if(response.data['respuesta'][0]['AffectedRows']=="1"){ - sendMessage(client, from, "Listo, usuario *"+response.data['params']['par1']+"* desbloqueado, por favor *cerrar navegadores* y reingresar.", response.trigger, step); - } - else{ - sendMessage(client, from, "El usuario *"+response.data['params']['par1']+"* no *existe* o esta dado de *baja*, por favor revisarlo y volver a intentar.", response.trigger, step); - } - return response - }).catch(function (error) { - console.log(error); - return error - }); - // const r = await axios.get(theUrl).then(function (response) { - // console.log('AXIOS RES=', response) - // }).catch(function (error) { - // console.log(error); - // return error - // }) - // return Promise.resolve(r) +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive } - + +/** + * Revisa que exista el archivo "chats/numero.json" + * @param {*} theFile + * @returns + */ function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json" + const fs = require('fs'); if (fs.existsSync(theFile)) { // console.log("Si existe el archivo "+ theFile); var h = true; diff --git a/flow/response.json b/flow/response.json index eff337f..f171a64 100644 --- a/flow/response.json +++ b/flow/response.json @@ -48,7 +48,7 @@ "trigger":null }, "opcion1":{ - "keywords": "1", + "keywords": ["1"], "replyMessage":[ { "mensaje":[ @@ -68,7 +68,7 @@ "goto":"menu" }, "opcion2":{ - "keywords": "2", + "keywords": ["2"], "replyMessage":[ { "mensaje":[ @@ -86,12 +86,12 @@ "goto":"menu" }, "opcion3":{ - "keywords": "3", + "keywords": ["3"], "replyMessage":[ { "mensaje":[ "Seleccionaste la *opción 3*\n", - "Por favor dame tu nombre.\n", + "*Por favor dame tu nombre.*\n", "Aquí vamos a aceptar *cualquier* texto, porque en el *initial.json* tenemos keywords : \"*\" (un asterisco en expresiones regulares quiere decir *\"cualquier cosa\"*)", "Y en *response.json* en la opción correspondiente tenemos \"pasoRequerido\" : \"menu\", que quiere decir que SOLO se va a disparar cuando el paso anterior sea \"menu\"." ] @@ -180,7 +180,7 @@ } }, "lista":{ - "keywords": "4", + "keywords": ["4"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de listas"] @@ -207,7 +207,7 @@ "goto":"menu" }, "botones":{ - "keywords": "5", + "keywords": ["5"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de botones"] @@ -306,7 +306,7 @@ "goto":"menu" }, "botonespaq3":{ - "keywords": "6", + "keywords": ["6"], "replyMessage":[ { "mensaje":["*%saludo%*, este es un ejemplo de botones y regExp"] From 16698cc4e36abbd156a1ed15440e18b2ea0b929e Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 02:52:29 -0600 Subject: [PATCH 12/19] Update README.md --- README.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 57984b6..fd6f01f 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ "pasoRequerido":"menu" } ``` - - Permite **expresiones regulares** en las palabras predefinidas en el initial.json. + - Permite **expresiones regulares** en las palabras predefinidas en el **initial.json**. - Si queremos usar RegExp, en los "keywords" de **inital.json**, en lugar de un arreglo, debemos usar un string ( quitamos los [] ) y en él usamos "*" para significar cualquier texto y "|" para significar "OR", esto nos permite ser mas flexibles con los "keywords", por ejemplo, si queremos que el mensaje pueda decir: @@ -62,7 +62,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ - Ponemos __%dia_semana%__ para que aparezca "lunes, martes, miercoles, etc" dependiendo del día de la semana. - Ponemos __%msjant_XX%__ para que aparezca el mensaje xx anterior, es decir, si quieres mostrar el texto de 2 mensajes anteriores se pone %msjant_2%. - etc, etc, se pueden agregar mas remplazos en la funcion "remplazos" en el archivo "adapter\index.js". - - Permite el envío de **multiples mensajes** definidos en la **misma respuesta** del **response.json**. (Esta modificación se la robe por completo a [KJoaquin](https://github.com/KJoaquin), el lo solucionó [aquí](https://github.com/codigoencasa/bot-whatsapp/issues/111#issuecomment-1353504575) 🙌🏽 y yo solo lo adapté a mi repo!) + - Permite el envío de **multiples mensajes** definidos en la **misma respuesta** del **response.json**. (Esta modificación se la robe por completo a [KJoaquin](https://github.com/KJoaquin), el lo solucionó [aquí](https://github.com/codigoencasa/bot-whatsapp/issues/111#issuecomment-1353504575) 🙌🏽 y yo solo lo adapté a mi repositorio!.) Antes: ```json @@ -88,7 +88,31 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ } } ``` - + - Permite conectarse a APIs, por ejemplo: Google Sheets, Excel y cualquier otra API que se pueda llamar desde una funcion, esto se hace agregando el parametro "funcion" al **response.json**. + ``` + "Desbloqueo":{ + "keywords": "desbloqueo", + "replyMessage":[ + "Mensaje de desbloqueo de usuarios." + ], + "funcion":"getFakeHTTP", //esta linea ejecuta la funcion. + "media":null, + "trigger":null, + "pasoRequerido":"soporte" + } + + ``` + - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "keywords" al **response.json** + - Se puede especificar que al terminar un paso, el flujo se vaya automaticamente a otro, por ejemplo, si tengo un flujo de tres pasos y quiero que al terminar el tercer paso, se regrese automaticamente al primero, agrego el parametro "goto" al **response.json** del tercer paso y pongo el nombre del paso 1. + ``` + "paso3":{ + "keywords": ["zapatos"], + "replyMessage":["Gracias por tu compra"], + "media":null, + "trigger":null, + "goto":"paso1" + }, + ``` - Las modificaciones están enfocadas al uso de los archivos __initial.json__ y __response.json__, yo no uso MySQL o DialogFlow, así que no sé si las modificaciones funcionen con esos modulos, en particular el __remplazo %msjant_XX%__ depende de los archivos __JSON__ que se crean en el directorio "chats". - Tiene agregado el parche de **botones y listas**, así que funcionan sin problema (las listas no funcionan si el bot esta ligado a un número que use **Whatsapp Business**). - Tiene los ultimos parches de **DialogFlow** (27-dic-2022) (When Dialogflow asks for an Image, then **Upload it to Google Drive** and then generate Shared Link) From 754f0259d46497140fce87703fd7703fbcb335a4 Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 02:55:23 -0600 Subject: [PATCH 13/19] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd6f01f..fa6559b 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ } } ``` - - Permite conectarse a APIs, por ejemplo: Google Sheets, Excel y cualquier otra API que se pueda llamar desde una funcion, esto se hace agregando el parametro "funcion" al **response.json**. + - Permite conectarse a **APIs**, por ejemplo: Google Sheets, Excel y cualquier otra API que se pueda llamar desde una funcion, esto se hace agregando el parametro "funcion" al **response.json**. ``` "Desbloqueo":{ "keywords": "desbloqueo", @@ -103,7 +103,8 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ ``` - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "keywords" al **response.json** - - Se puede especificar que al terminar un paso, el flujo se vaya automaticamente a otro, por ejemplo, si tengo un flujo de tres pasos y quiero que al terminar el tercer paso, se regrese automaticamente al primero, agrego el parametro "goto" al **response.json** del tercer paso y pongo el nombre del paso 1. + + - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tengo un flujo de tres pasos y quiero que al terminar el tercer paso, se regrese automaticamente al primero, agrego el parametro "goto" al **response.json** del tercer paso y pongo el nombre del paso 1. ``` "paso3":{ "keywords": ["zapatos"], From 2fd9226770fc28385c516e76d7371e38f2f4ac1b Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 02:57:01 -0600 Subject: [PATCH 14/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa6559b..081acc2 100644 --- a/README.md +++ b/README.md @@ -102,9 +102,9 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ } ``` - - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "keywords" al **response.json** + - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "keywords" del **initial.json** al **response.json** - - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tengo un flujo de tres pasos y quiero que al terminar el tercer paso, se regrese automaticamente al primero, agrego el parametro "goto" al **response.json** del tercer paso y pongo el nombre del paso 1. + - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tengo un flujo de tres pasos, y quiero que al terminar el tercer paso se regrese automaticamente al primero, agrego el parametro __"goto"__ al **response.json** del tercer paso y pongo el nombre del paso 1. ``` "paso3":{ "keywords": ["zapatos"], From e5c0c0e7243638e37005f6910b36cf2759700149 Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 03:02:40 -0600 Subject: [PATCH 15/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 081acc2..488bfb9 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ ``` - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "keywords" del **initial.json** al **response.json** - - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tengo un flujo de tres pasos, y quiero que al terminar el tercer paso se regrese automaticamente al primero, agrego el parametro __"goto"__ al **response.json** del tercer paso y pongo el nombre del paso 1. + - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tenemos un flujo de tres pasos, y queremos que al terminar el tercer paso se regrese automaticamente al primero, agregamos el parametro __"goto"__ al **response.json** del tercer paso y ponemos el nombre del paso 1. ``` "paso3":{ "keywords": ["zapatos"], @@ -115,7 +115,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ }, ``` - Las modificaciones están enfocadas al uso de los archivos __initial.json__ y __response.json__, yo no uso MySQL o DialogFlow, así que no sé si las modificaciones funcionen con esos modulos, en particular el __remplazo %msjant_XX%__ depende de los archivos __JSON__ que se crean en el directorio "chats". - - Tiene agregado el parche de **botones y listas**, así que funcionan sin problema (las listas no funcionan si el bot esta ligado a un número que use **Whatsapp Business**). + - Tiene agregado el parche de **botones y listas**, así que funcionan sin problema (las listas no funcionan si el bot esta **ligado** a un número que use **Whatsapp Business**). - Tiene los ultimos parches de **DialogFlow** (27-dic-2022) (When Dialogflow asks for an Image, then **Upload it to Google Drive** and then generate Shared Link) ## INICIA DOCUMENTACION DEL PROYECTO ORIGINAL From 41e0edfb49591d7c4081f8db4f7404f040c85963 Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 03:03:58 -0600 Subject: [PATCH 16/19] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 488bfb9..7d04fdd 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ } } ``` - - Permite conectarse a **APIs**, por ejemplo: Google Sheets, Excel y cualquier otra API que se pueda llamar desde una funcion, esto se hace agregando el parametro "funcion" al **response.json**. + - Permite conectarse a **APIs**, por ejemplo: Google Sheets, Excel y cualquier otra API que se pueda llamar desde una funcion, esto se hace agregando el parametro "```funcion```" al **response.json**. ``` "Desbloqueo":{ "keywords": "desbloqueo", @@ -102,9 +102,9 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ } ``` - - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "keywords" del **initial.json** al **response.json** + - Los archivos **initial.json** y **response.json** se unificaron y ya solo se usa el **response.json**, para esto solo se agrega el parametro "```keywords```" del **initial.json** al **response.json** - - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tenemos un flujo de tres pasos, y queremos que al terminar el tercer paso se regrese automaticamente al primero, agregamos el parametro __"goto"__ al **response.json** del tercer paso y ponemos el nombre del paso 1. + - Se puede especificar que al terminar un paso, el flujo se **vaya automaticamente** a otro, por ejemplo, si tenemos un flujo de tres pasos, y queremos que al terminar el tercer paso se regrese automaticamente al primero, agregamos el parametro "```goto```" al **response.json** del tercer paso y ponemos el nombre del paso 1. ``` "paso3":{ "keywords": ["zapatos"], From 51620a501ab26b6f770012d7fe31c71b971dba4a Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 03:06:15 -0600 Subject: [PATCH 17/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d04fdd..969e227 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https:/ } } ``` - Ahora **replyMessage** debe de contener un arreglo con los mensajes que se van a enviar: + Ahora "```replyMessage```" debe de contener un arreglo con los mensajes que se van a enviar: ```json { "ejemploNuevo":{ From 22de88798fd5c0ea311a4d93053ea29a6aae45cf Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 03:11:27 -0600 Subject: [PATCH 18/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 969e227..fc3c37f 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ El siguiente proyecto se realizó con fines educativos para el canal de [Youtube > [VER](https://github.com/leifermendez/bot-whatsapp/commits/main) ### Busco colaboradores ⭐ -Hola amigos me gusta mucho este proyecto pero por cuestiones de tiempo se me dificulta mantener las actualizaciones si alguno quieres participar en el proyecto escribeme a leifer.contacto@gmail.com +Hola amigos me gusta mucho este proyecto pero por cuestiones de tiempo se me dificulta mantener las actualizaciones si alguno quiere participar en el proyecto escribanme a leifer.contacto@gmail.com #### Acceso rápido > Si tienes una cuenta en __heroku__ puedes desplegar este proyecto con (1 click) @@ -262,7 +262,7 @@ __Listo 😎__ ![](https://i.imgur.com/OSUgljQ.png) -> Ahora deberías obtener un arespuesta por parte del BOT como la siguiente, ademas de esto tambien se crea un archivo excel +> Ahora deberías obtener una respuesta por parte del BOT como la siguiente, ademas de esto tambien se crea un archivo excel con el historial de conversación con el número de tu cliente ![](https://i.imgur.com/lrMLgR8.png) From 9f159eec7a5f5bbdcac180dd719479a45e979b0a Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Tue, 7 Feb 2023 03:14:32 -0600 Subject: [PATCH 19/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc3c37f..e8db7ad 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## Chatbot Whatsapp (OpenSource) -#### Actualizado Diciembre 2022 +#### Actualizado Febrero 2023 Este proyecto es un clon de la **version 1** (legacy) de [Leifer Mendez](https://github.com/leifermendez/bot-whatsapp) y tiene las siguientes modificaciones: