Compare commits

..

1 Commits

Author SHA1 Message Date
cheveguerra
36a7d9a0b7 ci(providers): check provider versions 2023-01-17 09:15:20 +00:00
35 changed files with 102 additions and 895 deletions

View File

@@ -10,15 +10,9 @@ jobs:
release: release:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs:
commit: ${{ steps.vars.outputs.commit }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{github.event.after}}
persist-credentials: false
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
@@ -56,9 +50,8 @@ jobs:
- name: Release @bot-whatsapp/portal - name: Release @bot-whatsapp/portal
run: yarn node ./scripts/release.js --name=portal --version= --token="${{ secrets.NPM_TOKEN }}" run: yarn node ./scripts/release.js --name=portal --version= --token="${{ secrets.NPM_TOKEN }}"
- name: Commit & Push changes - name: Commit Versioning & Push changes
uses: actions-js/push@master uses: stefanzweifel/git-auto-commit-action@v4
with: with:
branch: release/next commit_message: 'ci(version): :zap: automatic - "${date}" updated versions every packages'
github_token: ${{ secrets.GITHUB_TOKEN }} branch: dev
force: true

View File

@@ -67,9 +67,13 @@ jobs:
- name: Release Github - name: Release Github
run: yarn node ./scripts/github.js --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.OCTO_TOKEN }}" run: yarn node ./scripts/github.js --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.OCTO_TOKEN }}"
- name: Commit & Push changes - name: 'Run if changes have been detected'
uses: actions-js/push@master run: |
git add .
git commit -m "chore(version): pre release"
- name: Commit Versioning & Push changes
if: github.event_name == 'push'
uses: stefanzweifel/git-auto-commit-action@v4
with: with:
branch: release/production commit_message: 'chore(version): launch release 🚀 "${{ steps.package-version.outputs.current-version}}"'
github_token: ${{ secrets.GITHUB_TOKEN }}
force: true

1
.gitignore vendored
View File

@@ -1,5 +1,4 @@
/node_modules /node_modules
/packages/repl
/packages/*/starters /packages/*/starters
/packages/*/node_modules /packages/*/node_modules
/packages/*/dist /packages/*/dist

View File

@@ -2,47 +2,6 @@
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. 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) ### [0.1.17](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.16...v0.1.17) (2023-01-13)

View File

