mirror of
https://github.com/cheveguerra/bot-whatsapp.git
synced 2026-04-20 20:49:15 +00:00
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
|
/packages/repl
|
||||||
/packages/*/starters
|
/packages/*/starters
|
||||||
/packages/*/node_modules
|
/packages/*/node_modules
|
||||||
/packages/*/dist
|
/packages/*/dist
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ class CoreClass {
|
|||||||
flowClass
|
flowClass
|
||||||
databaseClass
|
databaseClass
|
||||||
providerClass
|
providerClass
|
||||||
constructor(_flow, _database, _provider) {
|
generalArgs = { blackList: [] }
|
||||||
|
constructor(_flow, _database, _provider, _args) {
|
||||||
this.flowClass = _flow
|
this.flowClass = _flow
|
||||||
this.databaseClass = _database
|
this.databaseClass = _database
|
||||||
this.providerClass = _provider
|
this.providerClass = _provider
|
||||||
|
this.generalArgs = { ...this.generalArgs, ..._args }
|
||||||
|
|
||||||
for (const { event, func } of this.listenerBusEvents()) {
|
for (const { event, func } of this.listenerBusEvents()) {
|
||||||
this.providerClass.on(event, func)
|
this.providerClass.on(event, func)
|
||||||
@@ -70,6 +72,7 @@ class CoreClass {
|
|||||||
const { body, from } = messageCtxInComming
|
const { body, from } = messageCtxInComming
|
||||||
let msgToSend = []
|
let msgToSend = []
|
||||||
let fallBackFlag = false
|
let fallBackFlag = false
|
||||||
|
if (this.generalArgs.blackList.includes(from)) return
|
||||||
if (!body) return
|
if (!body) return
|
||||||
if (!body.length) return
|
if (!body.length) return
|
||||||
|
|
||||||
@@ -89,14 +92,18 @@ class CoreClass {
|
|||||||
|
|
||||||
// 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx
|
// 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx
|
||||||
const sendFlow = async (messageToSend, numberOrId) => {
|
const sendFlow = async (messageToSend, numberOrId) => {
|
||||||
|
// [1 Paso] esto esta bien!
|
||||||
|
if (prevMsg?.options?.capture) await cbEveryCtx(prevMsg?.ref)
|
||||||
|
|
||||||
const queue = []
|
const queue = []
|
||||||
for (const ctxMessage of messageToSend) {
|
for (const ctxMessage of messageToSend) {
|
||||||
const delayMs = ctxMessage?.options?.delay || 0
|
const delayMs = ctxMessage?.options?.delay || 0
|
||||||
if (delayMs) await delay(delayMs)
|
if (delayMs) await delay(delayMs)
|
||||||
QueuePrincipal.enqueue(() =>
|
QueuePrincipal.enqueue(() =>
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this.sendProviderAndSave(numberOrId, ctxMessage),
|
this.sendProviderAndSave(numberOrId, ctxMessage).then(
|
||||||
resolveCbEveryCtx(ctxMessage),
|
() => resolveCbEveryCtx(ctxMessage)
|
||||||
|
),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -113,6 +120,7 @@ class CoreClass {
|
|||||||
|
|
||||||
// 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes
|
// 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes
|
||||||
// para evitar bloque de whatsapp
|
// para evitar bloque de whatsapp
|
||||||
|
|
||||||
const flowDynamic = async (
|
const flowDynamic = async (
|
||||||
listMsg = [],
|
listMsg = [],
|
||||||
optListMsg = { limit: 5, fallback: false }
|
optListMsg = { limit: 5, fallback: false }
|
||||||
@@ -122,15 +130,21 @@ class CoreClass {
|
|||||||
|
|
||||||
fallBackFlag = optListMsg.fallback
|
fallBackFlag = optListMsg.fallback
|
||||||
const parseListMsg = listMsg
|
const parseListMsg = listMsg
|
||||||
.map(({ body }, index) =>
|
.map((opt, index) => {
|
||||||
toCtx({
|
const body = typeof opt === 'string' ? opt : opt.body
|
||||||
|
const media = opt?.media ?? null
|
||||||
|
const buttons = opt?.buttons ?? []
|
||||||
|
|
||||||
|
return toCtx({
|
||||||
body,
|
body,
|
||||||
from,
|
from,
|
||||||
keyword: null,
|
keyword: null,
|
||||||
index,
|
index,
|
||||||
|
options: { media, buttons },
|
||||||
})
|
})
|
||||||
)
|
})
|
||||||
.slice(0, optListMsg.limit)
|
.slice(0, optListMsg.limit)
|
||||||
|
|
||||||
for (const msg of parseListMsg) {
|
for (const msg of parseListMsg) {
|
||||||
await this.sendProviderAndSave(from, msg)
|
await this.sendProviderAndSave(from, msg)
|
||||||
}
|
}
|
||||||
@@ -139,7 +153,6 @@ class CoreClass {
|
|||||||
|
|
||||||
// 📄 Se encarga de revisar si el contexto del mensaje tiene callback o fallback
|
// 📄 Se encarga de revisar si el contexto del mensaje tiene callback o fallback
|
||||||
const resolveCbEveryCtx = async (ctxMessage) => {
|
const resolveCbEveryCtx = async (ctxMessage) => {
|
||||||
if (prevMsg?.options?.capture) return cbEveryCtx(prevMsg?.ref)
|
|
||||||
if (!ctxMessage?.options?.capture)
|
if (!ctxMessage?.options?.capture)
|
||||||
return await cbEveryCtx(ctxMessage?.ref)
|
return await cbEveryCtx(ctxMessage?.ref)
|
||||||
}
|
}
|
||||||
@@ -153,17 +166,6 @@ class CoreClass {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevMsg?.ref) resolveCbEveryCtx(prevMsg)
|
|
||||||
|
|
||||||
// 📄 [options: callback]: Si se tiene un callback se ejecuta
|
|
||||||
//TODO AQUI
|
|
||||||
// if (!fallBackFlag) {
|
|
||||||
// if (prevMsg?.options?.capture) cbEveryCtx(prevMsg?.ref)
|
|
||||||
// for (const ite of this.flowClass.find(body)) {
|
|
||||||
// if (!ite?.options?.capture) cbEveryCtx(ite?.ref)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa
|
// 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa
|
||||||
if (!fallBackFlag && prevMsg?.options?.nested?.length) {
|
if (!fallBackFlag && prevMsg?.options?.nested?.length) {
|
||||||
const nestedRef = prevMsg.options.nested
|
const nestedRef = prevMsg.options.nested
|
||||||
@@ -173,11 +175,6 @@ class CoreClass {
|
|||||||
|
|
||||||
msgToSend = this.flowClass.find(body, false, flowStandalone) || []
|
msgToSend = this.flowClass.find(body, false, flowStandalone) || []
|
||||||
|
|
||||||
// //TODO AQUI
|
|
||||||
// for (const ite of msgToSend) {
|
|
||||||
// cbEveryCtx(ite?.ref)
|
|
||||||
// }
|
|
||||||
|
|
||||||
sendFlow(msgToSend, from)
|
sendFlow(msgToSend, from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -225,5 +222,24 @@ class CoreClass {
|
|||||||
this.continue(null, responde.ref)
|
this.continue(null, responde.ref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Funcion dedicada a enviar el mensaje sin pasar por el flow
|
||||||
|
* (dialogflow)
|
||||||
|
* @param {*} messageToSend
|
||||||
|
* @param {*} numberOrId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
sendFlowSimple = async (messageToSend, numberOrId) => {
|
||||||
|
const queue = []
|
||||||
|
for (const ctxMessage of messageToSend) {
|
||||||
|
const delayMs = ctxMessage?.options?.delay || 0
|
||||||
|
if (delayMs) await delay(delayMs)
|
||||||
|
QueuePrincipal.enqueue(() =>
|
||||||
|
this.sendProviderAndSave(numberOrId, ctxMessage)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Promise.all(queue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = CoreClass
|
module.exports = CoreClass
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ const { addKeyword, addAnswer, addChild, toSerialize } = require('./io/methods')
|
|||||||
* @param {*} args
|
* @param {*} args
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const createBot = async ({ flow, database, provider }) =>
|
const createBot = async ({ flow, database, provider }, args = {}) =>
|
||||||
new CoreClass(flow, database, provider)
|
new CoreClass(flow, database, provider, args)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crear instancia de clase Io (Flow)
|
* Crear instancia de clase Io (Flow)
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ const { generateRef, generateRefSerialize } = require('../../utils/hash')
|
|||||||
* @param options {media:string, buttons:[], capture:true default false}
|
* @param options {media:string, buttons:[], capture:true default false}
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const toCtx = ({ body, from, prevRef, index }) => {
|
const toCtx = ({ body, from, prevRef, options = {}, index }) => {
|
||||||
return {
|
return {
|
||||||
ref: generateRef(),
|
ref: generateRef(),
|
||||||
keyword: prevRef,
|
keyword: prevRef,
|
||||||
answer: body,
|
answer: body,
|
||||||
options: {},
|
options: options ?? {},
|
||||||
from,
|
from,
|
||||||
refSerialize: generateRefSerialize({ index, answer: body }),
|
refSerialize: generateRefSerialize({ index, answer: body }),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bot-whatsapp/bot",
|
"name": "@bot-whatsapp/bot",
|
||||||
"version": "0.0.66-alpha.0",
|
"version": "0.0.73-alpha.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./lib/bundle.bot.cjs",
|
"main": "./lib/bundle.bot.cjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
29
packages/bot/tests/flow.class.test.js
Normal file
29
packages/bot/tests/flow.class.test.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
const { test } = require('uvu')
|
||||||
|
const assert = require('uvu/assert')
|
||||||
|
const FlowClass = require('../io/flow.class')
|
||||||
|
const MockProvider = require('../../../__mocks__/mock.provider')
|
||||||
|
const { addKeyword } = require('../index')
|
||||||
|
|
||||||
|
test(`[FlowClass] Probando instanciamiento de clase`, async () => {
|
||||||
|
const MOCK_FLOW = addKeyword('hola').addAnswer('Buenas!')
|
||||||
|
const flowClass = new FlowClass([MOCK_FLOW])
|
||||||
|
assert.is(flowClass instanceof FlowClass, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test(`[FlowClass] Probando find`, async () => {
|
||||||
|
const MOCK_FLOW = addKeyword('hola').addAnswer('Buenas!')
|
||||||
|
const flowClass = new FlowClass([MOCK_FLOW])
|
||||||
|
|
||||||
|
flowClass.find('hola')
|
||||||
|
assert.is(flowClass instanceof FlowClass, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test(`[FlowClass] Probando findBySerialize`, async () => {
|
||||||
|
const MOCK_FLOW = addKeyword('hola').addAnswer('Buenas!')
|
||||||
|
const flowClass = new FlowClass([MOCK_FLOW])
|
||||||
|
|
||||||
|
flowClass.findBySerialize('')
|
||||||
|
assert.is(flowClass instanceof FlowClass, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test.run()
|
||||||
@@ -117,7 +117,7 @@ class DialogFlowCXContext extends CoreClass {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.sendFlow(listMessages, from)
|
this.sendFlowSimple(listMessages, from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class DialogFlowContext extends CoreClass {
|
|||||||
...customPayload,
|
...customPayload,
|
||||||
answer: fields?.answer?.stringValue,
|
answer: fields?.answer?.stringValue,
|
||||||
}
|
}
|
||||||
this.sendFlow([ctxFromDX], from)
|
this.sendFlowSimple([ctxFromDX], from)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class DialogFlowContext extends CoreClass {
|
|||||||
answer: queryResult?.fulfillmentText,
|
answer: queryResult?.fulfillmentText,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendFlow([ctxFromDX], from)
|
this.sendFlowSimple([ctxFromDX], from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Esta funcion se utliza para responder un mensaje despues del `addKeyword()`
|
|||||||
- delay: 0 (milisegundos)
|
- delay: 0 (milisegundos)
|
||||||
- media: url de imagen
|
- media: url de imagen
|
||||||
- buttons: array `[{body:'Boton1'}, {body:'Boton2'}, {body:'Boton3'}]`
|
- buttons: array `[{body:'Boton1'}, {body:'Boton2'}, {body:'Boton3'}]`
|
||||||
- capture: false (para esperar respuesta)
|
- capture: true (para esperar respuesta)
|
||||||
- child: Objecto tipo flujo o arra de flujos hijos
|
- child: Objecto tipo flujo o arra de flujos hijos
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|||||||
Reference in New Issue
Block a user