From 9f9d8339252d60ebd8852f516240b1d10a6c4266 Mon Sep 17 00:00:00 2001 From: Developer RL Business <66280283+devrlbusiness@users.noreply.github.com> Date: Tue, 17 Jan 2023 09:33:59 -0700 Subject: [PATCH 01/18] Update index.mdx --- packages/docs/src/routes/docs/flows/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx index 7a2171c..2e078d7 100644 --- a/packages/docs/src/routes/docs/flows/index.mdx +++ b/packages/docs/src/routes/docs/flows/index.mdx @@ -55,7 +55,7 @@ Esta funcion se utliza para responder un mensaje despues del `addKeyword()` - delay: 0 (milisegundos) - media: url de imagen - 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 ```js From f6130cf0b91c552cf41254f1807640dcfa26dd32 Mon Sep 17 00:00:00 2001 From: Developer RL Business <66280283+devrlbusiness@users.noreply.github.com> Date: Tue, 17 Jan 2023 09:35:21 -0700 Subject: [PATCH 02/18] Update index.mdx --- packages/docs/src/routes/docs/flows/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx index 7a2171c..2e078d7 100644 --- a/packages/docs/src/routes/docs/flows/index.mdx +++ b/packages/docs/src/routes/docs/flows/index.mdx @@ -55,7 +55,7 @@ Esta funcion se utliza para responder un mensaje despues del `addKeyword()` - delay: 0 (milisegundos) - media: url de imagen - 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 ```js From f5a7de3a003c012e2164e51fff26892cfc3144be Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Fri, 20 Jan 2023 11:58:50 +0100 Subject: [PATCH 03/18] fix(bot): :bug: flowDynamic stranger behaviour --- .gitignore | 1 + packages/bot/core/core.class.js | 25 ++++++------------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 1cc3038..9f6dbbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules +/packages/repl /packages/*/starters /packages/*/node_modules /packages/*/dist diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index e3efc04..e1e16e4 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -89,14 +89,18 @@ class CoreClass { // 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx const sendFlow = async (messageToSend, numberOrId) => { + // [1 Paso] esto esta bien! + if (prevMsg?.options?.capture) await cbEveryCtx(prevMsg?.ref) + const queue = [] for (const ctxMessage of messageToSend) { const delayMs = ctxMessage?.options?.delay || 0 if (delayMs) await delay(delayMs) QueuePrincipal.enqueue(() => Promise.all([ - this.sendProviderAndSave(numberOrId, ctxMessage), - resolveCbEveryCtx(ctxMessage), + this.sendProviderAndSave(numberOrId, ctxMessage).then( + () => resolveCbEveryCtx(ctxMessage) + ), ]) ) } @@ -139,7 +143,6 @@ class CoreClass { // 📄 Se encarga de revisar si el contexto del mensaje tiene callback o fallback const resolveCbEveryCtx = async (ctxMessage) => { - if (prevMsg?.options?.capture) return cbEveryCtx(prevMsg?.ref) if (!ctxMessage?.options?.capture) return await cbEveryCtx(ctxMessage?.ref) } @@ -153,17 +156,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 if (!fallBackFlag && prevMsg?.options?.nested?.length) { const nestedRef = prevMsg.options.nested @@ -173,11 +165,6 @@ class CoreClass { msgToSend = this.flowClass.find(body, false, flowStandalone) || [] - // //TODO AQUI - // for (const ite of msgToSend) { - // cbEveryCtx(ite?.ref) - // } - sendFlow(msgToSend, from) return } From 877252bd4a8a7bbbbf083c3ceaeaeb952b0a1828 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Fri, 20 Jan 2023 12:02:01 +0100 Subject: [PATCH 04/18] fix(bot): :bug: flowDynamic stranger behaviour --- packages/bot/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bot/package.json b/packages/bot/package.json index d3f004e..fe542c1 100644 --- a/packages/bot/package.json +++ b/packages/bot/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/bot", - "version": "0.0.66-alpha.0", + "version": "0.0.73-alpha.0", "description": "", "main": "./lib/bundle.bot.cjs", "scripts": { From 7067b4a80b7938ccfaf1ed141a37d645a1a3a062 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 09:09:16 +0100 Subject: [PATCH 05/18] fix(contexts): :bug: fixed #524 issue --- packages/bot/core/core.class.js | 19 +++++++++++++++++++ .../src/dialogflow-cx/dialogflow-cx.class.js | 2 +- .../src/dialogflow/dialogflow.class.js | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index e1e16e4..ea5eff3 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -212,5 +212,24 @@ class CoreClass { 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 diff --git a/packages/contexts/src/dialogflow-cx/dialogflow-cx.class.js b/packages/contexts/src/dialogflow-cx/dialogflow-cx.class.js index 25bd2a6..2d0ebd2 100644 --- a/packages/contexts/src/dialogflow-cx/dialogflow-cx.class.js +++ b/packages/contexts/src/dialogflow-cx/dialogflow-cx.class.js @@ -117,7 +117,7 @@ class DialogFlowCXContext extends CoreClass { } }) - this.sendFlow(listMessages, from) + this.sendFlowSimple(listMessages, from) } } diff --git a/packages/contexts/src/dialogflow/dialogflow.class.js b/packages/contexts/src/dialogflow/dialogflow.class.js index ebd92bc..6a7cda0 100644 --- a/packages/contexts/src/dialogflow/dialogflow.class.js +++ b/packages/contexts/src/dialogflow/dialogflow.class.js @@ -107,7 +107,7 @@ class DialogFlowContext extends CoreClass { ...customPayload, answer: fields?.answer?.stringValue, } - this.sendFlow([ctxFromDX], from) + this.sendFlowSimple([ctxFromDX], from) return } @@ -115,7 +115,7 @@ class DialogFlowContext extends CoreClass { answer: queryResult?.fulfillmentText, } - this.sendFlow([ctxFromDX], from) + this.sendFlowSimple([ctxFromDX], from) } } From 79cc31a96f6a9836447cc4e6bb1e1521c54183fe Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 09:14:36 +0100 Subject: [PATCH 06/18] fix(contexts): :bug: fixed #524 issue --- packages/bot/tests/flow.class.test.js | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 packages/bot/tests/flow.class.test.js diff --git a/packages/bot/tests/flow.class.test.js b/packages/bot/tests/flow.class.test.js new file mode 100644 index 0000000..b9c55e2 --- /dev/null +++ b/packages/bot/tests/flow.class.test.js @@ -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() From 3c4b1c0fc4b6d98d67c67806d918d3604bb2209b Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 11:52:49 +0100 Subject: [PATCH 07/18] feat(bot): :zap: flowDynamic buttons, media --- packages/bot/core/core.class.js | 13 ++++++++++--- packages/bot/io/methods/toCtx.js | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index ea5eff3..3f20b7b 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -117,6 +117,7 @@ class CoreClass { // 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes // para evitar bloque de whatsapp + const flowDynamic = async ( listMsg = [], optListMsg = { limit: 5, fallback: false } @@ -126,15 +127,21 @@ class CoreClass { fallBackFlag = optListMsg.fallback const parseListMsg = listMsg - .map(({ body }, index) => - toCtx({ + .map((opt, index) => { + const body = typeof opt === 'string' ? opt : opt.body + const media = opt?.media ?? null + const buttons = opt?.buttons ?? [] + + return toCtx({ body, from, keyword: null, index, + options: { media, buttons }, }) - ) + }) .slice(0, optListMsg.limit) + for (const msg of parseListMsg) { await this.sendProviderAndSave(from, msg) } diff --git a/packages/bot/io/methods/toCtx.js b/packages/bot/io/methods/toCtx.js index d29295e..980cbfb 100644 --- a/packages/bot/io/methods/toCtx.js +++ b/packages/bot/io/methods/toCtx.js @@ -5,12 +5,12 @@ const { generateRef, generateRefSerialize } = require('../../utils/hash') * @param options {media:string, buttons:[], capture:true default false} * @returns */ -const toCtx = ({ body, from, prevRef, index }) => { +const toCtx = ({ body, from, prevRef, options = {}, index }) => { return { ref: generateRef(), keyword: prevRef, answer: body, - options: {}, + options: options ?? {}, from, refSerialize: generateRefSerialize({ index, answer: body }), } From 7078dc4c93d01bf90ef08ecb34e89a1abbe16fd2 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 12:02:31 +0100 Subject: [PATCH 08/18] feat(bot): :zap: add blacklist --- packages/bot/core/core.class.js | 5 ++++- packages/bot/index.js | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index 3f20b7b..30e6f4d 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -21,10 +21,12 @@ class CoreClass { flowClass databaseClass providerClass - constructor(_flow, _database, _provider) { + generalArgs = { blackList: [] } + constructor(_flow, _database, _provider, _args) { this.flowClass = _flow this.databaseClass = _database this.providerClass = _provider + this.generalArgs = { ...this.generalArgs, ..._args } for (const { event, func } of this.listenerBusEvents()) { this.providerClass.on(event, func) @@ -70,6 +72,7 @@ class CoreClass { const { body, from } = messageCtxInComming let msgToSend = [] let fallBackFlag = false + if (this.generalArgs.blackList.includes(from)) return if (!body) return if (!body.length) return diff --git a/packages/bot/index.js b/packages/bot/index.js index eb9df24..ac96063 100644 --- a/packages/bot/index.js +++ b/packages/bot/index.js @@ -8,8 +8,8 @@ const { addKeyword, addAnswer, addChild, toSerialize } = require('./io/methods') * @param {*} args * @returns */ -const createBot = async ({ flow, database, provider }) => - new CoreClass(flow, database, provider) +const createBot = async ({ flow, database, provider }, args = {}) => + new CoreClass(flow, database, provider, args) /** * Crear instancia de clase Io (Flow) From 767e0764d61a038d66ae510a97fbe1d5f10736af Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 13:09:41 +0100 Subject: [PATCH 09/18] test: :art: more test e2e --- __test__/01-case.test.js | 41 +++++++++++++++++ __test__/02-case.test.js | 99 ++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 __test__/01-case.test.js create mode 100644 __test__/02-case.test.js diff --git a/__test__/01-case.test.js b/__test__/01-case.test.js new file mode 100644 index 0000000..bce4a42 --- /dev/null +++ b/__test__/01-case.test.js @@ -0,0 +1,41 @@ +const { test } = require('uvu') +const assert = require('uvu/assert') +const MOCK_DB = require('../packages/database/src/mock') +const PROVIDER_DB = require('../packages/provider/src/mock') +const { + addKeyword, + createBot, + createFlow, + createProvider, +} = require('../packages/bot') + +test(`[Caso - 01] Flow Basico`, async () => { + const [VALUE_A, VALUE_B] = ['hola', 'buenas'] + + const flow = addKeyword(VALUE_A).addAnswer(VALUE_B) + const provider = createProvider(PROVIDER_DB) + const database = new MOCK_DB() + + createBot({ + database, + flow: createFlow([flow]), + provider, + }) + + provider.delaySendMessage(100, 'message', { + from: '000', + body: VALUE_A, + }) + + await delay(100) + + const prevMsg = database.getPrevByNumber('000') + + assert.is(prevMsg.answer, VALUE_B) +}) + +test.run() + +function delay(ms) { + return new Promise((res) => setTimeout(res, ms)) +} diff --git a/__test__/02-case.test.js b/__test__/02-case.test.js new file mode 100644 index 0000000..426e110 --- /dev/null +++ b/__test__/02-case.test.js @@ -0,0 +1,99 @@ +const { test } = require('uvu') +const assert = require('uvu/assert') +const MOCK_DB = require('../packages/database/src/mock') +const PROVIDER_DB = require('../packages/provider/src/mock') +const { + addKeyword, + createBot, + createFlow, + createProvider, +} = require('../packages/bot/lib/bundle.bot.cjs') + +/** + * Falsear peticion async + * @param {*} fakeData + * @returns + */ +const fakeHTTP = async (fakeData = []) => { + console.log('⚡ Server request!') + await delay(50) + console.log('⚡ Server return!') + const data = fakeData.map((u, i) => ({ body: `${i + 1} ${u}` })) + console.log(data) + return Promise.resolve(data) +} + +test(`[Caso - 02] Flow Más Complejo`, async () => { + const MOCK_VALUES = [ + 'Bienvenido te envio muchas marcas (5510)', + 'Seleccione marca del auto a cotizar, con el *número* correspondiente', + 'Seleccione la sub marca del auto a cotizar, con el *número* correspondiente:', + 'Los precios rondan:', + ] + const provider = createProvider(PROVIDER_DB) + const database = new MOCK_DB() + + const flujoPrincipal = addKeyword(['hola']) + .addAnswer(MOCK_VALUES[0], null, async (ctx, { flowDynamic }) => { + console.log('execute...') + const data = await fakeHTTP(['Ford', 'GM', 'BMW']) + return flowDynamic(data) + }) + .addAnswer(MOCK_VALUES[1], null, async (ctx, { flowDynamic }) => { + const data = await fakeHTTP(['Ranger', 'Explorer']) + return flowDynamic(data) + }) + .addAnswer(MOCK_VALUES[2], null, async (ctx, { flowDynamic }) => { + const data = await fakeHTTP(['Usado', 'Nuevos']) + return flowDynamic(data) + }) + .addAnswer(MOCK_VALUES[3], null, async (ctx, { flowDynamic }) => { + const data = await fakeHTTP(['1000', '2000', '3000']) + return flowDynamic(data) + }) + + createBot({ + database, + flow: createFlow([flujoPrincipal]), + provider, + }) + + provider.delaySendMessage(0, 'message', { + from: '000', + body: 'hola', + }) + + await delay(1200) + const getHistory = database.listHistory.map((i) => i.answer) + assert.is(MOCK_VALUES[0], getHistory[0]) + + //FlowDynamic + assert.is('1 Ford', getHistory[1]) + assert.is('2 GM', getHistory[2]) + assert.is('3 BMW', getHistory[3]) + + assert.is(MOCK_VALUES[1], getHistory[4]) + + //FlowDynamic + assert.is('1 Ranger', getHistory[5]) + assert.is('2 Explorer', getHistory[6]) + + assert.is(MOCK_VALUES[2], getHistory[7]) + + //FlowDynamic + assert.is('1 Usado', getHistory[8]) + assert.is('2 Nuevos', getHistory[9]) + + assert.is(MOCK_VALUES[3], getHistory[10]) + + //FlowDynamic + assert.is('1 1000', getHistory[11]) + assert.is('2 2000', getHistory[12]) + assert.is('3 3000', getHistory[13]) +}) + +test.run() + +function delay(ms) { + return new Promise((res) => setTimeout(res, ms)) +} diff --git a/package.json b/package.json index 354bc44..2d1061e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "build": "yarn run cli:rollup && yarn run bot:rollup && yarn run provider:rollup && yarn run database:rollup && yarn run contexts:rollup && yarn run create-bot-whatsapp:rollup && yarn run portal:rollup", "copy.lib": "node ./scripts/move.js", "test.unit": "node ./node_modules/uvu/bin.js packages test", - "test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit", + "test.e2e": "node ./node_modules/uvu/bin.js __test__", + "test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit && npm run test.e2e", "test": "npm run test.coverage", "cli": "node ./packages/cli/bin/cli.js", "create": "node ./packages/create-bot-whatsapp/bin/create.js", From 0af74602f52ef4b5164e818f5f4ddfc893c54245 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 13:13:41 +0100 Subject: [PATCH 10/18] test: :art: more test e2e --- __test__/02-case.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__test__/02-case.test.js b/__test__/02-case.test.js index 426e110..f400284 100644 --- a/__test__/02-case.test.js +++ b/__test__/02-case.test.js @@ -7,7 +7,7 @@ const { createBot, createFlow, createProvider, -} = require('../packages/bot/lib/bundle.bot.cjs') +} = require('../packages/bot/index') /** * Falsear peticion async From ac39ac831c1b0d2cf186908d33fc5a01f26236a3 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 14:38:43 +0100 Subject: [PATCH 11/18] test: :art: more test e2e --- __test__/02-case.test.js | 2 +- __test__/03-case.test.js | 44 +++++++++++++++++++++++++++ packages/bot/tests/flow.class.test.js | 1 - 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 __test__/03-case.test.js diff --git a/__test__/02-case.test.js b/__test__/02-case.test.js index f400284..a2a93ec 100644 --- a/__test__/02-case.test.js +++ b/__test__/02-case.test.js @@ -23,7 +23,7 @@ const fakeHTTP = async (fakeData = []) => { return Promise.resolve(data) } -test(`[Caso - 02] Flow Más Complejo`, async () => { +test(`[Caso - 02] Flow (flowDynamic)`, async () => { const MOCK_VALUES = [ 'Bienvenido te envio muchas marcas (5510)', 'Seleccione marca del auto a cotizar, con el *número* correspondiente', diff --git a/__test__/03-case.test.js b/__test__/03-case.test.js new file mode 100644 index 0000000..45c399a --- /dev/null +++ b/__test__/03-case.test.js @@ -0,0 +1,44 @@ +const { test } = require('uvu') +const assert = require('uvu/assert') +const MOCK_DB = require('../packages/database/src/mock') +const PROVIDER_DB = require('../packages/provider/src/mock') +const { + addKeyword, + createBot, + createFlow, + createProvider, +} = require('../packages/bot/index') + +test(`[Caso - 03] Flow puro`, async () => { + const MOCK_VALUES = ['Bienvenido a mi tienda', 'Como estas?'] + + const provider = createProvider(PROVIDER_DB) + const database = new MOCK_DB() + + const flujoPrincipal = addKeyword(['hola']) + .addAnswer(MOCK_VALUES[0]) + .addAnswer(MOCK_VALUES[1]) + + createBot({ + database, + flow: createFlow([flujoPrincipal]), + provider, + }) + + provider.delaySendMessage(0, 'message', { + from: '000', + body: 'hola', + }) + + await delay(10) + const getHistory = database.listHistory.map((i) => i.answer) + + assert.is(MOCK_VALUES[0], getHistory[0]) + assert.is(MOCK_VALUES[1], getHistory[1]) +}) + +test.run() + +function delay(ms) { + return new Promise((res) => setTimeout(res, ms)) +} diff --git a/packages/bot/tests/flow.class.test.js b/packages/bot/tests/flow.class.test.js index b9c55e2..e1c93d7 100644 --- a/packages/bot/tests/flow.class.test.js +++ b/packages/bot/tests/flow.class.test.js @@ -1,7 +1,6 @@ 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 () => { From cebfed03823e8fdbd4742aaad0408bf2d5a85b82 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Mon, 23 Jan 2023 20:27:55 +0100 Subject: [PATCH 12/18] test(bot): :zap: more test and endflow --- __test__/04-case.test.js | 82 +++++++++++++++++++++++++++++++++ packages/bot/core/core.class.js | 22 ++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 __test__/04-case.test.js diff --git a/__test__/04-case.test.js b/__test__/04-case.test.js new file mode 100644 index 0000000..2291a0c --- /dev/null +++ b/__test__/04-case.test.js @@ -0,0 +1,82 @@ +const { test } = require('uvu') +const assert = require('uvu/assert') +const MOCK_DB = require('../packages/database/src/mock') +const PROVIDER_DB = require('../packages/provider/src/mock') +const { + addKeyword, + createBot, + createFlow, + createProvider, +} = require('../packages/bot/index') + +/** + * Falsear peticion async + * @param {*} fakeData + * @returns + */ +const fakeHTTP = async (fakeData = []) => { + console.log('⚡ Server request!') + await delay(50) + console.log('⚡ Server return!') + const data = fakeData.map((u, i) => ({ body: `${i + 1} ${u}` })) + console.log(data) + return Promise.resolve(data) +} + +test(`[Caso - 04] Romper flujo (endFlow)`, async () => { + const MOCK_VALUES = [ + 'Bienvenido te envio muchas marcas (5510)', + 'Seleccione marca del auto a cotizar, con el *número* correspondiente', + 'Seleccione la sub marca del auto a cotizar, con el *número* correspondiente:', + 'Los precios rondan:', + ] + const provider = createProvider(PROVIDER_DB) + const database = new MOCK_DB() + + const flujoPrincipal = addKeyword(['hola']) + .addAnswer(MOCK_VALUES[0], null, async (ctx, { flowDynamic }) => { + console.log('execute...') + const data = await fakeHTTP(['Ford', 'GM', 'BMW']) + return flowDynamic(data) + }) + .addAnswer(MOCK_VALUES[1], null, async (ctx, { endFlow }) => { + return endFlow() + }) + .addAnswer(MOCK_VALUES[2], null, async (ctx, { flowDynamic }) => { + const data = await fakeHTTP(['Usado', 'Nuevos']) + return flowDynamic(data) + }) + .addAnswer(MOCK_VALUES[3], null, async (ctx, { flowDynamic }) => { + const data = await fakeHTTP(['1000', '2000', '3000']) + return flowDynamic(data) + }) + + createBot({ + database, + flow: createFlow([flujoPrincipal]), + provider, + }) + + provider.delaySendMessage(0, 'message', { + from: '000', + body: 'hola', + }) + + await delay(1200) + const getHistory = database.listHistory.map((i) => i.answer) + assert.is(MOCK_VALUES[0], getHistory[0]) + + //FlowDynamic + assert.is('1 Ford', getHistory[1]) + assert.is('2 GM', getHistory[2]) + assert.is('3 BMW', getHistory[3]) + + assert.is(MOCK_VALUES[1], getHistory[4]) + assert.is(undefined, getHistory[5]) +}) + +test.run() + +function delay(ms) { + return new Promise((res) => setTimeout(res, ms)) +} diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index 30e6f4d..f7051b3 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -72,11 +72,12 @@ class CoreClass { const { body, from } = messageCtxInComming let msgToSend = [] let fallBackFlag = false + let endFlowFlag = false if (this.generalArgs.blackList.includes(from)) return if (!body) return if (!body.length) return - const prevMsg = await this.databaseClass.getPrevByNumber(from) + let prevMsg = await this.databaseClass.getPrevByNumber(from) const refToContinue = this.flowClass.findBySerialize( prevMsg?.refSerialize ) @@ -90,13 +91,28 @@ class CoreClass { this.databaseClass.save(ctxByNumber) } + // 📄 Limpiar cola de procesos + const clearQueue = () => { + QueuePrincipal.pendingPromise = false + QueuePrincipal.queue = [] + } + + // 📄 Finalizar flujo + const endFlow = async () => { + prevMsg = null + endFlowFlag = true + clearQueue() + return + } + // 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx const sendFlow = async (messageToSend, numberOrId) => { // [1 Paso] esto esta bien! - if (prevMsg?.options?.capture) await cbEveryCtx(prevMsg?.ref) + if (prevMsg?.options?.capture) await cbEveryCtx(prevMsg?.ref) const queue = [] for (const ctxMessage of messageToSend) { + if (endFlowFlag) return const delayMs = ctxMessage?.options?.delay || 0 if (delayMs) await delay(delayMs) QueuePrincipal.enqueue(() => @@ -145,6 +161,7 @@ class CoreClass { }) .slice(0, optListMsg.limit) + if (endFlowFlag) return for (const msg of parseListMsg) { await this.sendProviderAndSave(from, msg) } @@ -163,6 +180,7 @@ class CoreClass { return this.flowClass.allCallbacks[inRef](messageCtxInComming, { fallBack, flowDynamic, + endFlow, }) } From 71c969f3e9f58217820afea2e22b3a3690767546 Mon Sep 17 00:00:00 2001 From: lisandroprada Date: Mon, 23 Jan 2023 16:34:53 -0300 Subject: [PATCH 13/18] Update index.mdx --- packages/docs/src/routes/docs/flows/index.mdx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx index 2e078d7..1a5e879 100644 --- a/packages/docs/src/routes/docs/flows/index.mdx +++ b/packages/docs/src/routes/docs/flows/index.mdx @@ -159,6 +159,19 @@ const flowString = addKeyword('hola') --- +# QRPortalWeb + +Argumento para asignar nombre y puerto al BOT + +```js +QRPortalWeb({name:BOTNAME, port:3005 }); + +``` + +--- + + + Date: Tue, 24 Jan 2023 14:22:33 +0100 Subject: [PATCH 14/18] docs: :art: modal added --- .../src/components/widgets/SearchModal.tsx | 20 +++++++++++++++++++ packages/docs/src/routes/docs/layout!.tsx | 2 ++ packages/docs/src/routes/index.tsx | 2 +- packages/docs/src/services/opencollective.ts | 2 +- .../server/@qwik-city-not-found-paths.js | 2 +- .../portal/server/@qwik-city-static-paths.js | 1 - 6 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 packages/docs/src/components/widgets/SearchModal.tsx diff --git a/packages/docs/src/components/widgets/SearchModal.tsx b/packages/docs/src/components/widgets/SearchModal.tsx new file mode 100644 index 0000000..ed31b87 --- /dev/null +++ b/packages/docs/src/components/widgets/SearchModal.tsx @@ -0,0 +1,20 @@ +import { component$, useStore } from '@builder.io/qwik' + +export const SearchModal = component$(() => { + const state = useStore({ + open: false, + src: '', + }) + + return ( +
+
+ +
+
+ ) +}) + +export const SingleModal = component$(() => { + return
Modal singlke
+}) diff --git a/packages/docs/src/routes/docs/layout!.tsx b/packages/docs/src/routes/docs/layout!.tsx index cb34220..4d66df2 100644 --- a/packages/docs/src/routes/docs/layout!.tsx +++ b/packages/docs/src/routes/docs/layout!.tsx @@ -3,6 +3,7 @@ import type { DocumentHead } from '@builder.io/qwik-city' import ExtraBar from '~/components/widgets/ExtraBar' import Header from '~/components/widgets/Header' import NavBar from '~/components/widgets/NavBar' +import { SearchModal } from '~/components/widgets/SearchModal' import SponsorBar from '~/components/widgets/SponsorBar' import { GlobalStore } from '~/contexts' // import Navigation from '~/components/widgets/Navigation' @@ -14,6 +15,7 @@ export default component$(() => { return ( <> +
diff --git a/packages/docs/src/routes/index.tsx b/packages/docs/src/routes/index.tsx index 8ad3b75..dbfb2da 100644 --- a/packages/docs/src/routes/index.tsx +++ b/packages/docs/src/routes/index.tsx @@ -10,11 +10,11 @@ import { fetchGithub } from '~/services/github' import { fetchOpenCollective } from '~/services/opencollective' import { RequestHandlerNetlify } from '@builder.io/qwik-city/middleware/netlify-edge' import { GITHUB_TOKEN } from './docs/constant' +import { SearchModal } from '~/components/widgets/SearchModal' export const onGet: RequestHandlerNetlify = async ({ platform }) => { const CHECK_GITHUB_TOKEN = (platform as any)?.['GITHUB_TOKEN'] ?? GITHUB_TOKEN - console.log(`[🚩 platform]: `, GITHUB_TOKEN) const dataGithub = await fetchGithub(CHECK_GITHUB_TOKEN) const dataOpenCollective = await fetchOpenCollective() return { diff --git a/packages/docs/src/services/opencollective.ts b/packages/docs/src/services/opencollective.ts index 2eb60c8..9a89f25 100644 --- a/packages/docs/src/services/opencollective.ts +++ b/packages/docs/src/services/opencollective.ts @@ -4,7 +4,7 @@ */ export const fetchOpenCollective = async () => { const data = await fetch( - `https://opencollective.com/bot-whatsapp/members/users.json?limit=10&offset=0`, + `https://opencollective.com/bot-whatsapp/members/users.json?limit=22&offset=0`, { method: 'GET', } diff --git a/packages/portal/server/@qwik-city-not-found-paths.js b/packages/portal/server/@qwik-city-not-found-paths.js index f5f657d..473076c 100644 --- a/packages/portal/server/@qwik-city-not-found-paths.js +++ b/packages/portal/server/@qwik-city-not-found-paths.js @@ -1,7 +1,7 @@ const notFounds = [ [ '/', - '\n\n\n \n \n 404 Resource Not Found\n \n \n\n\n

404 Resource Not Found

\n\n', + '\n\n \n \n \n 404 Resource Not Found\n \n \n \n \n

404 Resource Not Found

\n \n\n', ], ] function getNotFound(p) { diff --git a/packages/portal/server/@qwik-city-static-paths.js b/packages/portal/server/@qwik-city-static-paths.js index 1afa65f..1835f6b 100644 --- a/packages/portal/server/@qwik-city-static-paths.js +++ b/packages/portal/server/@qwik-city-static-paths.js @@ -1,5 +1,4 @@ const staticPaths = new Set([ - '/', '/favicon.svg', '/manifest.json', '/q-manifest.json', From 371b403456398d150b4839e1805cbb6afe76b2fe Mon Sep 17 00:00:00 2001 From: Gregoriotecnico <118696506+Gregoriotecnico@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:38:38 +0100 Subject: [PATCH 15/18] =?UTF-8?q?Adici=C3=B3n=20de=20endFlow()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/docs/src/routes/docs/flows/index.mdx | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx index 1a5e879..f1a8d3b 100644 --- a/packages/docs/src/routes/docs/flows/index.mdx +++ b/packages/docs/src/routes/docs/flows/index.mdx @@ -158,6 +158,51 @@ const flowString = addKeyword('hola') ``` --- +## endFlow() + +Esta funcion se utliza para finalizar un flujo con dos o más addAnswer. Un ejemplo de uso sería registrar 3 datos de un usuario en 3 preguntas distinas y +que el usuario pueda finalizar por él mismo el flujo. +Como podrás comprobar en el ejemplo siguiente, se puede vincular flowDynamic y todas sus funciones; como por ejemplo botones. + + + +```js +const flowFormulario = addKeyword(['Hola']) + +.addAnswer(['Hola!','Escriba su *Nombre* para generar su solicitud'], +{capture: true,buttons:[{body:'❌ Cancelar solicitud'}]}, +async (ctx,{flowDynamic, endFlow})=>{ + if(ctx.body == '❌ Cancelar solicitud'){ + await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}]) + return endFlow() + } + }) + .addAnswer(['También necesito tus dos apellidos'], + {capture: true,buttons:[{body:'❌ Cancelar solicitud'}]}, + async (ctx,{flowDynamic, endFlow})=>{ + if(ctx.body == '❌ Cancelar solicitud'){ + await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}]) + return endFlow() + } + }) + .addAnswer(['Dejeme su número de teléfono y le llamaré lo antes posible.'], +{capture: true,buttons:[{body:'❌ Cancelar solicitud'}]}, +async (ctx,{flowDynamic, endFlow})=>{ + if(ctx.body == '❌ Cancelar solicitud'){ + await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}]) + return endFlow() + } + }) + + + +``` + +--- + + + + # QRPortalWeb From 943fe8698caf82706386c60960bc79a9bd9412cd Mon Sep 17 00:00:00 2001 From: Gregoriotecnico <118696506+Gregoriotecnico@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:55:11 +0100 Subject: [PATCH 16/18] =?UTF-8?q?Adici=C3=B3n=20blackList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/docs/src/routes/docs/flows/index.mdx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx index 1a5e879..e363630 100644 --- a/packages/docs/src/routes/docs/flows/index.mdx +++ b/packages/docs/src/routes/docs/flows/index.mdx @@ -23,6 +23,23 @@ const flowPrincipal = addKeyword(['hola', 'alo']) --- +## blackList + +Éste argumento se utiliza para **evitar que el bot se active** cuando los números de la lista activen el bot. +Es importante que el número **vaya acompañado de su prefijo**, en el caso de España "34". + +```js +createBot({ + flow: adapterFlow, + provider: adapterProvider, + database: adapterDB, + },{ + blackList:['34XXXXXXXXX','34XXXXXXXXX','34XXXXXXXXX','34XXXXXXXXX'] + }) +``` + +--- + ## addKeyword() Esta funcion se utliza para iniciar un flujo de conversion.
Recibe un `string` o un `array` From 24220822f431afb0b4765addca90587576e0b7d2 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Tue, 24 Jan 2023 22:44:24 +0100 Subject: [PATCH 17/18] chore(release): 0.1.18 --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d3865b..9b39939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,47 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.1.18](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.17...v0.1.18) (2023-01-24) + + +### Features + +* **bot:** :zap: add blacklist ([7078dc4](https://github.com/leifermendez/bot-whatsapp/commit/7078dc4c93d01bf90ef08ecb34e89a1abbe16fd2)) +* **bot:** :zap: flowDynamic buttons, media ([3c4b1c0](https://github.com/leifermendez/bot-whatsapp/commit/3c4b1c0fc4b6d98d67c67806d918d3604bb2209b)) + + +### Bug Fixes + +* **bot:** :bug: body undefined ([bb6ed4a](https://github.com/leifermendez/bot-whatsapp/commit/bb6ed4a084ae98070dfdf0c4ba1eca574c4092cc)) +* **bot:** :bug: body undefined ([9234cf1](https://github.com/leifermendez/bot-whatsapp/commit/9234cf1c5d00abdd35e62a826b3c450ab056987a)) +* **bot:** :bug: body undefined ([a118bbb](https://github.com/leifermendez/bot-whatsapp/commit/a118bbbf7f0a7023cb7f33c23f37db72adad151f)) +* **bot:** :bug: body undefined ([f54dea5](https://github.com/leifermendez/bot-whatsapp/commit/f54dea52b01063acd6122eeba1fbbe324aa7805d)) +* **bot:** :bug: body undefined ([72e0a91](https://github.com/leifermendez/bot-whatsapp/commit/72e0a910503e9643db7dfbc6e09c41c96934e1f7)) +* **bot:** :bug: body undefined ([70dd4d7](https://github.com/leifermendez/bot-whatsapp/commit/70dd4d73e814fc5636d19a887f3621c483b837c1)) +* **bot:** :bug: body undefined ([ecf0eef](https://github.com/leifermendez/bot-whatsapp/commit/ecf0eef928917d76c59bd23886cb7a4108b421f1)) +* **bot:** :bug: flowDynamic stranger behaviour ([877252b](https://github.com/leifermendez/bot-whatsapp/commit/877252bd4a8a7bbbbf083c3ceaeaeb952b0a1828)) +* **bot:** :bug: flowDynamic stranger behaviour ([f5a7de3](https://github.com/leifermendez/bot-whatsapp/commit/f5a7de3a003c012e2164e51fff26892cfc3144be)) +* **bot:** :memo: more docs ([98793d0](https://github.com/leifermendez/bot-whatsapp/commit/98793d0cfc1674830beaa3707f933c5a791eec14)) +* **cli:** :zap: refactor ([a29b9d4](https://github.com/leifermendez/bot-whatsapp/commit/a29b9d4e1f85fc163cf1d633c0857f0c8b7f03e1)) +* **cli:** :zap: refactor ([18ef4e9](https://github.com/leifermendez/bot-whatsapp/commit/18ef4e9d726575ca390ca24354825860328d3347)) +* **cli:** :zap: refactor ([3648757](https://github.com/leifermendez/bot-whatsapp/commit/3648757fa083bdb88a16bf6c2e90c828c233bdb1)) +* **cli:** :zap: refactor ([32f6a70](https://github.com/leifermendez/bot-whatsapp/commit/32f6a70f8f6fb26d8ea2a0f1a4aec4827b9d6a93)) +* **cli:** :zap: refactor ([8c825e7](https://github.com/leifermendez/bot-whatsapp/commit/8c825e7f6b7133f7cc7f3041ce331b80a9fe60e0)) +* **cli:** :zap: refactor ([0c0f437](https://github.com/leifermendez/bot-whatsapp/commit/0c0f4375b84549bee809340a85f9ce038ee2739e)) +* **cli:** :zap: refactor ([039ce5d](https://github.com/leifermendez/bot-whatsapp/commit/039ce5dd7cac8115b335ad5de05f7bd871e24140)) +* **cli:** :zap: refactor ([5e87918](https://github.com/leifermendez/bot-whatsapp/commit/5e879188b8bf9d486399b308a9a9c2612607d465)) +* **cli:** :zap: refactor ([21a7270](https://github.com/leifermendez/bot-whatsapp/commit/21a72702817bc6b344223b34ca4513a7ff45fc93)) +* **cli:** :zap: refactor ([82a99b2](https://github.com/leifermendez/bot-whatsapp/commit/82a99b2c80e6738566042ea738bbab8208a17758)) +* **cli:** :zap: refactor ([cc19974](https://github.com/leifermendez/bot-whatsapp/commit/cc19974579379777b05cb69c38cec0fce6740471)) +* **cli:** :zap: refactor ([56fcb8f](https://github.com/leifermendez/bot-whatsapp/commit/56fcb8fb72169bc21fce7c4fcdceccf2acd39c73)) +* **cli:** :zap: refactor ([f36cff1](https://github.com/leifermendez/bot-whatsapp/commit/f36cff1eefdd96be4ab531e1cb2d3b630b1a81c3)) +* **cli:** :zap: refactor ([b393c11](https://github.com/leifermendez/bot-whatsapp/commit/b393c11af6c0ebccb0a690be8b90b9df8877dad1)) +* **cli:** :zap: refactor ([6683715](https://github.com/leifermendez/bot-whatsapp/commit/6683715ad617ea1075654a475a1c62ea607c733f)) +* **contexts:** :bug: fixed [#524](https://github.com/leifermendez/bot-whatsapp/issues/524) issue ([79cc31a](https://github.com/leifermendez/bot-whatsapp/commit/79cc31a96f6a9836447cc4e6bb1e1521c54183fe)) +* **contexts:** :bug: fixed [#524](https://github.com/leifermendez/bot-whatsapp/issues/524) issue ([7067b4a](https://github.com/leifermendez/bot-whatsapp/commit/7067b4a80b7938ccfaf1ed141a37d645a1a3a062)) +* **provider:** wwebjs upgrade ([345f256](https://github.com/leifermendez/bot-whatsapp/commit/345f256a1b4a238519dafc15c9a31bc5e6bad4fe)) +* se agrego @bot-whatsapp/portal a package.json ([46a9fa6](https://github.com/leifermendez/bot-whatsapp/commit/46a9fa6793e06600335de998d2bd9d0691b02ca4)) + ### [0.1.17](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.16...v0.1.17) (2023-01-13) diff --git a/package.json b/package.json index 2d1061e..fda898a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/root", - "version": "0.1.17", + "version": "0.1.18", "description": "Bot de wahtsapp open source para MVP o pequeños negocios", "main": "app.js", "private": true, From 558013b2b4ca7d72977045485bedbbdb7113ff63 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Tue, 24 Jan 2023 22:50:59 +0100 Subject: [PATCH 18/18] docs: :memo: add --- packages/docs/src/components/widgets/SearchModal.tsx | 10 +++++----- packages/docs/src/routes/index.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/docs/src/components/widgets/SearchModal.tsx b/packages/docs/src/components/widgets/SearchModal.tsx index ed31b87..287a28b 100644 --- a/packages/docs/src/components/widgets/SearchModal.tsx +++ b/packages/docs/src/components/widgets/SearchModal.tsx @@ -1,10 +1,10 @@ -import { component$, useStore } from '@builder.io/qwik' +import { component$ } from '@builder.io/qwik' export const SearchModal = component$(() => { - const state = useStore({ - open: false, - src: '', - }) + // const state = useStore({ + // open: false, + // src: '', + // }) return (
diff --git a/packages/docs/src/routes/index.tsx b/packages/docs/src/routes/index.tsx index dbfb2da..9b0f04a 100644 --- a/packages/docs/src/routes/index.tsx +++ b/packages/docs/src/routes/index.tsx @@ -10,7 +10,7 @@ import { fetchGithub } from '~/services/github' import { fetchOpenCollective } from '~/services/opencollective' import { RequestHandlerNetlify } from '@builder.io/qwik-city/middleware/netlify-edge' import { GITHUB_TOKEN } from './docs/constant' -import { SearchModal } from '~/components/widgets/SearchModal' +// import { SearchModal } from '~/components/widgets/SearchModal' export const onGet: RequestHandlerNetlify = async ({ platform }) => { const CHECK_GITHUB_TOKEN =