@@ -34,13 +34,6 @@ Entiende más a fondo sus funcionalidades explicadas en nuestra documentación.
<!-- readme: collaborators,contributors -start --> <!-- readme: collaborators,contributors -start -->
<table> <table>
<tr> <tr>
<td align="center">
<a href="https://github.com/cheveguerra">
<img src="https://avatars.githubusercontent.com/u/5891114?v=4" width="50;" alt="cheveguerra"/>
<br />
<sub><b>Jose Alberto Guerra Ugalde</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/leifermendez"> <a href="https://github.com/leifermendez">
<img src="https://avatars.githubusercontent.com/u/15802366?v=4" width="50;" alt="leifermendez"/> <img src="https://avatars.githubusercontent.com/u/15802366?v=4" width="50;" alt="leifermendez"/>
@@ -49,10 +42,10 @@ Entiende más a fondo sus funcionalidades explicadas en nuestra documentación.
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/leifermendezfroged"> <a href="https://github.com/aurik3">
<img src="https://avatars.githubusercontent.com/u/97020486?v=4" width="50;" alt="leifermendezfroged"/> <img src="https://avatars.githubusercontent.com/u/37228512?v=4" width="50;" alt="aurik3"/>
<br /> <br />
<sub><b>Leifer Mendez</b></sub> <sub><b>Null</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@@ -63,20 +56,12 @@ Entiende más a fondo sus funcionalidades explicadas en nuestra documentación.
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/danielcasta0398"> <a href="https://github.com/leifermendezfroged">
<img src="https://avatars.githubusercontent.com/u/98791147?v=4" width="50;" alt="danielcasta0398"/> <img src="https://avatars.githubusercontent.com/u/97020486?v=4" width="50;" alt="leifermendezfroged"/>
<br /> <br />
<sub><b>Juan Daniel Castaño</b></sub> <sub><b>Leifer Mendez</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/marianarolfo">
<img src="https://avatars.githubusercontent.com/u/68322254?v=4" width="50;" alt="marianarolfo"/>
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/HKong31"> <a href="https://github.com/HKong31">
<img src="https://avatars.githubusercontent.com/u/113340082?v=4" width="50;" alt="HKong31"/> <img src="https://avatars.githubusercontent.com/u/113340082?v=4" width="50;" alt="HKong31"/>
@@ -90,53 +75,11 @@ Entiende más a fondo sus funcionalidades explicadas en nuestra documentación.
<br /> <br />
<sub><b>Zvi</b></sub> <sub><b>Zvi</b></sub>
</a> </a>
</td>
<td align="center">
<a href="https://github.com/JosephVTX">
<img src="https://avatars.githubusercontent.com/u/91026290?v=4" width="50;" alt="JosephVTX"/>
<br />
<sub><b>Joseph Vega Callupe</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Gonzalito87">
<img src="https://avatars.githubusercontent.com/u/100331586?v=4" width="50;" alt="Gonzalito87"/>
<br />
<sub><b>Null</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/devrlbusiness">
<img src="https://avatars.githubusercontent.com/u/66280283?v=4" width="50;" alt="devrlbusiness"/>
<br />
<sub><b>Developer RL Business</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Gregoriotecnico">
<img src="https://avatars.githubusercontent.com/u/118696506?v=4" width="50;" alt="Gregoriotecnico"/>
<br />
<sub><b>Null</b></sub>
</a>
</td></tr> </td></tr>
<tr> <tr>
<td align="center"> <td align="center">
<a href="https://github.com/aurik3"> <a href="https://github.com/Gonzalito87">
<img src="https://avatars.githubusercontent.com/u/37228512?v=4" width="50;" alt="aurik3"/> <img src="https://avatars.githubusercontent.com/u/100331586?v=4" width="50;" alt="Gonzalito87"/>
<br />
<sub><b>Null</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jlferrete">
<img src="https://avatars.githubusercontent.com/u/36698913?v=4" width="50;" alt="jlferrete"/>
<br />
<sub><b>Jose Luis Ferrete Olarte</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/6rak0">
<img src="https://avatars.githubusercontent.com/u/12260031?v=4" width="50;" alt="6rak0"/>
<br /> <br />
<sub><b>Null</b></sub> <sub><b>Null</b></sub>
</a> </a>
@@ -149,10 +92,10 @@ Entiende más a fondo sus funcionalidades explicadas en nuestra documentación.
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/lisandroprada"> <a href="https://github.com/ulisesvina">
<img src="https://avatars.githubusercontent.com/u/7232326?v=4" width="50;" alt="lisandroprada"/> <img src="https://avatars.githubusercontent.com/u/20508563?v=4" width="50;" alt="ulisesvina"/>
<br /> <br />
<sub><b>Null</b></sub> <sub><b>Ulises Viña</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@@ -161,8 +104,7 @@ Entiende más a fondo sus funcionalidades explicadas en nuestra documentación.
<br /> <br />
<sub><b>Rodrigo Mendoza Cabrera</b></sub> <sub><b>Rodrigo Mendoza Cabrera</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/yond1994"> <a href="https://github.com/yond1994">
<img src="https://avatars.githubusercontent.com/u/47557263?v=4" width="50;" alt="yond1994"/> <img src="https://avatars.githubusercontent.com/u/47557263?v=4" width="50;" alt="yond1994"/>

View File

@@ -1,41 +0,0 @@
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))
}

View File

