Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: next version 0.1.32 #840

Merged
merged 29 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4b98309
docs: :zap: improve docs wit Ozzy
leifermendez Jun 1, 2023
50effc1
docs: :memo: page `addKeyword`
leifermendez Jun 2, 2023
25b8031
docs: :memo: page `addAnswer`
leifermendez Jun 2, 2023
05478ba
docs: :memo: gotoFlow doc
leifermendez Jun 4, 2023
fff26d5
Adding @bot/provider documentation: meta/twilio/baileys/venom/wppconn…
ozzyoss77 Jun 22, 2023
a83aeed
Merge branch 'feat/docs-improve' into tmp/docs
ozzyoss77 Jun 22, 2023
12bc843
Merge pull request #775 from ozzyoss77/tmp/docs
leifermendez Jun 23, 2023
260c240
fix(provider): 🐛Fixed get state message poll
andresayac Aug 13, 2023
8f90ee8
fix(provider): 🐛Fixed Baileys body Undefined sometimes
andresayac Aug 13, 2023
0f792da
fix(provider): 🐛Fixed get data mysql for baileys
andresayac Aug 19, 2023
c358d58
Merge pull request #827 from codigoencasa/release/production
leifermendez Aug 26, 2023
e5d5f36
chore: bug leak
leifermendez Aug 27, 2023
8c58147
chore: :zap: fix
leifermendez Aug 27, 2023
dd82adc
chore: :zap: fix
leifermendez Aug 27, 2023
d7bb161
test: more test unit
leifermendez Aug 27, 2023
f0e28a5
🚑️ Now field keyword at adapterMySQL/history can be NULL
Trystan4861 Aug 29, 2023
cd34679
Merge pull request #831 from Trystan4861/TRY-0003-MySQL-NULL-Keyword
leifermendez Aug 29, 2023
e298b54
feat: Integrate 'capture_only_intended' flag for silent execution in …
gerrcass Aug 29, 2023
e2043a7
Merge pull request #832 from gerrcass/feat/addanswer-capture
leifermendez Aug 31, 2023
56f0f46
Merge pull request #836 from codigoencasa/feat/middleware
leifermendez Aug 31, 2023
dba52ad
chore: new addAction capture
leifermendez Aug 31, 2023
9a05f23
Merge pull request #808 from andresayac/dev-baileys-fix-body-undifined
leifermendez Aug 31, 2023
4ad51d4
Merge commit '9a05f23e21868008b40cf16164990163275a4e6d' into dev
leifermendez Aug 31, 2023
08d5cdc
Merge pull request #807 from andresayac/dev-baileys-fix-getMessage
leifermendez Aug 31, 2023
721e57e
Merge branch 'dev' of github.com:codigoencasa/bot-whatsapp into dev
leifermendez Aug 31, 2023
b52e27b
chore: new addAction capture
leifermendez Aug 31, 2023
cd68e70
docs: update
leifermendez Aug 31, 2023
ed0be7b
chore: next version 0.1.32
leifermendez Aug 31, 2023
df75e5f
Merge pull request #838 from codigoencasa/dev
leifermendez Aug 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions __test__/0.1.6-case.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const { suite } = require('uvu')
const assert = require('uvu/assert')
const { addKeyword, createBot, createFlow, EVENTS } = require('../packages/bot/index')
const { setup, clear, delay } = require('../__mocks__/env')
const { generateRefprovider } = require('../packages/provider/common/hash')

const fakeHTTP = async (fakeData = []) => {
await delay(50)
const data = fakeData.map((u) => ({ body: `${u}` }))
return Promise.resolve(data)
}

const suiteCase = suite('EVENTS:')

suiteCase.before.each(setup)
suiteCase.after.each(clear)

suiteCase(`WELCOME`, async ({ database, provider }) => {
const flow = addKeyword(EVENTS.WELCOME).addAnswer('Bievenido')

createBot({
database,
provider,
flow: createFlow([flow]),
})

await provider.delaySendMessage(0, 'message', {
from: '000',
body: 'hola',
})

await delay(100)
const getHistory = database.listHistory.map((i) => i.answer)

assert.is('Bievenido', getHistory[0])
})

suiteCase(`MEDIA`, async ({ database, provider }) => {
const flow = addKeyword(EVENTS.MEDIA).addAnswer('media recibido')

createBot({
database,
provider,
flow: createFlow([flow]),
})

await provider.delaySendMessage(0, 'message', {
from: '000',
body: generateRefprovider('_event_media_'),
})
await delay(100)
const getHistory = database.listHistory.map((i) => i.answer)

assert.is('media recibido', getHistory[0])
})

suiteCase(`LOCATION`, async ({ database, provider }) => {
const flow = addKeyword(EVENTS.LOCATION).addAnswer('location recibido')

createBot({
database,
provider,
flow: createFlow([flow]),
})

await provider.delaySendMessage(0, 'message', {
from: '000',
body: generateRefprovider('_event_location_'),
})
await delay(100)
const getHistory = database.listHistory.map((i) => i.answer)

assert.is('location recibido', getHistory[0])
})

suiteCase(`DOCUMENT`, async ({ database, provider }) => {
const flow = addKeyword(EVENTS.DOCUMENT).addAnswer('document recibido')

createBot({
database,
provider,
flow: createFlow([flow]),
})

await provider.delaySendMessage(0, 'message', {
from: '000',
body: generateRefprovider('_event_document_'),
})
await delay(100)
const getHistory = database.listHistory.map((i) => i.answer)

assert.is('document recibido', getHistory[0])
})

suiteCase(`VOICE_NOTE`, async ({ database, provider }) => {
const flow = addKeyword(EVENTS.VOICE_NOTE).addAnswer('voice recibido')

createBot({
database,
provider,
flow: createFlow([flow]),
})

await provider.delaySendMessage(0, 'message', {
from: '000',
body: generateRefprovider('_event_voice_note_'),
})
await delay(100)
const getHistory = database.listHistory.map((i) => i.answer)

assert.is('voice recibido', getHistory[0])
})

suiteCase.run()
File renamed without changes.
46 changes: 46 additions & 0 deletions __test__/0.1.8-case.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const { suite } = require('uvu')
const assert = require('uvu/assert')
const { addKeyword, createBot, createFlow } = require('../packages/bot/index')
const { setup, clear, delay } = require('../__mocks__/env')

const suiteCase = suite('Flujo: addAction (capture)')

suiteCase.before.each(setup)
suiteCase.after.each(clear)

suiteCase(`Debe ejecutar accion con captura`, async ({ database, provider }) => {
const flujoPrincipal = addKeyword(['hola'])
.addAction(async (_, { flowDynamic }) => {
return flowDynamic('Buenas! ¿Cual es tu nombre?')
})
.addAction({ capture: true }, async (ctx, { flowDynamic, state }) => {
state.update({ name: ctx.body })
return flowDynamic(`Gracias por tu nombre!: ${ctx.body}`)
})
.addAnswer('Chao!')

await createBot({
database,
flow: createFlow([flujoPrincipal]),
provider,
})

await provider.delaySendMessage(0, 'message', {
from: '000',
body: 'hola',
})

await provider.delaySendMessage(50, 'message', {
from: '000',
body: 'Leifer',
})

await delay(1000)
const getHistory = database.listHistory.map((i) => i.answer)
assert.is('Buenas! ¿Cual es tu nombre?', getHistory[0])
assert.is('Gracias por tu nombre!: Leifer', getHistory[3])
assert.is('Chao!', getHistory[4])
assert.is(undefined, getHistory[5])
})

suiteCase.run()
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/root",
"version": "0.1.30",
"version": "0.1.31",
"description": "Bot de wahtsapp open source para MVP o pequeños negocios",
"main": "app.js",
"private": true,
Expand Down
93 changes: 66 additions & 27 deletions packages/bot/core/core.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const Queue = require('../utils/queue')
const { LIST_REGEX } = require('../io/events')
const SingleState = require('../context/state.class')
const GlobalState = require('../context/globalState.class')
const { generateTime } = require('../utils/hash')