@@ -1,99 +0,0 @@
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 - 02] Flow (flowDynamic)`, 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))
}

View File

@@ -1,44 +0,0 @@
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))
}

View File

@@ -1,82 +0,0 @@
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))
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bot-whatsapp/root", "name": "@bot-whatsapp/root",
"version": "0.1.18", "version": "0.1.17",
"description": "Bot de wahtsapp open source para MVP o pequeños negocios", "description": "Bot de wahtsapp open source para MVP o pequeños negocios",
"main": "app.js", "main": "app.js",
"private": true, "private": true,
@@ -24,8 +24,7 @@
"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", "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", "copy.lib": "node ./scripts/move.js",
"test.unit": "node ./node_modules/uvu/bin.js packages test", "test.unit": "node ./node_modules/uvu/bin.js packages test",
"test.e2e": "node ./node_modules/uvu/bin.js __test__", "test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit",
"test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit && npm run test.e2e",
"test": "npm run test.coverage", "test": "npm run test.coverage",
"cli": "node ./packages/cli/bin/cli.js", "cli": "node ./packages/cli/bin/cli.js",
"create": "node ./packages/create-bot-whatsapp/bin/create.js", "create": "node ./packages/create-bot-whatsapp/bin/create.js",

View File

@@ -21,12 +21,10 @@ class CoreClass {
flowClass flowClass
databaseClass databaseClass
providerClass providerClass
generalArgs = { blackList: [] } constructor(_flow, _database, _provider) {
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)
@@ -72,12 +70,10 @@ class CoreClass {
const { body, from } = messageCtxInComming const { body, from } = messageCtxInComming
let msgToSend = [] let msgToSend = []
let fallBackFlag = false let fallBackFlag = false
let endFlowFlag = false
if (this.generalArgs.blackList.includes(from)) return
if (!body) return if (!body) return
if (!body.length) return if (!body.length) return
let prevMsg = await this.databaseClass.getPrevByNumber(from) const prevMsg = await this.databaseClass.getPrevByNumber(from)
const refToContinue = this.flowClass.findBySerialize( const refToContinue = this.flowClass.findBySerialize(
prevMsg?.refSerialize prevMsg?.refSerialize
) )
@@ -91,35 +87,16 @@ class CoreClass {
this.databaseClass.save(ctxByNumber) 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 // 📄 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) {
if (endFlowFlag) return
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).then( this.sendProviderAndSave(numberOrId, ctxMessage),
() => resolveCbEveryCtx(ctxMessage) resolveCbEveryCtx(ctxMessage),
),
]) ])
) )
} }
@@ -136,7 +113,6 @@ 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 }
@@ -146,22 +122,15 @@ class CoreClass {
fallBackFlag = optListMsg.fallback fallBackFlag = optListMsg.fallback
const parseListMsg = listMsg const parseListMsg = listMsg
.map((opt, index) => { .map(({ body }, index) =>
const body = typeof opt === 'string' ? opt : opt.body toCtx({
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)
if (endFlowFlag) return
for (const msg of parseListMsg) { for (const msg of parseListMsg) {
await this.sendProviderAndSave(from, msg) await this.sendProviderAndSave(from, msg)
} }
@@ -170,6 +139,7 @@ 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)
} }
@@ -180,10 +150,20 @@ class CoreClass {
return this.flowClass.allCallbacks[inRef](messageCtxInComming, { return this.flowClass.allCallbacks[inRef](messageCtxInComming, {
fallBack, fallBack,
flowDynamic, flowDynamic,
endFlow,
}) })
} }
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
@@ -193,6 +173,11 @@ 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
} }
@@ -240,24 +225,5 @@ 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

View File

@@ -8,8 +8,8 @@ const { addKeyword, addAnswer, addChild, toSerialize } = require('./io/methods')
* @param {*} args * @param {*} args
* @returns * @returns
*/ */
const createBot = async ({ flow, database, provider }, args = {}) => const createBot = async ({ flow, database, provider }) =>
new CoreClass(flow, database, provider, args) new CoreClass(flow, database, provider)
/** /**
* Crear instancia de clase Io (Flow) * Crear instancia de clase Io (Flow)

View File

@@ -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, options = {}, index }) => { const toCtx = ({ body, from, prevRef, 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 }),
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bot-whatsapp/bot", "name": "@bot-whatsapp/bot",
"version": "0.0.73-alpha.0", "version": "0.0.66-alpha.0",
"description": "", "description": "",
"main": "./lib/bundle.bot.cjs", "main": "./lib/bundle.bot.cjs",
"scripts": { "scripts": {

View File

@@ -1,28 +0,0 @@
const { test } = require('uvu')
const assert = require('uvu/assert')
const FlowClass = require('../io/flow.class')
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()

View File

@@ -48,11 +48,11 @@ const nextSteps = async () => {
name: 'providerWs', name: 'providerWs',
message: '¿Cuál proveedor de whatsapp quieres utilizar?', message: '¿Cuál proveedor de whatsapp quieres utilizar?',
choices: [ choices: [
{ title: 'Baileys (gratis)', value: 'baileys' },
{ title: 'Venom (gratis)', value: 'venom' },
{ title: 'whatsapp-web.js (gratis)', value: 'wweb' }, { title: 'whatsapp-web.js (gratis)', value: 'wweb' },
{ title: 'Venom (gratis)', value: 'venom' },
{ title: 'Baileys (gratis)', value: 'baileys' },
{ title: 'Twilio', value: 'twilio' }, { title: 'Twilio', value: 'twilio' },
{ title: 'Meta', value: 'meta' }, { title: 'API Oficial (Meta)', value: 'meta' },
], ],
max: 1, max: 1,
hint: 'Espacio para seleccionar', hint: 'Espacio para seleccionar',

View File

@@ -117,7 +117,7 @@ class DialogFlowCXContext extends CoreClass {
} }
}) })
this.sendFlowSimple(listMessages, from) this.sendFlow(listMessages, from)
} }
} }

View File

@@ -107,7 +107,7 @@ class DialogFlowContext extends CoreClass {
...customPayload, ...customPayload,
answer: fields?.answer?.stringValue, answer: fields?.answer?.stringValue,
} }
this.sendFlowSimple([ctxFromDX], from) this.sendFlow([ctxFromDX], from)
return return
} }
@@ -115,7 +115,7 @@ class DialogFlowContext extends CoreClass {
answer: queryResult?.fulfillmentText, answer: queryResult?.fulfillmentText,
} }
this.sendFlowSimple([ctxFromDX], from) this.sendFlow([ctxFromDX], from)
} }
} }

View File

@@ -14,7 +14,7 @@ export default component$(
<a href={props.user.html_url} target="_blank"> <a href={props.user.html_url} target="_blank">
<img <img
class="w-16 h-16 rounded-full mx-auto object-cover" class="w-16 h-16 rounded-full mx-auto object-cover"
src={props.user.avatar_url} src={props.user.avatar_url + '&s=80'}
alt={props.user.login} alt={props.user.login}
width="80" width="80"
height="80" height="80"
@@ -23,9 +23,7 @@ export default component$(
<div class="pt-2 space-y-4 justify-center flex"> <div class="pt-2 space-y-4 justify-center flex">
<figcaption class="text-sm"> <figcaption class="text-sm">
<div class={'font-semibold truncate'}> <div class={'font-semibold'}>{props.user.login}</div>
{props.user.login}
</div>
</figcaption> </figcaption>
</div> </div>
</figure> </figure>

View File

@@ -56,7 +56,7 @@ export default component$(() => {
</a> </a>
<a <a
target={'_blank'} target={'_blank'}
href="https://youtu.be/UgoS8PXxe-A" href="https://youtu.be/DEIyGyJNGa8"
class="btn bg-gray-50 dark:bg-transparent" class="btn bg-gray-50 dark:bg-transparent"
> >
Ver video Ver video

View File

@@ -1,54 +0,0 @@
import { component$ } from '@builder.io/qwik'
import { RequestHandlerCloudflarePages } from '@builder.io/qwik-city/middleware/cloudflare-pages'
import { User } from '~/contexts'
import Collaborator from './Collaborator'
export const onRequest: RequestHandlerCloudflarePages = async () => {
console.log('??heree')
}
export const TaleUsers = component$((props: { users: User[] }) => {
return (
<>
{props.users.map((user) => (
<div class="col-span-2 ">
{' '}
<Collaborator user={user} />
</div>
))}
</>
)
})
export default component$((props: { users: User[] }) => {
return (
<section class="relative ">
<div class={'px-4 py-16 mx-auto max-w-6xl lg:py-20'}>
<div class="mb-10 md:mx-auto sm:text-center md:mb-12 max-w-3xl">
<p class="text-base text-primary-600 dark:text-purple-200 font-semibold tracking-wide uppercase">
Premium
</p>
<h2 class="text-4xl md:text-5xl font-bold leading-tighter tracking-tighter mb-4 font-heading">
Miembros
</h2>
<p class="max-w-3xl mx-auto sm:text-center text-xl text-gray-600 dark:text-slate-400">
Conviértete en un miembro destacado y forma parte del
proyecto y disfruta de manera adelantada de las
actualizaciones{' '}
<a
class={'font-semibold'}
target={'_blank'}
href="https://opencollective.com/bot-whatsapp"
>
Únete
</a>
</p>
</div>
<div class="grid lg:grid-cols-12 grid-cols-1 gap-4 ">
<TaleUsers users={props.users} />
</div>
</div>
</section>
)
})

View File

@@ -1,20 +0,0 @@
import { component$ } from '@builder.io/qwik'
export const SearchModal = component$(() => {
// const state = useStore({
// open: false,
// src: '',
// })
return (
<div class={'bg-gray-100/75 fixed w-[100vw] h-[100vh] z-50'}>
<div class={'bg-red-200 w-1/3 m-auto mt-12'}>
<SingleModal />
</div>
</div>
)
})
export const SingleModal = component$(() => {
return <div class={'bg-blue-300 w-100 px-3 py-2'}>Modal singlke</div>
})

View File

@@ -52,22 +52,16 @@ export default component$(() => {
title: 'Avanzado', title: 'Avanzado',
list: [ list: [
{ name: 'Migración', link: '/docs/migration' }, { name: 'Migración', link: '/docs/migration' },
{ name: 'MasterClass', link: '/docs/masterclass' }, { name: 'Extender funcionalidades', link: '/docs/custom' },
],
},
{
title: 'Despliegue',
list: [
{ name: 'Local', link: '/docs/deploy/local' },
{ name: 'Docker', link: '/docs/deploy/docker' },
{ name: 'Cloud', link: '/docs/deploy/cloud' },
], ],
}, },
{ {
title: 'Comunidad', title: 'Comunidad',
list: [ list: [
{ name: 'MasterClass', link: '/docs/masterclass' },
{ name: 'Colabores', link: '/docs/contributing' }, { name: 'Colabores', link: '/docs/contributing' },
{ name: 'Unirme al proyecto', link: '/docs/join' }, { name: 'Unirme al proyecto', link: '/docs/join' },
{ name: 'Sponsors', link: '/docs/sponsors' },
], ],
}, },
]) ])

View File

@@ -1,108 +0,0 @@
import Alert from '../../../../components/widgets/Alert'
import Navigation from '../../../../components/widgets/Navigation'
# Entorno Cloud
Si deseas tener tu chatbot en ejecución en un servidor en la nueba esta, guía te ayudará.
El servidor deberá cumplir con los requisitos mínimos, puedes ver en [este enlace.](/docs/requirements)
---
Dependiendo de tu proveedor de **servicio Cloud** debes crear una instancia (máquina virtual), este ejemplo iremos orientando en un entorno de AWS.
En nuestro ejemplo creamos una maquina virtual con **Ubuntu 20.04**
![](https://i.imgur.com/5zRCz9q.png)
---
Posterior al proceso de crear la máquina esperamos unos minutos hasta que ya está operativo y tomamos nota del usuario y la IP pública para proceder a conectarnos vía SSH
## ![](https://i.imgur.com/ljyJPBm.png)
## Conectarse via SSH
Luego de obtener los datos necesarios para conectarnos a nuestra máquina, procedemos a hacerlo
```shell
ssh -i llaveBot.pem ubutnu@34.228.208.104
```
---
Luego puede aparecer un mensaje como el siguiente donde solo debes de responder **yes**
![](https://i.imgur.com/rUBASqR.png)
---
Una vez conectado ya estás dentro de la máquina virtual, te aconsejamos la primera vez hacer una actualización de dependencias de Ubuntu con los siguientes comandos
```shell
sudo apt-get update
```
```shell
sudo apt-get upgrade
```
---
## Recuerda instalar Node 16 o superior
Puedes ver más a detalle los pasos de la instalacion en este [blog](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04-es)
```shell
curl -sL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh
```
```shell
sudo bash nodesource_setup.sh
```
```shell
sudo apt-get install -y nodejs
```
---
## Implementar el bot
Si tienes el código de tu chatbot en un repositorio, solo falta que clones el repo en el servidor y ejecutes `npm start`
Para escanear el **QR** puedes hacerlo vía WEB accediendo a la URL `http://[TU_IP_PUBLICA]:3000` en este ejemplo seria `http://34.228.208.10:3000`
![](https://i.imgur.com/xcovczm.png)
---
## Firewall
Si no te abre la pagina web asegurate de tener el puerto abierto en tu firewall.
Ejemplo permitir el puerto **3000**
![](https://i.imgur.com/0dAz0B1.png)
---
## Escanear QR
![](https://i.imgur.com/2m3NbXC.png)
---
## Ejecutar en Producción
Debes ubicarte en el directorio donde tienes el codigo fuente de tu chatbot.
Independientemente de tu sistema operativo deberás ejecutar el chatbot con el comando atrevés de un sistema que mantenga el proceso en ejecución.
Recomendamos [Pm2](https://pm2.keymetrics.io/)
```shell
pm2 start app.js --name=bot1
```
![](https://i.imgur.com/ilPS75H.png)
La consola de devolver un mensaje con una lista de procesos, en el ejemplo puedes observar, que tenemos un proceso llamado `bot1`
De esta manera ya puedes cerrar la terminal y tu bot seguirá en ejecución sin problema

View File

@@ -1,32 +0,0 @@
import Alert from '../../../../components/widgets/Alert'
import Navigation from '../../../../components/widgets/Navigation'
# Entorno Docker
Previamente, necesitas tener instalado Docker en tu servidor dependiendo del sistema operativo, los procesos cambian,
puedes encontrar toda la información oficial de docker en [este enlace.](https://docs.docker.com/get-docker/)
---
Dependiendo del proveedor que has elegido necesitaras una implementación de Docker específica, pero no te preocupes, ya que viene implementada automáticamente en un archivo llamado **Dockerfile**, también puedes ver los otros Dockerfile en el apartado de [plantillas.](https://github.com/codigoencasa/bot-whatsapp/tree/main/starters/apps)
![](https://i.imgur.com/cDspa0R.png)
---
## Contruir imagen
Solo es necesario construir la imagen del docker lo puedes hacer con el siguiente comando
```shell
docker build . -t botwhatsapp:latest
```
## Iniciar contenedor
Para iniciar el contenedor con la imagen previamente construida puedes realizarlo ejecutando el siguiente comando.
Se utiliza el puerto **3001** solo com un ejemplo puedes usar el puerto que tu quieras
```shell
docker run -e PORT=3001 -p 3001:3001 botwhatsapp:latest
```

View File

@@ -1,26 +0,0 @@
import Alert from '../../../../components/widgets/Alert'
import Navigation from '../../../../components/widgets/Navigation'
# Entorno Local
Si deseas tener tu chatbot en ejecución en un servidor local (computadora personal, etc.) esta, guía te ayudará.
El servidor local deberá cumplir con los requisitos mínimos, puedes ver en [este enlace.](/docs/requirements)
---
<Alert>Si deseas instalar pm2 puedes ejecutar `npm install pm2 --global`</Alert>
Debes ubicarte en el directorio donde tienes el codigo fuente de tu chatbot.
Independientemente de tu sistema operativo deberás ejecutar el chatbot con el comando atrevés de un sistema que mantenga el proceso en ejecución.
Recomendamos [Pm2](https://pm2.keymetrics.io/)
```shell
pm2 start app.js --name=bot1
```
![](https://i.imgur.com/ilPS75H.png)
La consola de devolver un mensaje con una lista de procesos, en el ejemplo puedes observar, que tenemos un proceso llamado `bot1`
De esta manera ya puedes cerrar la terminal y tu bot seguirá en ejecución sin problema

View File

@@ -23,23 +23,6 @@ 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() ## addKeyword()
Esta funcion se utliza para iniciar un flujo de conversion. <br /> Recibe un `string` o un `array` Esta funcion se utliza para iniciar un flujo de conversion. <br /> Recibe un `string` o un `array`
@@ -72,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: true (para esperar respuesta) - capture: false (para esperar respuesta)
- child: Objecto tipo flujo o arra de flujos hijos - child: Objecto tipo flujo o arra de flujos hijos
```js ```js
@@ -175,64 +158,6 @@ 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
Argumento para asignar nombre y puerto al BOT
```js
QRPortalWeb({name:BOTNAME, port:3005 });
```
---
<Navigation <Navigation
pages={[ pages={[

View File

@@ -3,7 +3,6 @@ import type { DocumentHead } from '@builder.io/qwik-city'
import ExtraBar from '~/components/widgets/ExtraBar' import ExtraBar from '~/components/widgets/ExtraBar'
import Header from '~/components/widgets/Header' import Header from '~/components/widgets/Header'
import NavBar from '~/components/widgets/NavBar' import NavBar from '~/components/widgets/NavBar'
import { SearchModal } from '~/components/widgets/SearchModal'
import SponsorBar from '~/components/widgets/SponsorBar' import SponsorBar from '~/components/widgets/SponsorBar'
import { GlobalStore } from '~/contexts' import { GlobalStore } from '~/contexts'
// import Navigation from '~/components/widgets/Navigation' // import Navigation from '~/components/widgets/Navigation'
@@ -15,7 +14,6 @@ export default component$(() => {
return ( return (
<> <>
<SearchModal />
<Header /> <Header />
<main class={'overflow-hidden'}> <main class={'overflow-hidden'}>
<div class={'max-w-8xl'}> <div class={'max-w-8xl'}>

View File

@@ -0,0 +1,24 @@
[![hackmd-github-sync-badge](https://hackmd.io/79xQyVSgRD6RsTpqtMPPdw/badge)](https://hackmd.io/79xQyVSgRD6RsTpqtMPPdw)
### Preguntas Frecuentes para Master Class BOT v2
> Anota aqui las preguntas o dudas que tengas
> Pronto estare publicando fecha y hora para la masterclass
1.- Si necesito correr dos bots al mismo tiempo ¿donde puedo cambiar el puerto?
2.- Si necesito agregar o modificar funciones del bot, ¿como puedo hacerlo?
3.- Si quiero mi bot con otra base de datos diferente a MySQL ¿como lo puedo hacer?
4.- Quiero conectarme a tal o cual API con JSON/XML/etc, ¿se puede hacer?
5.- ¿Como integrar listas?
6.- Preguntas y respuestas con el Bot
7.- Guardar conversaciones en Excel.
8.- ¿Puedo usar 2 o mas sesiones (códigos QR) al mismo tiempo?
9.- ¿Puede ser que al usar el provider bailey, al leer el qr.png, que sea desde una url en el navegador, y no desde visual studio? Gracias
10.- ¿Cómo tomo los datos que me envían en un mensaje para utilizarlo internamente en la búsqueda de datos propios y devolver la respuesta?

View File

@@ -1,26 +0,0 @@
# MasterClass
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/22jiE2Z3XGM"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
---
### Preguntas de la masterclass
- Si necesito correr dos bots al mismo tiempo ¿donde puedo cambiar el puerto?
- Si necesito agregar o modificar funciones del bot, ¿como puedo hacerlo?
- Si quiero mi bot con otra base de datos diferente a MySQL ¿como lo puedo hacer?
- Quiero conectarme a tal o cual API con JSON/XML/etc, ¿se puede hacer?
- ¿Como integrar listas?
- Preguntas y respuestas con el Bot
- Guardar conversaciones en Excel.
- ¿Puedo usar 2 o mas sesiones (códigos QR) al mismo tiempo?
- ¿Puede ser que al usar el provider bailey, al leer el qr.png, que sea desde una url en el navegador, y no desde visual studio? Gracias
- ¿Cómo tomo los datos que me envían en un mensaje para utilizarlo internamente en la búsqueda de datos propios y devolver la respuesta?

View File

@@ -5,22 +5,16 @@ import Features from '~/components/widgets/Features'
import FAQs from '~/components/widgets/FAQs' import FAQs from '~/components/widgets/FAQs'
import CallToAction from '~/components/widgets/CallToAction' import CallToAction from '~/components/widgets/CallToAction'
import Collaborators from '~/components/widgets/Collaborators' import Collaborators from '~/components/widgets/Collaborators'
import Members from '~/components/widgets/Members'
import { fetchGithub } from '~/services/github' import { fetchGithub } from '~/services/github'
import { fetchOpenCollective } from '~/services/opencollective'
import { RequestHandlerNetlify } from '@builder.io/qwik-city/middleware/netlify-edge' import { RequestHandlerNetlify } from '@builder.io/qwik-city/middleware/netlify-edge'
import { GITHUB_TOKEN } from './docs/constant' import { GITHUB_TOKEN } from './docs/constant'
// import { SearchModal } from '~/components/widgets/SearchModal'
export const onGet: RequestHandlerNetlify = async ({ platform }) => { export const onGet: RequestHandlerNetlify = async ({ platform }) => {
const CHECK_GITHUB_TOKEN = const CHECK_GITHUB_TOKEN =
(platform as any)?.['GITHUB_TOKEN'] ?? GITHUB_TOKEN (platform as any)?.['GITHUB_TOKEN'] ?? GITHUB_TOKEN
const dataGithub = await fetchGithub(CHECK_GITHUB_TOKEN) console.log(`[🚩 platform]: `, GITHUB_TOKEN)
const dataOpenCollective = await fetchOpenCollective() const data = await fetchGithub(CHECK_GITHUB_TOKEN)
return { return data
dataGithub,
dataOpenCollective,
}
} }
export default component$(() => { export default component$(() => {
@@ -33,16 +27,9 @@ export default component$(() => {
<CallToAction /> <CallToAction />
<Resource <Resource
value={resource} value={resource}
onResolved={(data: any) => { onResolved={(data: any) => <Collaborators users={data} />}
return (
<>
<Collaborators users={data.dataGithub} />
<FAQs />
<Members users={data.dataOpenCollective} />
</>
)
}}
></Resource> ></Resource>
<FAQs />
</> </>
) )
}) })

View File

@@ -14,9 +14,6 @@ export const fetchGithub = async (token: string) => {
}, },
} }
) )
const listUsers = await data.json() const listUsers = data.json()
return listUsers.map((u: any) => ({ return listUsers
...u,
avatar_url: `${u.avatar_url}&s=80`,
}))
} }

View File

@@ -1,19 +0,0 @@
/**
* GET API from OpenCollective
* @returns
*/
export const fetchOpenCollective = async () => {
const data = await fetch(
`https://opencollective.com/bot-whatsapp/members/users.json?limit=22&offset=0`,
{
method: 'GET',
}
)
const listUsers = await data.json()
return listUsers.map((u: any) => ({
html_url: u.profile,
avatar_url: u.image ?? 'https://i.imgur.com/HhiYKwN.png',
login: u.name,
id: u.MemberId,
}))
}

View File

@@ -1,7 +1,7 @@
const notFounds = [ const notFounds = [
[ [
'/', '/',
'<!DOCTYPE html>\n<html>\n <head>\n <meta charset="utf-8" />\n <meta http-equiv="Status" content="404" />\n <title>404 Resource Not Found</title>\n <meta name="viewport" content="width=device-width,initial-scale=1" />\n <style>\n body {\n color: #006ce9;\n background-color: #fafafa;\n padding: 30px;\n font-family: ui-sans-serif, system-ui, -apple-system,\n BlinkMacSystemFont, Roboto, sans-serif;\n }\n p {\n max-width: 600px;\n margin: 60px auto 30px auto;\n background: white;\n border-radius: 4px;\n box-shadow: 0px 0px 50px -20px #006ce9;\n overflow: hidden;\n }\n strong {\n display: inline-block;\n padding: 15px;\n background: #006ce9;\n color: white;\n }\n span {\n display: inline-block;\n padding: 15px;\n }\n pre {\n max-width: 580px;\n margin: 0 auto;\n }\n </style>\n </head>\n <body>\n <p><strong>404</strong> <span>Resource Not Found</span></p>\n </body>\n</html>\n', '<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Status" content="404"/>\n <title>404 Resource Not Found</title>\n <meta name="viewport" content="width=device-width,initial-scale=1">\n <style>\n body { color: #006ce9; background-color: #fafafa; padding: 30px; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Roboto, sans-serif; }\n p { max-width: 600px; margin: 60px auto 30px auto; background: white; border-radius: 4px; box-shadow: 0px 0px 50px -20px #006ce9; overflow: hidden; }\n strong { display: inline-block; padding: 15px; background: #006ce9; color: white; }\n span { display: inline-block; padding: 15px; }\n pre { max-width: 580px; margin: 0 auto; }\n </style>\n</head>\n<body>\n <p><strong>404</strong> <span>Resource Not Found</span></p>\n</body>\n</html>',
], ],
] ]
function getNotFound(p) { function getNotFound(p) {

View File

@@ -1,4 +1,5 @@
const staticPaths = new Set([ const staticPaths = new Set([
'/',
'/favicon.svg', '/favicon.svg',
'/manifest.json', '/manifest.json',
'/q-manifest.json', '/q-manifest.json',