const logger = new Console({
stdout: createWriteStream(`${process.cwd()}/core.class.log`),
Expand Down Expand Up @@ -157,6 +158,7 @@ class CoreClass {
// 📄 Limpiar cola de procesos
const clearQueue = () => {
this.queuePrincipal.clearQueue(from)
return
}

// 📄 Finalizar flujo
Expand All @@ -171,7 +173,9 @@ class CoreClass {
}

// 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx
const sendFlow = async (messageToSend, numberOrId, options = { prev: prevMsg }) => {
const sendFlow = async (messageToSend, numberOrId, options = {}) => {
options = { prev: prevMsg, forceQueue: false, ...options }

if (options.prev?.options?.capture) {
await cbEveryCtx(options.prev?.ref)
}
Expand All @@ -186,15 +190,33 @@ class CoreClass {
await delay(delayMs) // Esperar según el retraso configurado
}

logger.log(`[sendQueue_A]: `, ctxMessage)
//TODO el proceso de forzar cola de procsos
if (options?.forceQueue) {
const listIdsRefCallbacks = messageToSend.map((i) => i.ref)

const listProcessWait = this.queuePrincipal.getIdsCallbacs(from)
if (!listProcessWait.length) {
this.queuePrincipal.setIdsCallbacks(from, listIdsRefCallbacks)
} else {
const lastMessage = messageToSend[messageToSend.length - 1]
await this.databaseClass.save({ ...lastMessage, from: numberOrId })
if (listProcessWait.includes(lastMessage.ref)) {
this.queuePrincipal.clearQueue(from)
}
}
}

try {
await this.queuePrincipal.enqueue(from, async () => {
// Usar async en la función pasada a enqueue
await this.sendProviderAndSave(numberOrId, ctxMessage)
logger.log(`[QUEUE_SE_ENVIO]: `, ctxMessage)
await resolveCbEveryCtx(ctxMessage)
})
await this.queuePrincipal.enqueue(
from,
async () => {
// Usar async en la función pasada a enqueue
await this.sendProviderAndSave(numberOrId, ctxMessage)
logger.log(`[QUEUE_SE_ENVIO]: `, ctxMessage)
await resolveCbEveryCtx(ctxMessage)
},
ctxMessage.ref
)
} catch (error) {
logger.error(`Error al encolar: ${error.message}`)
return Promise.reject
Expand All @@ -215,12 +237,10 @@ class CoreClass {
const flowStandaloneChild = this.flowClass.getFlowsChild()
const nextChildMessages =
(await this.flowClass.find(refToContinueChild?.ref, true, flowStandaloneChild)) || []
if (nextChildMessages?.length) return await sendFlow(nextChildMessages, from, { prev: undefined })
}
if (nextChildMessages?.length)
return exportFunctionsSend(() => sendFlow(nextChildMessages, from, { prev: undefined }))

if (!isContinueFlow) {
await sendFlow(filterNextFlow, from, { prev: undefined })
return
return exportFunctionsSend(() => sendFlow(filterNextFlow, from, { prev: undefined }))
}
}
// 📄 [options: fallBack]: esta funcion se encarga de repetir el ultimo mensaje
Expand Down Expand Up @@ -269,13 +289,14 @@ class CoreClass {
const parseListMsg = listMsg.map((opt, index) => createCtxMessage(opt, index))

if (endFlowFlag) return
this.queuePrincipal.setFingerTime(from, generateTime()) //aqui debeo decirle al sistema como que finalizo el flujo
for (const msg of parseListMsg) {
const delayMs = msg?.options?.delay ?? this.generalArgs.delay ?? 0
if (delayMs) await delay(delayMs)
await this.sendProviderAndSave(from, msg)
}

if (options?.continue) await continueFlow()
if (options?.continue) await continueFlow(generateTime())
return
}

Expand Down Expand Up @@ -313,11 +334,27 @@ class CoreClass {
await this.flowClass.allCallbacks[inRef](messageCtxInComming, argsCb)
//Si no hay llamado de fallaback y no hay llamado de flowDynamic y no hay llamado de enflow EL flujo continua
const ifContinue = !flags.endFlow && !flags.fallBack && !flags.flowDynamic
if (ifContinue) await continueFlow()
if (ifContinue) await continueFlow(prevMsg?.options?.nested?.length)

return
}

const exportFunctionsSend = async (cb = () => Promise.resolve()) => {
await cb()
return {
createCtxMessage,
clearQueue,
endFlow,
sendFlow,
continueFlow,
fallBack,
gotoFlow,
flowDynamic,
resolveCbEveryCtx,
cbEveryCtx,
}
}

// 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa
if (!endFlowFlag && prevMsg?.options?.nested?.length) {
const nestedRef = prevMsg.options.nested
Expand All @@ -327,8 +364,7 @@ class CoreClass {

msgToSend = this.flowClass.find(body, false, flowStandalone) || []

await sendFlow(msgToSend, from)
return
return exportFunctionsSend(() => sendFlow(msgToSend, from))
}

// 📄🤘(tiene return) Si el mensaje previo implementa capture
Expand All @@ -337,14 +373,15 @@ class CoreClass {

if (typeCapture === 'boolean' && fallBackFlag) {
msgToSend = this.flowClass.find(refToContinue?.ref, true) || []
await sendFlow(msgToSend, from)
return
return exportFunctionsSend(() => sendFlow(msgToSend, from, { forceQueue: true }))
}
}

msgToSend = this.flowClass.find(body) || []

if (msgToSend.length) return sendFlow(msgToSend, from)
if (msgToSend.length) {
return exportFunctionsSend(() => sendFlow(msgToSend, from))
}

if (!prevMsg?.options?.capture) {
msgToSend = this.flowClass.find(this.generalArgs.listEvents.WELCOME) || []
Expand All @@ -365,7 +402,7 @@ class CoreClass {
msgToSend = this.flowClass.find(this.generalArgs.listEvents.VOICE_NOTE) || []
}
}
return sendFlow(msgToSend, from)
return exportFunctionsSend(() => sendFlow(msgToSend, from, { forceQueue: true }))
}

/**
Expand All @@ -377,18 +414,16 @@ class CoreClass {
sendProviderAndSave = async (numberOrId, ctxMessage) => {
try {
const { answer } = ctxMessage
logger.log(`[sendProviderAndSave]: `, ctxMessage)
if (answer && answer.length && answer !== '__call_action__') {
await this.providerClass.sendMessage(numberOrId, answer, ctxMessage)
logger.log(`[providerClass.sendMessage]: `, ctxMessage)
if (answer !== '__capture_only_intended__') {
await this.providerClass.sendMessage(numberOrId, answer, ctxMessage)
}
await this.databaseClass.save({ ...ctxMessage, from: numberOrId })
logger.log(`[databaseClass.save]: `, ctxMessage)
}

return Promise.resolve
} catch (err) {
logger.log(`[ERROR.save]: `, ctxMessage)
console.log('ERROR:Enviando')
return Promise.reject
}
}
Expand Down Expand Up @@ -419,7 +454,11 @@ class CoreClass {
for (const ctxMessage of messageToSend) {
const delayMs = ctxMessage?.options?.delay ?? this.generalArgs.delay ?? 0
if (delayMs) await delay(delayMs)
await this.queuePrincipal.enqueue(numberOrId, () => this.sendProviderAndSave(numberOrId, ctxMessage))
await this.queuePrincipal.enqueue(
numberOrId,
() => this.sendProviderAndSave(numberOrId, ctxMessage),
generateTime()
)
// await queuePromises.dequeue()
}
return Promise.resolve
Expand Down
5 changes: 4 additions & 1 deletion packages/bot/io/methods/addAnswer.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ const addAnswer =
ctx,
ref: ctx.ref,
addAnswer: addAnswer(ctx),
addAction: (cb = () => null) => addAnswer(ctx)('__call_action__', null, cb),
addAction: (cb = () => null, flagCb = () => null) => {
if (typeof cb === 'object') return addAnswer(ctx)('__capture_only_intended__', cb, flagCb)
return addAnswer(ctx)('__call_action__', null, cb)
},
toJson: toJson(ctx),
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/bot/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/bot",
"version": "0.0.156-alpha.0",
"version": "0.0.167-alpha.0",
"description": "",
"main": "./lib/bundle.bot.cjs",
"scripts": {
Expand Down
Loading